Docker Compose入門 (2) ~ウェブサーバの開発環境を作るための準備~
前回(第1回)は、Dockerコンテナに対応するアプリケーションを開発・実行するために、Docker Composeというツールを使うのが便利ということで、例としてDocker Composeを使ってWordPressをコマンド1つで実行する方法を紹介しました。WordPressのような、しっかりとしたアプリケーション以外でもDocker Composeが使える場面があります。
今回は、Docker Composeを使ってウェブサーバ(Apache httpd)を実行し、コンテンツを表示する例を見ていきましょう。
目次
なぜDocker Composeなのか?
単純にウェブサーバとして実行するアプリケーションであれば、Dockerだけで何ら困らないでしょう。例えば、Apache httpdサーバを実行するには、次のようにしてコンテナを実行できます。
docker run -d httpd
しかし、実際には、複数のコンテナ(ウェブサーバやデータベースサーバなど)を同時に起動し、相互に通信するケースも多いでしょう。
docker run -d httpd docker run -d mariadb …等々
そうなりますと、コンテナ間の通信のためにネットワークの管理が必要ですし、データを共有するためのボリューム管理も必要です。毎回dockerコマンドを使っても実現できますが、あまりDockerらしいスマートなやりかたとはいえません。コンテナの活用にふさわしい、スケールしやすい環境を整えるためには、Docker Composeの活用が楽でしょう。
単純なApache httpdサーバをComposeで起動するには?
今回は簡単な例として、シンプルなウェブサーバ(Apache httpd)を、ComposeファイルとDockerfileを書いて実行する例を紹介します。
Dockerでhttpdコンテナを実行する方法
Apache httpdを1つだけ起動するのであれば、Docker Composeを使わなくても非常にシンプルに済みます。次のコマンドは、Apache httpdが入っているDockerイメージ「httpd:alpine」を実行するものです。コマンドを補足しますと、イメージ名に付けるタグ「alpine」とは、Alpine Linuxベースのイメージにhttpdをセットアップしたもので、容量が110MB程度と小さなものです。オプションの「-d」はデタッチド・モードとしてバックグラウンドでコンテナを実行します。そして「-p 8080:80」は、ホスト側のポート8080をコンテナ内のポート80にマッピング(割り当て)します。
docker run -d -p 8080:80 --name docker-httpd --rm httpd:alpine
それから、コンテナが起動しているかどうかを調べましょう。「docker ps」コマンドを実行したら、次のような表示になります。
# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3c872b356aea httpd:alpine "httpd-foreground" 4 seconds ago Up 2 seconds 0.0.0.0:8080->80/tcp docker-httpd
もしも、ホスト側で既にポート8080を使用中の場合、コンテナは起動に失敗し、コンテナは実行中になりません。その場合はポート番号を8080のかわりに8090など、空いている未使用ポートを指定して起動しなおします。あとは、ブラウザから「http://<サーバのIPアドレス>:8080」を開けば、次のようなApache初期画面が表示されます。
停止するには、次のコマンドを実行するだけです。
docker kill docker-httpd
コンテナ実行時に「--rm」オプションを付けていましたので、コンテナのプロセスが停止後は、自動的にコンテナ(用のイメージレイヤ及びログなど関連情報)も自動的に削除されます。
Docker Composeでhttpdコンテナを実行する方法
次はDocker Composeを使ってhttpdを実行する方法を見ていきます。Docker Composeを使ってウェブサーバを立ち上げるには、まず、作業用のディレクトリを作成し、そのディレクトリに移動する必要があります。ここではdocker-httpdという名前のディレクトリを作成し、移動しましょう。
$ mkdir docker-httpd && cd docker-httpd
ここでディレクトリを作成・移動したのは、Docker Composeで操作するときに作業対象となる「プロジェクト」を準備するためです。Docker Composeコマンドの実行時、現在操作している(カレントの)ディレクトリにある「docker-compose.yaml」、又は「docker-compose.yml」を探し、その記述内容に従ってコンテナやネットワークなどを一括操作します。
この作業ディレクトリのことを、Docker Composeでは「プロジェクト」と呼びます。デフォルトでは、ディレクトリ名をプロジェクト名として扱います。そのため、今回の例ではディレクトリ名「docker-httpd」が、プロジェクト名にもなります。なお、このプロジェクト名に結び付けて、ネットワーク名やボリューム名も管理されます。
次に、ディレクトリ内で「docker-compose.yaml」ファイルを作成します。この拡張子が示すように、内容の記述はYAML形式の書式に従う必要があります。
お好みのエディタでファイルを開き、内容を次のようにします。
version: '3' services: web: build: . ports: - "8080:80"
内容を上から順番に説明します。
- 「version: '3'」 …Docker Composeファイル形式のバージョン指定です。バージョンによって細かな記法や挙動が異なります。現時点では「3」を指定しておくのが望ましいでしょう。ネットワークやボリュームも操作可能であり(バージョン2以降)、かつ、Swarmモードでのサービス実行にも対応しています。
- 「services:」 … コンテナとして実行するアプリケーション"サービス"の意味です。通常は、この中で、どのようにしてコンテナを実行するのか定義します。
- 「web」 … これは「web」という名称のサービスを定義しています。
- 「build: .」 … 「.」(現在のディレクトリ)にあるDockerfileでDockerイメージをビルドします。
- 「ports:」 … このサービスが公開するポートの指定です。"ホスト側のポート番号:コンテナ内のポート番号"の順番です。
それから、次の内容で Dockerfile を準備します。
FROM httpd:alpine
これは「httpd:alpine」という名称のDockerイメージをベースにしてDockerイメージをビルド(構築)する命令です。このDockerfileはDocker Composeだからといって特段構文は変わりません。通常のDockerfile同様、必要があれば命令行を好きなように追加・編集できます。
これで、同一ディレクトリに「docker-compose.yaml」と「Dockerfile」が整いました。
DockerfileとComposeファイルでビルドする
次に、httpd アプリケーションを実行する前に、イメージのビルドを行います。Docker イメージの場合は「docker image build」か「docker build」コマンドを使いました。Docker Composeの場合は「docker-compose build」コマンドでイメージをビルドします。
$ docker-compose build Building web Step 1/1 : FROM httpd:alpine alpine: Pulling from library/httpd Digest: sha256:ca20eca5ae5c1be31bdf99d700d86d9164edd71bcf519325bde67ed04aa1008f Status: Downloaded newer image for httpd:alpine ---> cb171b88ec92 Successfully built cb171b88ec92 Successfully tagged apache_web:latest
このコマンドは、イメージをビルドする「docker image build」コマンドを都度実行しなくても、自動的にDockerfileが処理され、イメージが作成されています。今回は1つのDockerイメージがビルド対象ですが、複数のDockerイメージを自動ビルドすることも可能です。ビルドするたび、毎回タグを指定する必要がないため、複数のイメージを同時に扱う場合には、より強力な手助けになるでしょう。
以上で準備が調いました。
Docker Composeでプロジェクトの実行
準備が整ったあとはサービスを実行します。「docker-compose up」コマンドに、デタッチド・モードとしてバックグラウンドで実行するのを示す「-d」オプションも付与します。(なお、このオプションがなければフォアグラウンドで実行しますので、その場合は「Ctrl+C」で中断できます。)
$ docker-compose up -d Creating network "dockerhttpd_default" with the default driver Creating dockerhttpd_web_1 ... done
このとき、出力結果の1行目を見ますと、自動的に専用のブリッジ・ネットワーク「dockerhttpd_default」が作成されています。これは、同一プロジェクト内のみで通信可能な、専用のブリッジ・ネットワークを自動的に作成しています。先ほどのYAMLファイルでポートのマッピングを「8080:80」と指定していたのを覚えていますでしょうか。
ports: - "8080:80"
これは、「ホスト側のポート8080」を、このブリッジ・ネットワーク「dockerhttpd_defaultネットワーク内のポート80にマッピングする」という意味でした。なお、今回の例では実行するコンテナは1つですが、もしサービスとして複数のコンテナを実行する場合は、ブリッジネットワーク内で自動的にアクセスの負荷分散(ラウンドロビン方式)が処理されます。
それから、サービスが実行中かどうかは「docker-compose ps」コマンドを使います。
$ docker-compose ps Name Command State Ports ------------------------------------------------------------------- dockerhttpd_web_1 httpd-foreground Up 0.0.0.0:8080->80/tcp
サービスの状態を示す「State」列が「Up」であれば実行中です。ブラウザから「http://<サーバのIPアドレス>」を表示すると、先ほどと同様にApacheの初期画面「It works!」が表示されましたでしょうか。
起動したサービスを停止する
一旦起動したサービスは停止したり、再起動したりできます。停止するには「docker-compose stop」です。
$ docker-compose stop Stopping dockerhttpd_web_1 ... done
状態を調べるコマンドを実行すると、状態(State)が終了(Exit)となっているのが分かります。
$ docker-compose ps Name Command State Ports ------------------------------------------------------- dockerhttpd_web_1 httpd-foreground Exit 137
停止しているサービスを再び起動するには「docker-compose up -d」を実行します。
$ docker-compose up -d Starting dockerhttpd_web_1 ... done
サービスのデバッグ
サービスが実行中の場合、コンテナ内で操作することができます。サービスとして実行中のコンテナに対し、プロセスを追加するには「docker-compose exec <サービス名> <コマンド>」を実行します。
今回は「web」というサービスを実行中です。このコンテナ内に「/bin/bash」プロセスを追加するには、次のように実行します。
# docker-compose exec web /bin/bash bash-5.0#
コンテナ内での操作は通常の「bash」ですので、「exit」で終了できます。
また、コンテナの中に入る必要がなければ「docker-compose logs」コマンドで、サービスの標準出力を確認することもできます。
サービスの終了・削除
使わなくなったサービスは終了・削除します。このとき、1つ1つ「docker kill」コマンドなどで止める必要がありません。「docker-compose down」コマンドを使うと、Dockerイメージの停止・削除と、このプロジェクトが使用するブリッジ・ネットワークも自動削除します。
$ docker-compose down -v Stopping dockerhttpd_web_1 ... done Removing dockerhttpd_web_1 ... done Removing network dockerhttpd_default
Dockerfile の修正と、サービス実行時にビルドも行う方法
実際の利用シーンでは、頻繁にDockerfileの書き換えも発生するでしょう。今回はApacheのドキュメント・ルート(サイトにアクセス時、トップページとして表示されるディレクトリ)に書き換えたindex.htmlを置きます。まずは、docker-httpdディレクトリ内で「Hello World」を表示するindex.htmlファイルを作成します。
$ echo '<h1>Hello World</h1>' > index.html $ cat index.html <h1>Hello World</h1>
Dockerfileも編集し、作成したindex.htmlをCOPY命令でコンテナ内のドキュメント・ルートにコピーします。Dockerfileは次のように書き換えます。
FROM httpd:alpine COPY ./index.html /usr/local/apache2/htdocs/index.html
それから、Docker Composeを使い、実行時にビルドも同時に行うオプション「--build」を付けて実行します。
$ docker-compose up -d --build Creating network "dockerhttpd_default" with the default driver Building web Step 1/2 : FROM httpd:alpine ---> cb171b88ec92 Step 2/2 : COPY ./index.html /usr/local/apache2/htdocs/index.html ---> 7a499107c39a Successfully built 7a499107c39a Successfully tagged dockerhttpd_web:latest Creating dockerhttpd_web_1 ... done
それから改めてブラウザで「http://<サーバのIPアドレス>:8080」にアクセスしましょう。次のように表示されていれば正常です。
あとはCOPY行を書き換えれば、任意のコンテンツを表示できます。
今回の振り返り
今回はApache httpdを例に、DockerコンテナではなくDocker Composeのサービスとしてアプリケーションを扱う方法を試しました。次回以降は、より細かな設定方法や操作など、Docker Composeが行えることを深掘りしていきます。