Node.js を使用した Docker 入門 — パート 1

Node.jsアプリでDockerコンテナの使用を開始するのに役立つステップバイステップガイド。

前提 条件

このチュートリアルを完了するには、次のものが必要です。

ノード ドッカーのロゴ

ドッカーの概要

Dockerは、アプリケーションを開発、出荷、実行するためのオープンプラットフォームです。 Docker を使用すると、アプリケーションをインフラストラクチャから分離できるため、ソフトウェアを迅速に提供できます。 

Docker を使用すると、アプリケーションを管理するのと同じ方法でインフラストラクチャを管理できます。 コードを迅速に出荷、テスト、デプロイするための Docker の手法を活用することで、コードの記述と本番環境での実行の間の遅延を大幅に短縮できます。

サンプルアプリケーション

例として使用する単純な Node.js アプリケーションを作成しましょう。 ローカルマシン上にnode-dockerという名前のディレクトリを作成し、以下の手順に従って単純なREST APIを作成します。

$ cd [path to your node-docker directory]
$ npm init -y
$ npm install ronin-server ronin-mocks
$ touch server.js

次に、REST 要求を処理するコードを追加しましょう。 モックサーバーを使用して、実際のコードではなく、アプリケーションのDocker化に集中できるようにします。

任意の IDE でこの作業ディレクトリを開き、次のコードを server.js ファイルに入力します。

const ronin     = require( 'ronin-server' )
const mocks     = require( 'ronin-mocks' )
 
const server = ronin.server()
 
server.use( '/', mocks.server( server.Router(), false, true ) )
server.start()

モックサーバーはRoninと呼ばれ.jsデフォルトでポート8000に表示されます。 ルート (/) エンドポイントに対して POST 要求を行うことができ、サーバーに送信する JSON 構造はメモリに保存されます。 同じエンドポイントに GET 要求を送信し、以前に POST した JSON オブジェクトの配列を受信することもできます。

アプリケーションのテスト

アプリケーションを起動して、正しく実行されていることを確認しましょう。 ターミナルを開き、作成した作業ディレクトリに移動します。 

$ ノード サーバ.js

アプリケーションが正常に動作していることをテストするには、まず JSON を API に POST してから、GET 要求を行ってデータが保存されたことを確認します。 新しいターミナルを開き、次のcurlコマンドを実行します。

$ curl --request POST \
  --url http://localhost:8000/test \
  --header 'content-type: application/json' \
  --data '{
	"msg": "testing"
}'
{"code":"success","payload":[{"msg":"testing","id":"31f23305-f5d0-4b4f-a16f-6f4c8ec93cf1","createDate":"2020-08-28T21:53:07.157Z"}]}

$ curl http://localhost:8000/test
{"code":"success","meta":{"total":1,"count":1},"payload":[{"msg":"testing","id":"31f23305-f5d0-4b4f-a16f-6f4c8ec93cf1","createDate":"2020-08-28T21:53:07.157Z"}]}

サーバーが実行されているターミナルに戻ると、サーバーログに次のリクエストが表示されます。

2020-XX-31T16:35:08:4260  INFO: POST /test
2020-XX-31T16:35:21:3560  INFO: GET /test

ノードのドッカーファイルを作成します.js

アプリケーションが正しく実行されたので、Dockerfile の作成を見てみましょう。 

A Dockerfile は、ユーザーがイメージをアセンブルするためにコマンド ラインで呼び出すことができるすべてのコマンドを含むテキスト ドキュメントです。 コマンドを実行して docker build イメージをビルドするようにDockerに指示すると、Dockerはこれらの命令を読み取り、1つずつ実行し、結果としてDockerイメージを作成します。

アプリケーションの作成手順 Dockerfile を見ていきましょう。 作業ディレクトリのルートに e という名前の Dockerfilファイルを作成し、このファイルをテキスト エディタで開きます。

手記: Dockerfile の名前は重要ではありませんが、多くのコマンドのデフォルトのファイル名は単に Dockerfileです。 そのため、このシリーズ全体でこれをファイル名として使用します。

最初に行う必要があるのは、アプリケーションに使用する基本イメージを Docker に指示する行を Dockerfile に追加することです。 

Dockerfile:

FROM node:12.18.1

Docker イメージは、他のイメージから継承できます。 そのため、独自の基本イメージを作成する代わりに、Node.js アプリケーションを実行するために必要なすべてのツールとパッケージが既に含まれている公式の Node.js イメージを使用します。 これは、オブジェクト指向プログラミングでクラス継承について考えるのと同じ方法と考えることができます。 だから例えば。 JavaScript で Docker イメージを作成できるとしたら、次のように記述できます。

クラス MyImage は NodeBaseImage {} を拡張します

これにより、基本クラス NodeBaseImage から機能を継承したというクラス MyImageが作成されます。

同様に、コマンドを使用する FROM ときは、からのすべての機能を node:12.18.1 imageイメージに含めるようにdockerに指示します。

: 独自の基本イメージの作成の詳細については、 基本イメージの作成に関するドキュメントを参照してください。

残りのコマンドを実行するときに作業を簡単にするために、作業ディレクトリを作成しましょう。 

これにより、Docker は、このパスを後続のすべてのコマンドの既定の場所として使用するように指示されます。 この方法では、完全なファイルパスを入力する必要はありませんが、作業ディレクトリに基づく相対パスを使用できます。

WORKDIR /app

通常、Node.jsで書かれたプロジェクトをダウンロードしたら、最初に行うことはnpmパッケージをインストールすることです。 これにより、アプリケーションのすべての依存関係が、ノードランタイムがそれらを見つけることができるディレクトリにインストール node_modules されます。

npm installを実行する前に、 と package.json package-lock.json files をイメージに入れる必要があります。これを行うには、 COPY このコマンドを使用します。 このコマンドは COPY 2 つのパラメーターを取ります。 最初のパラメーターは、イメージにコピーするファイルを Docker に指示します。 2 番目のパラメーターは、そのファイルのコピー先を Docker に指示します。 と package-lock.json ファイルを作業ディレクトリ(/ app)にコピーします package.json

COPY package.json package.json
COPY package-lock.json package-lock.json

イメージ内にpackage.jsonファイルを取得したら、コマンドを使用して コマンドを実行 npm install する RUN。これは、マシンでローカルにnpm installを実行している場合とまったく同じように機能しますが、今回はこれらのノードモジュールがイメージ内のnode_modulesディレクトリにインストールされます。

RUN npm install

この時点で、ノードバージョン12.18.1に基づくイメージがあり、依存関係がインストールされています。 次に行う必要があるのは、ソースコードを画像に追加することです。 上記の package.json ファイルで行ったのと同じように、COPY コマンドを使用します。

COPY . .

このCOPYコマンドは、現在のディレクトリにあるすべてのファイルを取得し、それらをイメージにコピーします。 これで、イメージがコンテナー内で実行されるときに実行するコマンドをDockerに指示するだけです。 これを行うには、CMDコマンドを使用します。 

CMD [ "node", "server.js" ]

以下は完全なドッカーファイルです。

FROM node:12.18.1
 
WORKDIR /app
 
COPY package.json package.json
COPY package-lock.json package-lock.json
 
RUN npm install
 
COPY . .
 
CMD [ "node", "server.js" ]

イメージの構築

Dockerfile を作成したので、イメージをビルドしましょう。 これを行うには、docker build コマンドを使用します。 このコマンドは docker build 、Dockerファイルと「コンテキスト」からDockerイメージをビルドします。 ビルドのコンテキストは、指定された PATH または URL にあるファイルのセットです。 Docker ビルド プロセスは、コンテキスト内にある任意のファイルにアクセスできます。 

ビルド コマンドは、オプションで –tag フラグを受け取ります。 タグは、画像の名前とオプションのタグを「name:tag」形式で設定するために使用されます。 ここでは、物事を簡素化するために、オプションの「タグ」を省略します。 タグを渡さない場合、dockerはデフォルトのタグとして「latest」を使用します。 これは、ビルド出力の最後の行に表示されます。

最初の Docker イメージを作成しましょう。

$ docker build --tag node-docker .
Sending build context to Docker daemon  82.94kB
Step 1/7 : FROM node:12.18.1
---> f5be1883c8e0
Step 2/7 : WORKDIR /code
...
Successfully built e03018e56163
Successfully tagged node-docker:latest

ローカル画像の表示

ローカルマシンにある画像のリストを表示するには、2つのオプションがあります。 1 つは CLI を使用する方法、もう 1 つは Docker デスクトップを使用する方法です。 現在ターミナルで作業しているので、CLIを使用したイメージの一覧表示を見てみましょう。

画像を一覧表示するには、コマンドを実行するだけです images

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED              SIZE
node-docker         latest              3809733582bc        About a minute ago   945MB
node                12.18.1             f5be1883c8e0        2 months ago         918MB

少なくとも 2 つの画像が表示されます。 1つは基本イメージ用で、もう1つはビルドしたイメージ node:12.18.1 用です node-docker:latest.

画像のタグ付け

前述のように、イメージ名はスラッシュで区切られた名前コンポーネントで構成されます。 名前コンポーネントには、小文字、数字、区切り文字を含めることができます。 区切り記号は、ピリオド、1 つまたは 2 つのアンダースコア、または 1 つ以上のダッシュとして定義されます。 名前コンポーネントの先頭または末尾を区切り記号にすることはできません。

イメージは、マニフェストとレイヤーのリストで構成されます。 この時点では、これらのアーティファクトの組み合わせを指す「タグ」以外のマニフェストとレイヤーについてはあまり心配しないでください。 画像には複数のタグを付けることができます。 作成した画像の 2 つ目のタグを作成し、そのレイヤーを見てみましょう。

上記でビルドしたイメージの新しいタグを作成するには、次のコマンドを実行します。

$ ドッカータグ ノードドッカー:最新のノードドッカー:v1.0.0

docker tag コマンドは、イメージの新しいタグを作成します。 新しいイメージは作成されません。 タグは同じ画像を指し、画像を参照する別の方法です。

次に、コマンドを実行して、 docker images ローカルイメージのリストを表示します。

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
node-docker         latest              3809733582bc        24 minutes ago      945MB
node-docker         v1.0.0              3809733582bc        24 minutes ago      945MB
node                12.18.1             f5be1883c8e0        2 months ago        918MB

で始まる 2 つの画像 node-dockerがあることがわかります。 列を見る IMAGE ID と、2つの画像の値が同じであることがわかります。

先ほど作成したタグを削除しましょう。 これを行うには、次のコマンドを使用します rmi 。 オマンドは rmi c「画像の削除」の略です。 

$ docker rmi node-docker:v1.0.0
Untagged: node-docker:v1.0.0

Docker からの応答では、イメージは削除されておらず、"タグなし" のみであることがわかります。 imagesコマンドを実行して、これを再確認してください。

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
node-docker         latest              3809733582bc        32 minutes ago      945MB
node                12.18.1             f5be1883c8e0        2 months ago        918MB

タグ付け :v1.0.0 された画像は削除されましたが、 node-docker:latest マシンでタグを引き続き使用できます。

コンテナの実行

コンテナは通常のオペレーティングシステムプロセスですが、このプロセスは、独自のファイルシステム、独自のネットワーク、およびホストとは別の独自の分離されたプロセスツリーを持つという点で分離されています。

コンテナー内でイメージを実行するには、docker run コマンドを使用します。 このコマンドには docker run 1 つのパラメーターが必要であり、それがイメージ名です。 イメージを起動して、正しく実行されていることを確認しましょう。 ターミナルで次のコマンドを実行します。

$ ドッカーはノードドッカーを実行します

このコマンドを実行すると、コマンド プロンプトに戻っていないことがわかります。 これは、アプリケーションがRESTサーバーであり、コンテナを停止するまでOSに制御を戻すことなく、着信要求を待機するループで実行されるためです。

curlコマンドを使用してサーバーにGETリクエストを作成しましょう。

$ curl --request POST \
  --url http://localhost:8000/test \
  --header 'content-type: application/json' \
  --data '{
	"msg": "testing"
}'
curl: (7) Failed to connect to localhost port 8000: Connection refused

ご覧のとおり、サーバーへの接続が拒否されたため、curlコマンドは失敗しました。 つまり、ポート8000でローカルホストに接続できませんでした。 これは、コンテナーがネットワークを含む分離で実行されるためです。 コンテナを停止し、ローカルネットワークで公開されているポート8000で再起動しましょう。

コンテナを停止するには、ctrl-c キーを押します。 これにより、ターミナルプロンプトに戻ります。

コンテナーのポートを発行するには、docker run コマンドで —publish フラグ (-p 略して) を使用します。 —publish コマンドの形式は [host port]:[container port]です。 したがって、コンテナ内のポート8000をコンテナ外のポート3000に公開する場合は、— publish フラグを渡3000:8000 します。 

コンテナーを起動し、ポート 8000 をホストのポート 8000 に公開します。

$ docker run --publish 8000:8000 node-docker

それでは、上からcurlコマンドを再実行しましょう。

$ curl --request POST \
  --url http://localhost:8000/test \
  --header 'content-type: application/json' \
  --data '{
	"msg": "testing"
}'
{"code":"success","payload":[{"msg":"testing","id":"dc0e2c2b-793d-433c-8645-b3a553ea26de","createDate":"2020-09-01T17:36:09.897Z"}]}

成功! ポート8000のコンテナ内で実行されているアプリケーションに接続できました。 コンテナーが実行されているターミナルに戻ると、POST 要求がコンソールに記録されます。

2020-09-01T17:36:09:8770情報:投稿/テスト

ctrl-c を押してコンテナを停止します。

デタッチ モードで実行

これはこれまでのところ素晴らしいことですが、サンプルアプリケーションはWebサーバーであり、ターミナルをコンテナに接続する必要はありません。 Docker は、コンテナーをデタッチ モードまたはバックグラウンドで実行できます。 これを行うには、—detach または略して-dを使用できます。 Dockerは以前と同じようにコンテナを起動しますが、今回はコンテナから「デタッチ」し、ターミナルプロンプトに戻ります。

$ docker run -d -p 8000:8000 node-docker
ce02b3179f0f10085db9edfccd731101868f58631bdf918ca490ff6fd223a93b

Dockerはバックグラウンドでコンテナを起動し、ターミナルにコンテナIDを出力しました。

繰り返しになりますが、コンテナが正しく実行されていることを確認しましょう。 上から同じcurlコマンドを実行します。

$ curl --request POST \
  --url http://localhost:8000/test \
  --header 'content-type: application/json' \
  --data '{
	"msg": "testing"
}'
{"code":"success","payload":[{"msg":"testing","id":"dc0e2c2b-793d-433c-8645-b3a553ea26de","createDate":"2020-09-01T17:36:09.897Z"}]}

コンテナの一覧表示

コンテナをバックグラウンドで実行したので、コンテナが実行されているかどうか、またはマシン上で他のコンテナが実行されているかどうかをどのように知ることができますか? さて、私たちはドッカーpsコマンドを実行することができます。 Linuxの場合と同様に、マシン上のプロセスのリストを表示するには、psコマンドを実行します。 同じ精神で、docker psコマンドを実行して、マシンで実行されているコンテナのリストを表示できます。

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
ce02b3179f0f        node-docker         "docker-entrypoint.s…"   6 minutes ago       Up 6 minutes        0.0.0.0:8000->8000/tcp   wonderful_kalam

psコマンドは、実行中のコンテナに関する一連のことを伝えます。 コンテナID、コンテナ内で実行されているイメージ、コンテナの起動に使用されたコマンド、作成時、ステータス、公開されたポート、コンテナの名前を確認できます。 

あなたはおそらく私たちのコンテナの名前がどこから来ているのか疑問に思っているでしょう。 起動時にコンテナーの名前を指定しなかったため、Docker はランダムな名前を生成しました。 これはすぐに修正しますが、最初にコンテナを停止する必要があります。 コンテナを停止するには、 docker stop コンテナを停止するコマンドを実行します。 コンテナーの名前を渡すか、コンテナー ID を使用する必要があります。

$ docker stop wonderful_kalam
wonderful_kalam

次に、コマンドを再実行して、 docker ps 実行中のコンテナーの一覧を表示します。

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

コンテナの停止、開始、および命名

Docker コンテナーは、開始、停止、および再起動できます。 コンテナを停止すると、削除されませんが、ステータスが停止に変更され、コンテナ内のプロセスが停止します。 コマンドを実行したときの docker ps 既定の出力では、実行中のコンテナーのみが表示されます。 渡すと —all または–a 略して、停止しているか開始されているかにかかわらず、システム上のすべてのコンテナが表示されます。

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                      PORTS               NAMES
ce02b3179f0f        node-docker         "docker-entrypoint.s…"   16 minutes ago      Exited (0) 5 minutes ago                        wonderful_kalam
ec45285c456d        node-docker         "docker-entrypoint.s…"   28 minutes ago      Exited (0) 20 minutes ago                       agitated_moser
fb7a41809e5d        node-docker         "docker-entrypoint.s…"   37 minutes ago      Exited (0) 36 minutes ago                       goofy_khayyam

手順に沿って作業している場合は、いくつかのコンテナーが一覧表示されます。 これらは、開始および停止したが、削除されていないコンテナーです。

停止したばかりのコンテナを再起動しましょう。 停止したばかりのコンテナの名前を見つけて、再起動コマンドで以下のコンテナの名前を置き換えます。

$ ドッカー再起動wonderful_kalam

次に、psコマンドを使用して、すべてのコンテナを再度一覧表示します。

$ docker ps --all
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                      PORTS                    NAMES
ce02b3179f0f        node-docker         "docker-entrypoint.s…"   19 minutes ago      Up 8 seconds                0.0.0.0:8000->8000/tcp   wonderful_kalam
ec45285c456d        node-docker         "docker-entrypoint.s…"   31 minutes ago      Exited (0) 23 minutes ago                            agitated_moser
fb7a41809e5d        node-docker         "docker-entrypoint.s…"   40 minutes ago      Exited (0) 39 minutes ago                            goofy_khayyam

再起動したばかりのコンテナーがデタッチ モードで起動され、ポート 8000 が公開されていることに注意してください。 また、コンテナーの状態が "Up X 秒" であることも確認します。 コンテナーを再起動すると、最初に起動したときと同じフラグまたはコマンドでコンテナーが開始されます。

すべてのコンテナを停止して削除し、ランダムな名前付けの問題を修正してみましょう。

先ほど開始したコンテナーを停止します。 実行中のコンテナの名前を見つけ、以下のコマンドの名前をシステム上のコンテナの名前に置き換えます。

$ docker stop wonderful_kalam
wonderful_kalam

すべてのコンテナが停止したので、それらを削除しましょう。 コンテナーが削除されると、そのコンテナーは実行されなくなり、停止状態でもなくなりますが、コンテナー内のプロセスは停止され、コンテナーのメタデータは削除されます。

$ docker ps --all
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                      PORTS                    NAMES
ce02b3179f0f        node-docker         "docker-entrypoint.s…"   19 minutes ago      Up 8 seconds                0.0.0.0:8000->8000/tcp   wonderful_kalam
ec45285c456d        node-docker         "docker-entrypoint.s…"   31 minutes ago      Exited (0) 23 minutes ago                            agitated_moser
fb7a41809e5d        node-docker         "docker-entrypoint.s…"   40 minutes ago      Exited (0) 39 minutes ago                            goofy_khayyam

コンテナーを削除するには、コンテナー名を渡す docker rm コマンドを実行するだけです。 1 つのコマンドで複数のコンテナー名をコマンドに渡すことができます。 繰り返しになりますが、以下のコマンドのコンテナ名をシステムのコンテナ名に置き換えます。

$ docker rm wonderful_kalam agitated_moser goofy_khayyam
wonderful_kalam 
agitated_moser 
goofy_khayyam

docker ps --all コマンドを再度実行して、すべてのコンテナーがなくなったことを確認します。

それでは、厄介なランダムな名前の問題に対処しましょう。 標準的な方法は、コンテナーで実行されているものと、コンテナーが関連付けられているアプリケーションまたはサービスを簡単に識別できるという単純な理由で、コンテナーに名前を付けることです。 コード内の変数の適切な命名規則と同様に、読みやすくなります。 コンテナの命名も同様です。

コンテナーに名前を付けるには、run コマンドに –name フラグを渡すだけです。

$ docker run -d -p 8000:8000 --name rest-server node-docker
1aa5d46418a68705c81782a58456a4ccdb56a309cb5e6bd399478d01eaa5cdda
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
1aa5d46418a6        node-docker         "docker-entrypoint.s…"   3 seconds ago       Up 3 seconds        0.0.0.0:8000->8000/tcp   rest-server

そこでは、それはより良いです。 これで、名前に基づいてコンテナを簡単に識別できます。

結論

この投稿では、Dockerfileを使用したDockerイメージの作成、イメージのタグ付け、およびイメージの管理について学びました。 次に、コンテナーの実行、ポートの公開、およびデタッチ モードでのコンテナーの実行について説明しました。 次に、コンテナーの起動、停止、再起動による管理について学習しました。 また、コンテナをより簡単に識別できるように、コンテナに名前を付けることも検討しました。

パート 2では、コンテナでデータベースを実行し、それをアプリケーションに接続する方法を見ていきます。また、ローカル開発環境の設定と 、Docker を使用したイメージの共有についても説明します。

さらに詳しく