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

読む時間の目安: 3 分

前提条件

Go 言語イメージのビルド において説明した手順をひととおり行っていること。

概要

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

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

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

$ docker run docker-gs-ping
   ____    __
  / __/___/ /  ___
 / _// __/ _ \/ _ \
/___/\__/_//_/\___/ v4.2.2
High performance, minimalist Go web framework
https://echo.labstack.com
____________________________________O/_______
                                    O\
⇨ http server started on [::]:8080

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

さてそこで、このサーバーに対してcurlコマンドを使ってGETリクエストを行ってみます。

$ curl http://localhost:8080/
curl: (7) Failed to connect to localhost port 8080: Connection refused

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

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

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

コンテナーを起動させ、ポート8080をホスト上のポート8080として公開します。

$ docker run --publish 8080:8080 docker-gs-ping

そこで先ほどの curl コマンドを再度実行してみます。

$ curl http://localhost:8080/
Hello, Docker! <3

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

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

デタッチモード実行

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

$ docker run -d -p 8080:8080 docker-gs-ping
d75e61fcad1e0c0eca69a3f767be6ba28a66625ce4dc42201a8a323e8313c14e

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

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

$ curl http://localhost:8080/
Hello, Docker! <3

コンテナーの一覧表示

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

$ docker ps

CONTAINER ID   IMAGE            COMMAND             CREATED          STATUS          PORTS                    NAMES
d75e61fcad1e   docker-gs-ping   "/docker-gs-ping"   41 seconds ago   Up 40 seconds   0.0.0.0:8080->8080/tcp   inspiring_ishizaka

psコマンドは実行中コンテナーに関して、いろいろな情報を表示します。 その情報とは以下です。 コンテナー ID、コンテナー内部で実行しているイメージ、コンテナー起動時に用いられた実行コマンド、コンテナー生成時刻、ステータス、公開ポート、コンテナー名です。

コンテナー名はどうやって決まったんだろうと不思議に思うかもしれません。 コンテナーを起動したときにはコンテナー名を指定したわけではないので、Docker がランダムに名前を生成します。 コンテナー名はこの後すぐに変更していきますが、そのためにはまずコンテナーを停止する必要があります。 コンテナーを停止するにはdocker stopコマンドを実行します。 このコマンドはそのとおりにコンテナーを停止させます。 この際にはコンテナー名あるいはコンテナー ID を指定します。

$ docker stop inspiring_ishizaka
inspiring_ishizaka

docker psコマンドをもう一度実行して、実行中コンテナーの一覧を確認します。

$ docker ps

CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

コンテナーの停止、起動、名前変更

Docker コンテナーは起動させ停止させ、再起動することができます。 コンテナーを停止してもコンテナーが削除されるわけではなく、ステータスが停止となり、コンテナー内のプロセスが停止します。 docker psコマンドを実行したときに、出力されるコンテナーはデフォルトでは実行中コンテナーのみです。 --allまたは-aを指定すると、システム上にあるコンテナーすべて、つまり停止、起動にかかわらずすべてが表示されます。

$ docker ps -all

CONTAINER ID   IMAGE            COMMAND                  CREATED              STATUS                      PORTS     NAMES
d75e61fcad1e   docker-gs-ping   "/docker-gs-ping"        About a minute ago   Exited (2) 23 seconds ago             inspiring_ishizaka
f65dbbb9a548   docker-gs-ping   "/docker-gs-ping"        3 minutes ago        Exited (2) 2 minutes ago              wizardly_joliot
aade1bf3d330   docker-gs-ping   "/docker-gs-ping"        3 minutes ago        Exited (2) 3 minutes ago              magical_carson
52d5ce3c15f0   docker-gs-ping   "/docker-gs-ping"        9 minutes ago        Exited (2) 3 minutes ago              gifted_mestorf

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

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

$ docker restart inspiring_ishizaka

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

$ docker ps -a

CONTAINER ID   IMAGE            COMMAND                  CREATED          STATUS                     PORTS                    NAMES
d75e61fcad1e   docker-gs-ping   "/docker-gs-ping"        2 minutes ago    Up 5 seconds               0.0.0.0:8080->8080/tcp   inspiring_ishizaka
f65dbbb9a548   docker-gs-ping   "/docker-gs-ping"        4 minutes ago    Exited (2) 2 minutes ago                            wizardly_joliot
aade1bf3d330   docker-gs-ping   "/docker-gs-ping"        4 minutes ago    Exited (2) 4 minutes ago                            magical_carson
52d5ce3c15f0   docker-gs-ping   "/docker-gs-ping"        10 minutes ago   Exited (2) 4 minutes ago                            gifted_mestorf

上で再起動したコンテナーはデタッチモードで起動され、ポート8000が公開されています。 またコンテナーのステータスを見てみると「Up X seconds」(起動後 X 秒)となっています。 コンテナーを再起動したときには、はじめに起動したときと同じフラグ、同じコマンドによって起動されます。

ではコンテナーすべてを停止して削除します。 そしてランダムな名前になってしまう点を修正していきます。

起動したばかりのコンテナーを停止させます。 システム上の実行中コンテナーの名前を確認して、以下のコマンドにおけるコンテナー名を書き換えて指定してください。

$ docker stop inspiring_ishizaka
inspiring_ishizaka

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

コンテナーを削除するには、docker rmコマンドにコンテナー名を与えて実行します。 このコマンド 1 つに対して複数のコンテナー名を指定することもできます。

同じように、以下のコマンドにおけるコンテナー名を書き換えて指定してください。

$ docker rm inspiring_ishizaka wizardly_joliot magical_carson gifted_mestorf

inspiring_ishizaka
wizardly_joliot
magical_carson
gifted_mestorf

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

それでは、うっとうしいランダム名を解決します。 コンテナーに名前をつける理由は単純なものです。 どんなコンテナーが実行されているのかがすぐにわかります。 またどんなアプリケーションやサービスが関連づいているのかがわかります。 ソースコード上での変数の命名規則のようにすれば、単純に読みやすくなります。 だからコンテナーの命名も同じようにします。

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

$ docker run -d -p 8080:8080 --name rest-server docker-gs-ping
3bbc6a3102ea368c8b966e1878a5ea9b1fc61187afaac1276c41db22e4b7f48f
$ docker ps

CONTAINER ID   IMAGE            COMMAND             CREATED          STATUS          PORTS                    NAMES
3bbc6a3102ea   docker-gs-ping   "/docker-gs-ping"   25 seconds ago   Up 24 seconds   0.0.0.0:8080->8080/tcp   rest-server

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

次のステップ

本節ではコンテナーの実行、ポート公開を行いました。 またコンテナーのライフサイクルを管理する方法も学びました。 そしてコンテナーに名前づけを行って、識別しやすくしました。 次節ではコンテナー内においてデータベースを実行して、アプリケーションを接続する方法を示します。 以下を参照してください。

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

フィードバック

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


get started, go, golang, run, container