開発にコンテナを使う

事前準備

コンテナとしてイメージを実行 で、イメージ構築をし、それコンテナ化アプリケーションとして実行します。

概要

この章では、これまでのモジュールで構築したアプリケーションの、ローカル開発環境をセットアップする方法を説明します。イメージの構築には Docker を使い、すべてをとても簡単にする Docker Compose も使います。

ローカルデータベースとコンテナ

まず、コンテナでデータベースを実行する方法と、データを保持するためにボリュームとネットワーク機能を使い、アプリケーションがデータベースと通信できるようにする方法を説明します。それから、compose ファイルの中にすべてを入れ込みます。このファイルは1つのコマンドで、ローカル開発環境のセットアップと実行をできるようにします。最後に、コンテナ内で実行しているアプリケーションに、デバッガを接続する方法を説明します。

MongoDB をダウンロードし、インストールし、設定し、Mongo データベースをサービスとして実行する代わりに、MongoDB 用の Docker 公式イメージを使い、コンテナとして実行できるようになります。

コンテナ内で MogoDB を実行する前に、2つのボリュームを作成しておきたいです。これは、Docker が 保持し続けるデータ(persistent data)設定ファイル(configuration) を保存できます。バインド マウントを使う代わりに、 docker が提供するマネージド ボリューム機能を使いましょう。詳しい情報は ボリュームの使用 をご覧ください。

それでは、ボリュームを作成しましょう。作成するボリュームの1つは MogoDB のデータ用で、もう1つは設定ファイル用です。

$ docker volume create mongodb
$ docker volume create mongodb_config

次は、アプリケーションとデータベースが相互に対話できるようにするためのネットワークを作成します。ネットワークは ユーザ定義ブリッジネットワーク(user-defined bridge network) と呼ばれ、優れた DNS 名前解決サービスを提供するため、 接続文字列(connection string) を作成するために使えます。

$ docker network create mongodb

次は、コンテナとして MongoDB を実行し、先ほど作成したボリュームとネットワークに接続できるようにします。Docker は Hub からイメージを取得し、ローカルでイメージを実行します。

$ docker run -it --rm -d -v mongodb:/data/db \
  -v mongodb_config:/data/configdb -p 27017:27017 \
  --network mongodb \
  --name mongodb \
  mongo

うまくいけば、これで MongoDB を実行していますので、 server.js を更新し、MongoDB を使いメモリ上のデータストアを使わないようにしましょう。

const ronin     = require( 'ronin-server' )
const mocks     = require( 'ronin-mocks' )
const database  = require( 'ronin-database' )
const server = ronin.server()

database.connect( process.env.CONNECTIONSTRING )
server.use( '/', mocks.server( server.Router(), false, false ) )
server.start()

ronin-database モジュールを追加済みであれば、データベースに接続し、メモリ上のフラグは false にするよう、コードを変更します。そして、コンテナに変更を含めるため、イメージの再構築が必要です。

まず、アプリケーションで npm を使い ronin-database モジュールを追加しましょう。

$ npm install ronin-database

それから、イメージを構築できます。

$ docker build --tag node-docker .

次はコンテナを実行しましょう。ですが、アプリケーションがデータベースに接続するために使う接続文字列を知るため、環境変数 CONNECTIONSTRING の設定が今回は必要です。これを docker run コマンドで実行します。

$ docker run \
  -it --rm -d \
  --network mongodb \
  --name rest-server \
  -p 8000:8000 \
  -e CONNECTIONSTRING=mongodb://mongodb:27017/notes \
  node-docker

接続文字列の最後にある notes は、データベースの名前です。

アプリケーションをデータベースに接続し、メモを追加できるかどうか確かめましょう。

$ curl --request POST \
  --url http://localhost:8000/notes \
  --header 'content-type: application/json' \
  --data '{"name": "this is a note", "text": "this is a note that I wanted to take while I was working on writing a blog post.", "owner": "peter"}'

サービスからは以下の JSON が返ってくるでしょう。

{"code":"success","payload":{"_id":"5efd0a1552cd422b59d4f994","name":"this is a note","text":"this is a note that I wanted to take while I was working on writing a blog post.","owner":"peter","createDate":"2020-07-01T22:11:33.256Z"}}

Compose を使ってローカルで開発

このセクションでは、 node-docker と MongoDB を1つのコマンドで起動するための Compose ファイルを作成します。また、 node-docker をデバッグモードで起動するための Compose ファイルも作成しますので、実行中の node プロセスにデバッガを接続できるようになります。

IDE のメモ機能やテキストエディタを使い、 docker-compose.dev.yml という名前の新しいファイルを作成します。ファイル内に以下の命令をコピー&ペーストします。

version: '3.8'

services:
 notes:
  build:
   context: .
  ports:
   - 8000:8000
   - 9229:9229
  environment:
   - SERVER_PORT=8000
   - CONNECTIONSTRING=mongodb://mongo:27017/notes
  volumes:
   - ./:/app
  command: npm run debug

 mongo:
  image: mongo:4.2.8
  ports:
   - 27017:27017
  volumes:
   - mongodb:/data/db
   - mongodb_config:/data/configdb
volumes:
 mongodb:
 mongodb_config:

この Compose ファイルは docker run コマンドに一切パラメータを渡す必要がないため、とても便利です。Compose ファイル内で宣言的にパラメータを指定します。

ポート 9229 を公開していますので、デバッガをアタッチできます。また、ローカルのソースコードを実行中のコンテナにマッピングしていますので、テキストエディタで変更できるだけなく、それらの変更をコンテナに取り込めます。

Compose ファイルを使う上で、もう1つの素晴らしい機能は、サービス名を使ってサービスの名前解決をできるようになります。そのため、接続文字列として mongo が使えるようになります。 mongo という名前を使えるのは、 MongoDB サービスに対して Compose ファイル内でそのように名付けたからです。

デバッグモードでアプリケーションを起動するには、 package.json ファイルで、 アプリケーションをデバッグモードで起動するよう、 npm に命令行を追加する必要があります。

package.json ファイルを開き、scripts セクションに以下の行を追加します。

"debug": "nodemon --inspect=0.0.0.0:9229 server.js"

お分かりのように、 nodemon を使おうとしています。nodemon はサーバをデバッグモードで起動し、ファイルの変更も監視し、変更があればサーバを再起動します。以下のコマンドをターミナルで実行し、プロジェクトのディレクトリ内に nodemon をインストールします。

$ npm install nodemon

アプリケーションを起動し、適切に動作しているか確認しましょう。

$ docker-compose -f docker-compose.dev.yml up --build

--build フラグを渡したため、 Docker はイメージをコンパイルした後、イメージを起動します。

正常に動作すると、次のような画面が見えます。

node-compile

それから、API エンドポイントをテストしましょう。以下の curl コマンドを実行します:

$ curl --request GET --url http://localhost:8000/notes

次のような反応を受け取るでしょう:

{"code":"success","meta":{"total":0,"count":0},"payload":[]}

デバッガを接続

about:inspect

Chrome-inspect

Open dedicated DevTools for Node ( Node 用の専用 DevTools を開く)のリンクをクリックします。これはコンテナ内で実行している Node.js プロセスに接続した DevTools が開きます。

ソースコードを変更し、ブレイクポイントを設定します。

次のコードを既存の server.use() 宣言の上に追加し、ファイルを保存します。ブレイクポイントを適切に設定できるようにするため、ここで示すように、 return 宣言がその行の中にあるのを確認します。

server.use( '/foo', (req, res) => {
  return res.json({ "foo": "bar" })
})

Compose アプリケーションを実行しているターミナルを見ると、nodemon が変更を検出し、アプリケーションを再読み込みします。

nodemon

Chrome DevTools に移動し直し、 return res.json({ "foo": "bar" }) 背源を含むブレイクポイントを設定し、それからブレイクポイントをトリガとするため以下のコマンドを実行します。

$ curl --request GET --url http://localhost:8000/foo

ブレイクポイントでコードが停止するのが見えれば、通常通りにデバッグのために利用できるようになります。変数の調査と監視、ブレイクポイントの条件設定、スタックトレースの表示等ができます。

次のステップ

この章では、通常のコマンドラインとほとんど同じように使える、一般的な開発用イメージ作成方法を説明しました。また、 Compose ファイルもセットアップし、ソースコードを実行中のコンテナにマップし、デバッグポイントを公開しました。

次の章では、 Docker で単体テストを実行する方法を説明します。

テストの実行

フィードバック

フィードバックを通し、このトピックの改善を支援ください。考えがあれば、 Docker Docs GitHub リポジトリに issue を作成して教えてください。あるいは、更新の提案のために RP を作成 してください。

参考

Use containers for development

https://docs.docker.com/language/nodejs/develop/