コンテナーとしてのイメージ実行
読む時間の目安: 3 分
前提条件
Node イメージのビルド において説明した手順をひととおり行っていること。
概要
前節においてはサンプルアプリケーションを構築し、イメージビルドに利用する Dockerfile を生成しました。
イメージのビルドにはdocker build
というコマンドを使いました。
イメージのビルドができたので、そのイメージを実行して、アプリケーションが正しく動作することを確認します。
コンテナーというものは、オペレーティングシステム内の通常のプロセスにすぎません。 ただしこのプロセスは他から隔離されていて、独自のファイルシステム、独自のネットワークを持ちます。 またホストからは引き離された独自のプロセスツリーを持ちます。
コンテナー内においてイメージを実行するにはdocker run
コマンドを使います。
docker run
コマンドには 1 つの引数を必要とします。
それはイメージ名です。
ここまでに作り出したイメージを使って、正しく動作することを確認します。
ターミナルから以下のコマンドを実行します。
$ docker run node-docker
このコマンドを実行しても、コマンドプロンプトの入力状態には戻りません。 この理由は、実行したアプリケーションが 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 コマンドは、サーバーへの接続が拒否されたために失敗しました。 localhost のポート 8000 には接続できなかったということです。 この動作は期待どおりであって、コンテナーはネットワークも含めて隔離された環境内で実行されているからです。 一度コンテナーを停止させて、今度はローカルネットワーク上にポート 8000 を公開した上で再起動してみます。
コンテナーを停止するには Ctrl-C を入力します。 これによってターミナルのコマンドプロンプトが入力状態に戻ります。
コンテナーのポートを公開するには、docker run コマンドにおいて--publish
フラグ(あるいは-p
フラグ)を指定します。
--publish
フラグの書式は[ホストポート]:[コンテナーポート]
です。
そこでコンテナー内部のポート 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 INFO: POST /test
Ctrl-C を入力してコンテナーを停止します。
デタッチモード実行
ここまではうまくいきました。
もっともこのサンプルアプリケーションはウェブサーバーなので、ターミナルからコンテナーに接続するものではありません。
Docker ではコンテナーをデタッチモード(detached mode)、つまりバックグラウンドで実行することができます。
これを行うには--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"}]}
コンテナーの一覧表示
コンテナーをバックグラウンドで実行したので、コンテナーが実行しているかどうか、他にどんなコンテナーがマシン上で動作しているかは、どうやって調べたらよいでしょう。
それはdocker ps
コマンドを使います。
Linux 上であれば、マシン上のプロセス一覧を確認するには ps コマンドを実行します。
同じように Docker では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
ここまでの手順に沿って作業をしていれば、コンテナーがいくつか出力されたはずです。 このコンテナーはこれまでに起動し停止し、そのまま削除していないものです。
停止したコンテナーをここで再起動してみましょう。 停止したコンテナーの名前を確認して、再起動を行う以下のコマンドにおけるコンテナー名を書き換えて指定してください。
$ docker restart 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 seconds」(起動後 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
こうしてコンテナーの識別は、名前を使って簡単に行えるようになりました。
次のステップ
本節ではコンテナーの実行、ポート公開、デタッチモードでの実行を行いました。 またコンテナーの起動、停止、再起動という制御を行いました。 そしてコンテナーに名前づけを行って、識別しやすくしました。 次節ではコンテナー内においてデータベースを実行して、アプリケーションを接続する方法を示します。 以下を参照してください。
フィードバック
本トピック改善のためにフィードバックをお寄せください。 お気づきの点があれば Docker Docs の GitHub リポジトリに issue をあげてください。 あるいは PR の生成 により変更の提案を行ってください。