コンテナーとしてのイメージ実行

読む時間の目安: 3 分

前提条件

Python イメージのビルド の手順により Python イメージをビルドしていること。

概要

前節においてはサンプルアプリケーションを構築し、イメージビルドに利用する Dockerfile を生成しました。 イメージのビルドにはdocker buildというコマンドを使いました。 イメージのビルドができたので、そのイメージを実行して、アプリケーションが正しく動作することを確認します。

コンテナーというものは、オペレーティングシステム内の通常のプロセスにすぎません。 ただしこのプロセスは他から隔離されていて、独自のファイルシステム、独自のネットワークを持ちます。 またホストからは引き離された独自のプロセスツリーを持ちます。

コンテナー内においてイメージを実行するにはdocker runコマンドを使います。 docker runコマンドには 1 つの引数を必要とします。 それはイメージ名です。 ここまでに作り出したイメージを使って、正しく動作することを確認します。 ターミナルから以下のコマンドを実行します。

$ docker run python-docker

このコマンドを実行しても、コマンドプロンプトの入力状態には戻りません。 この理由は、実行したアプリケーションが REST サーバーであって、入ってくる要求を待ち受けるためのループ内で実行されるからです。 つまり OS へ戻る制御はなく、戻るためにはコンテナーを停止させることになります。

さてそこで新たなターミナルを開いて、このサーバーに対してcurlコマンドを使ってGETリクエストを行ってみます。

$ curl localhost:5000
curl: (7) Failed to connect to localhost port 5000: Connection refused

上のcurlコマンドは、サーバーへの接続が拒否されたために失敗しました。 localhost のポート 5000 には接続できなかったということです。 この動作は期待どおりであって、コンテナーはネットワークも含めて隔離された環境内で実行されているからです。 一度コンテナーを停止させて、今度はローカルネットワーク上にポート5000を公開した上で再起動してみます。

コンテナーを停止するには Ctrl-C を入力します。 これによってターミナルのコマンドプロンプトが入力状態に戻ります。

コンテナーのポートを公開するには、docker runコマンドにおいて--publishフラグ(あるいは-pフラグ)を指定します。 --publishフラグの書式は[ホストポート]:[コンテナーポート]です。 そこでコンテナー内部のポート 3000 をコンテナー外部のポート 5000 として公開するには、--publishフラグに3000:5000と指定します。

コンテナー内の flask アプリケーションの起動にあたっては公開ポートを指定していませんでした。 そこで公開ポートはデフォルトの 5000 となります。 これまでのリクエストをポート 5000 に向けるには、ホストのポート 8000 をコンテナーのポート 5000 に割り当てます。

$ docker run --publish 8000:5000 python-docker

そこで先ほどの curl コマンドを再度実行してみます。 新しいターミナルを開くことを忘れないでください。

$ curl localhost:8000
Hello, Docker!

成功しました。 コンテナー内部で実行されているアプリケーションに対して、ポート 8000 による接続ができました。 コンテナーを実行させたターミナルに戻ってみると、コンソール上に GET リクエストのログが出力されているはずです。

[31/Jan/2021 23:39:31] "GET / HTTP/1.1" 200 -

Ctrl-C を入力してコンテナーを停止します。

デタッチモード実行

ここまではうまくいきました。 もっともこのサンプルアプリケーションはウェブサーバーなので、ターミナルからコンテナーに接続するものではありません。 Docker ではコンテナーをデタッチモード(detached mode)、つまりバックグラウンドで実行することができます。 これを行うには--detachフラグ、あるいは短く-dフラグを指定します。 Docker は先ほどと同じようにコンテナーを起動させますが、今回はコンテナーから「デタッチされた」つまり切り離されて実行されるので、ターミナルにプロンプトが戻ってきます。

$ docker run -d -p 8000:5000 python-docker
ce02b3179f0f10085db9edfccd731101868f58631bdf918ca490ff6fd223a93b

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

同じようにコンテナーが適切に動作していることを確認します。 前とまったく同じ curl コマンドを実行してみます。

$ curl localhost:8000
Hello, Docker!

コンテナーの一覧表示

コンテナーをバックグラウンドで実行したので、コンテナーが実行しているかどうか、他にどんなコンテナーがマシン上で動作しているかは、どうやって調べたらよいでしょう。 それはdocker psコマンドを使います。 Linux 上であれば、マシン上のプロセス一覧を確認するにはpsコマンドを実行します。 同じように Docker ではdocker psを実行します。 このコマンドによって、マシン上で稼働しているコンテナーの一覧が表示されます。

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
ce02b3179f0f        python-docker         "python3 -m flask ru…"   6 minutes ago       Up 6 minutes        0.0.0.0:8000->5000/tcp   wonderful_kalam

docker 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        python-docker         "python3 -m flask ru…"   16 minutes ago      Exited (0) 5 minutes ago                        wonderful_kalam
ec45285c456d        python-docker         "python3 -m flask ru…"   28 minutes ago      Exited (0) 20 minutes ago                       agitated_moser
fb7a41809e5d        python-docker         "python3 -m flask ru…"   37 minutes ago      Exited (0) 36 minutes ago                       goofy_khayyam

コンテナーがいくつか出力されたはずです。 このコンテナーはこれまでに起動し停止し、そのまま削除していないものです。

停止したコンテナーをここで再起動してみましょう。 停止したコンテナーの名前を確認して、再起動を行う以下のコマンドにおけるコンテナー名を書き換えて指定してください。

$ docker restart wonderful_kalam

そこで再びdocker psコマンドを使ってコンテナー一覧を確認します。

$ docker ps --all
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                      PORTS                    NAMES
ce02b3179f0f        python-docker         "python3 -m flask ru…"   19 minutes ago      Up 8 seconds                0.0.0.0:8000->5000/tcp   wonderful_kalam
ec45285c456d        python-docker         "python3 -m flask ru…"   31 minutes ago      Exited (0) 23 minutes ago                            agitated_moser
fb7a41809e5d        python-docker         "python3 -m flask ru…"   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        python-docker         "python3 -m flask ru…"   19 minutes ago      Up 8 seconds                0.0.0.0:8000->5000/tcp   wonderful_kalam
ec45285c456d        python-docker         "python3 -m flask ru…"   31 minutes ago      Exited (0) 23 minutes ago                            agitated_moser
fb7a41809e5d        python-docker         "python3 -m flask ru…"   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コマンドを実行し、コンテナーすべてがなくなっていることを確認してください。

それではランダム名となる点を解決します。 コンテナーに名前をつける理由は単純なものです。 どんなコンテナーが実行されているのかがすぐにわかります。 またどんなアプリケーションやサービスが関連づいているのかがわかります。

コンテナー名をつけるにはdocker runコマンドに--nameフラグをつけます。

$ docker run -d -p 8000:5000 --name rest-server python-docker
1aa5d46418a68705c81782a58456a4ccdb56a309cb5e6bd399478d01eaa5cdda
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
1aa5d46418a6        python-docker         "python3 -m flask ru…"   3 seconds ago       Up 3 seconds        0.0.0.0:8000->5000/tcp   rest-server

わかりやすくなりました。 こうしてコンテナーの識別は、名前を使って簡単に行えます。

次のステップ

本節ではコンテナーの実行、ポート公開、デタッチモードでの実行を行いました。 またコンテナーの起動、停止、再起動という制御を行いました。 そしてコンテナーに名前づけを行って、識別しやすくしました。 次節ではコンテナー内においてデータベースを実行して、アプリケーションを接続する方法を示します。 以下を参照してください。

アプリケーションの開発方法

フィードバック

本トピック改善のためにフィードバックをお寄せください。 お気づきの点があれば Docker Docs の GitHub リポジトリに issue をあげてください。 あるいは PR の生成 により変更の提案を行ってください。


Python, run, image, container