Docker compose ことはじめハンズオン

  • 129
    いいね
  • 2
    コメント

修正履歴:
@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 オプションも含まれることもある)を記述したファイルになります。

docker-compose.ymlサンプル
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 のリリースページと異なる手順にしてあります)。

composeインストールコマンド(onUbuntu)
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コマンド確認
$ 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 は以下のように簡単なものとなります。

app-server/Dockerfile
FROM node:5
RUN npm -g install redis
ENV NODE_PATH /usr/local/lib/node_modules

ENTRYPOINT ["node", "app.js"]

次に、nodejs のソースコードを作成します。ディレクトリを以下のように作成します。

app-server/src/app.js
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 ファイルに記載します。

docker-compose.yml
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-composeup
$ docker-compose up
...

Docker DockerComposeHandsOn0000.png

上記のように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-composeによって作成されたイメージ名とコンテナ名
$ 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: 要素が削除された形となります。

docker-compose.yml
nodeapp:                            # <- サービス名
  build: "./app-server"             # <- Dockerfile のあるファイルの場所(Dockerfile のある場所。git リポジトリのURL も指定可能)
  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 コマンドでコンテナを起動します。

dockerbuild
$ 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