修正履歴:
@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