修正履歴:
@aosho235 さんのコメントより、Dockerfile の"EXPOSE 8888" の不要な記述を修正
@aosho235 さんのコメントより、node アプリを起動するコマンドが抜けていた点を修正(Dockerfile, docker-compose.yml)
@alt さんより編集リクエスト。シンタックスハイライトを適切なものに修正
感謝<(_ _)>
Docker Compose 概要
Docker compose とは、複数のコンテナから成るサービスを構築・実行する手順を自動的にし、管理を容易にする機能です。
Docker compose では、compose ファイルを用意してコマンドを1 回実行することで、そのファイルから設定を読み込んですべてのコンテナサービスを起動することができます。
Docker Compose を使うまでの主なステップ
Docker compose を使用するには、大きく分けて以下の3 つの手順から成り立ちます。
- それぞれのコンテナのDockerfile を作成します(既にあるイメージを使う場合は不要)
- docker-compose.yml を作成し、それぞれ独立したコンテナの起動定義を行います(場合によっては構築定義も含まれる)
- "docker-compose up" コマンドを実行してdocker-compose.yml で定義したコンテナを開始します
Docker compose はstart, stop, status, 起動中のコンテナのログ出力, ちょっとしたコマンドの実行といった機能も持ち合わせています(今回は割愛)。
docker-compose.yml ファイルとは
docker-compose.yml
ファイルは以下のようにyaml でDocker コンテナに関する起動オプション(build オプションも含まれることもある)を記述したファイルになります。
web:
build: .
ports:
- "5000:5000"
volumes:
- .:/code
links:
- redis
redis:
image: redis
# yaml の記載方法については下記を参照
# https://docs.docker.com/compose/compose-file/
このファイルに記載されている内容は基本的にdocker build
, docker run
コマンド指定することができるオプションになりますが、Docker compose のyaml ファイルとして記述することで複数のコンテナーから成るサービスを俯瞰的に見ることができるようになり、保守性のコストを軽くすることができます。
環境要件
今回実施した環境は以下のとおりです。
- 構成
OS | Ubuntu 15.04 |
---|---|
Docker Engine | version 1.9.1 |
事前準備
Docker Engine は既にインストールされているものとします。
Docker Engine をDocker リポジトリからインストールする(Ubuntu 15.04, 14.04 LTS)
Docker compose のインストール
基本的にはdocker compose のリリースページにアクセスして最新情報を確認し、Docker compose をインストールしていくことになります。
Docker compose release page
curl コマンドを使い以下のようにすることでインストールは完了です(一部docker compose のリリースページと異なる手順にしてあります)。
sudo COMPOSE_VERSION=1.5.2 bash -eu << '__EOT__'
echo ${COMPOSE_VERSION}
curl -L https://github.com/docker/compose/releases/download/${COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
chown root:docker /usr/local/bin/docker-compose
chmod ug+x /usr/local/bin/docker-compose
update-alternatives --install /usr/bin/docker-compose docker-compose /usr/local/bin/docker-compose 10
__EOT__
インストールが完了したら、docker-compose
コマンドを実行して動作を確認してみましょう。
$ docker-compose --version
docker-compose version 1.5.2, build 7240ff3
version が出力されれば、インストール成功です。
今回動作確認を行う環境について
今回DockerCompose のハンズオンを行うに当たり、資材の構成は以下のようになっています。
(Working dir)
+- docker-compose.yml
+- app-server/
+- Dockerfile
+- src/
+- app.js
Docker compose を使用した簡単なサンプル
Docker compose を使用した複数コンテナでひとつのサービスを作成するサンプルを実施してみます。
Document とほぼ同じ内容になりますが、のredis を使用してアクセス数をカウントする簡単なアプリケーションを作成してみます。
application 側の作成
アプリケーション側はnodejs を使用します。
今回はnode の公式リポジトリを使用するための、Dockerfile は以下のように簡単なものとなります。
FROM node:5
RUN npm -g install redis
ENV NODE_PATH /usr/local/lib/node_modules
ENTRYPOINT ["node", "app.js"]
次に、nodejs のソースコードを作成します。ディレクトリを以下のように作成します。
var redis = require('redis');
var redis_client = redis.createClient(6379, "noderedis");
var listen_port = 10080;
require('http').createServer(function (request, response) {
redis_client.incr('counter', function(error, reply) {
response.writeHead(200, {'Content-Type': 'text/plain'});
response.end("You accessed here " + reply + " times.\n");
});
}).listen(listen_port, '0.0.0.0');
console.log("Server is running on port " + listen_port + ".");
Redis 側の作成
Redis 側のコンテナの作成を行いますが、公式のRedis イメージを使用するためこちらはDockerfile は不要です。
Docker compose ファイルの作成
アプリ側のnode のアプリケーションとredis 側のアプリケーションをbuild, run するための定義をdocker-compose ファイルに記載します。
nodeapp:
build: "./app-server"
container_name: "nodeapp"
working_dir: "/usr/src/app"
ports:
- "10080:10080"
volumes:
- "$PWD/app-server/src:/usr/src/app"
links:
- "noderedis"
noderedis:
image: "redis:3"
container_name: "noderedis"
※@aosho235 さんのコメントより、Dockerfile に"ENTRYPOINT" を書かなかった場合はdocker-compose.yml に下記のように追記する方法で対応することも可能。
nodeapp:
......
command: node app.js
今回はnode のアプリケーションが乗るコンテナは、Dockerfile からイメージをbuild してそこからnodeapp という名前のコンテナを起動します。
redis が乗るコンテナについては、Dockerfile からイメージをbuild せずにDocker hub からpull してきた公式イメージを利用し、そこからnoderedis という名前のコンテナを起動します。
docker-compose.yml
ファイルのあるディレクトリまで移動し、docker-compose up
コマンドを実行します。
$ docker-compose up
...
上記のようにnode アプリとredis アプリのコンテナが同時に起動し、ひとつのコンソール上にそれぞれのコンテナのタグ付きでログが出力されます。
正常に起動したところで、動作確認をしてみましょう。
$ curl http://localhost:10080
You accessed here 1 times.
$ curl http://localhost:10080
You accessed here 2 times.
$ curl http://localhost:10080
You accessed here 3 times.
上記のようにredis からデータを引き出してきてアクセス数がカウントできていれば成功です。
docker-compose コマンドで作成されるイメージ名について
docker-compose up
コマンドを使用すると自動的にDocker イメージも作成してくれますが、そのイメージは以下のようなイメージとなります。
$ docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
dockercomposeexamplesimple_nodeapp latest 7d39370b4309 23 hours ago 643.5 MB
redis 3 0c4334bed751 4 days ago 151.3 MB
node 5 285fd945c0b6 2 weeks ago 642.7 MB
debian jessie 23cb15b0fcec 4 weeks ago 125.1 MB
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e48a2014b88d dockercomposeexamplesimple_nodeapp "node app.js" 4 minutes ago Up 4 minutes 0.0.0.0:10080->10080/tcp nodeapp
b8b47ca9a285 redis:3 "/entrypoint.sh redis" 23 hours ago Up 4 minutes 6379/tcp noderedis
上記の出力結果を確認すると、Redis については Docker Hub 公式からpull してきたイメージなのでredis:3
というわかりやすいイメージ名(+ タグ) ですが、nodejs に関してはdockercomposeexamplesimple_nodeapp
というイメージ名が自動的につけられています。調べたところ、現段階ではイメージの名前をdocker-compose.yml
ファイル内で指定する方法は仕様として無いようです(2015/01/03 現在)。
このイメージは、最終的にはnodejs のコンテナとしてdocker-compose.yml
内で指定した名前で作成されるので、動作上問題はありません(例えばlink でこのnodejs コンテナと接続する必要性のあるコンテナが出てきてもdocker-compose.yml 内で指定したものになるので、予め接続先のコンテナ名は推測できるし、構築の自動化に支障はきたしません)。
しかしどうしても見栄えが悪い、直接docker コマンドを実行して構築するシーンが出てきた時に乱雑なイメージのリストを見るのは嫌だ…という場合は事前にbuild したdocker イメージを指定してcompose-up を実行するという手順があります。
まず、docker-compose.yml
ファイルを以下の用に編集します。先ほど使用したファイルにimage:
要素が追加され、build:
要素が削除された形となります。
nodeapp: # <- サービス名
image: "tsutomu/nodeapp" # <- 使用するDocker イメージ名(この後ビルドする)
container_name: "nodeapp" # <- コンテナ名。指定しなかった場合はDocker compose で勝手に決められる
working_dir: "/usr/src/app" # <- コンテナ内のワーキングディレクトリ。docker run コマンドの-w/--workdir に相当
ports: # <- Expose するポート。docker run コマンドの-p/--publish に相当
- "10080:10080"
volumes: # <- Bind mount するディレクトリ。volume。docker run コマンドの-v/--volume に相当
- "$PWD/app-server/src:/usr/src/app"
links: # <- 他のコンテナと接続するときのコンテナ名。docker run コマンドの--link に相当
- "noderedis"
noderedis:
image: "redis:3" # <- イメージIDとtag
container_name: "noderedis"
新規に追加したimage:
の値に一致するようにdocker build
コマンドでイメージを作成し、docker-compose up
コマンドでコンテナを起動します。
$ docker build -t "tsutomu/nodeapp" ./app-server
ここで、イメージ名とコンテナ名を確認してみましょう。
先ほどと違い、docker-compose によって作成されたイメージは存在しないはずです。
$ docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
tsutomu/nodeapp latest 2169cc98c4e2 2 minutes ago 643.5 MB
redis 3 0c4334bed751 4 days ago 151.3 MB
node 5 285fd945c0b6 2 weeks ago 642.7 MB
debian jessie 23cb15b0fcec 4 weeks ago 125.1 MB
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d9c9f2a70735 tsutomu/nodeapp "node app.js" 9 seconds ago Up 8 seconds 8888/tcp, 0.0.0.0:10080->10080/tcp nodeapp
e295c5ff24fc redis:3 "/entrypoint.sh redis" 9 minutes ago Up 9 minutes 6379/tcp noderedis
参考
- Overview of Docker Compose
- https://docs.docker.com/compose/#features
- Using Redis with Node.js
- http://www.sitepoint.com/using-redis-node-js/
- It should be possible to explicit name images and containers
- https://github.com/docker/compose/issues/541