EC2 + Docker Machine + Swarm + Composeでコンテナオーケストレーションする

はじめに

今回はDocker MachineDocker SwarmDocker Composeの3つを使って、Amazon EC2でDockerコンテナをオーケストレーションしてみます!

やってみた

Swarmクラスタを作成する

まずは前回と同様に、Docker MachineでSwarmクラスタを作成します。

なおswarm createではdiscovery-stage.hub.docker.comにリクエストしてクラスタIDを取得しているのですが、タイミングによってはエラーが出る事がありました。現在はベータリリースという扱いなので仕方がないかと思いますが、ちょっと注意が必要です。

$ sudo docker run --rm swarm create
4e8ebb66a08f838fe05a36c20341f044

$ sudo ./docker-machine create --driver amazonec2 --amazonec2-access-key YOUR_ACCESS_KEY --amazonec2-secret-key YOUR_SECRET_KEY --amazonec2-region ap-northeast-1 --amazonec2-ami ami-a1bf56a1 --amazonec2-vpc-id YOUR_VPC_ID--swarm --swarm-master --swarm-discovery token://4e8ebb66a08f838fe05a36c20341f044 master
$ sudo ./docker-machine create --driver amazonec2 --amazonec2-access-key YOUR_ACCESS_KEY --amazonec2-secret-key YOUR_SECRET_KEY--amazonec2-region ap-northeast-1 --amazonec2-ami ami-a1bf56a1 --amazonec2-vpc-id YOUR_VPC_ID--swarm --swarm-discovery token://4e8ebb66a08f838fe05a36c20341f044 node1
$ sudo ./docker-machine create --driver amazonec2 --amazonec2-access-key YOUR_ACCESS_KEY --amazonec2-secret-key YOUR_SECRET_KEY --amazonec2-region ap-northeast-1 --amazonec2-ami ami-a1bf56a1 --amazonec2-vpc-id YOUR_VPC_ID--swarm --swarm-discovery token://4e8ebb66a08f838fe05a36c20341f044 node2

作成されたSwarmクラスタはこんな感じ。EC2インスタンスが3台追加されているはずです。

$ sudo ./docker-machine ls
NAME     ACTIVE   DRIVER      STATE     URL                         SWARM
master            amazonec2   Running   tcp://54.178.132.195:2376   master (master)
node1             amazonec2   Running   tcp://54.92.24.244:2376     master
node2    *        amazonec2   Running   tcp://54.178.180.56:2376    master

Docker Composeをインストールする

Docker Composeはバイナリをダウンロードしてくるだけです。

$ curl -L https://github.com/docker/compose/releases/download/1.1.0/docker-compose-`uname -s`-`uname -m` > docker-compose
$ sudo mv ./docker-compose /usr/local/bin
$ sudo chmod +x /usr/local/bin/docker-compose
$ docker-compose --version
docker-compose 1.1.0

オーケストレーションするDockerコンテナイメージを作成する

今回はWebサーバとMemcachedサーバを構築し、Memcachedにカウンター値を格納して、Webサーバにアクセスするたびにカウントアップする、という仕組みを作ります。このためWebアプリケーションを搭載したWebサーバ用のDockerイメージを作成します。

compose/web/scriptsというディレクトリを作り、その中にWebアプリケーションとなるRubyスクリプトを作成します。

$ mkdir ~/compose/web/scripts
$ vi ~/compose/web/scripts/app.rb

スクリプトの内容はこんな感じ。SinatraでWebサーバとして動作し、DalliによってMemcachedを操作します。Memcachedサーバは固定値を使っています(後述にて説明します)

require 'sinatra'
require 'dalli'

set :environment, :production

dc = Dalli::Client.new('54.178.132.195:11211')
value = Array.new

get '/' do
  if dc.get("count") == nil then
    dc.set("count", 1)
  end
  value = dc.get("count")
  dc.set("count", value + 1)
  "count is " + value.to_s
end

Webサーバ用DockerイメージのDockerfileでは、Docker Language Stackのrubyを使い、gemでSinatraとDalliを追加し、上述のrubyスクリプトを組み込んで起動しています。またSinatraのデフォルトポートである4567をEXPOSEしています。

$ vi ~/compose/web/Dockerfile
FROM ruby:latest

RUN gem install sinatra
RUN gem install dalli

ADD scripts/app.rb /usr/local/bin/app.rb

CMD ["ruby","/usr/local/bin/app.rb"]

EXPOSE 4567

このDockerfileをbuildし、Docker Hubに登録しておきます。

$ sudo docker build -t smokeymonkey/app .
$ sudo docker login
$ sudo docker push smokeymonkey/app:latest

Docker Composeの定義ファイルを作成する

Docker Domposeはdocker-compose.ymlファイルに定義を記述します。今回はwebコンテナとmemcachedコンテナを定義しており、Webコンテナでは前述で作成したWebサーバ用Dockerイメージを指定しています。

$ cd ~/compose/
$ vi docker-compose.yml
web:
  image: smokeymonkey/app:latest
  ports:
    - 4567
memcached:
  image: memcached
  ports:
    - 11211:11211
  environment:
  - constraint:node==master

memcachedコンテナはconstraint:node行によって必ずmasterノードで起動するように定義しています。これが上述のRubyスクリプトでMemcachedサーバのIPアドレスを固定値として埋め込んでいた理由です。

また、この仕組みでは11211/tcpとコンテナの4567/tcpポートがバインドされるランダムなホスト側ポートを使いますので、セキュリティグループで許可してください。

コンテナオーケストレーションする

さて本題。まず、Swarmクラスタを操作するために、環境変数を定義します。

$ $(sudo ./docker-machine env --swarm master)

次にComposeを操作するための環境変数の定義です。環境変数DOCKER_CLIENT_TIMEOUTはデフォルトでは60秒なのですが、大きなサイズのコンテナイメージを使う場合すぐにタイムアウトしてしまうので、大きく取っておきます。

$ export DOCKER_CLIENT_TIMEOUT=600

では起動!

$ sudo -E /usr/local/bin/docker-compose up -d
Creating compose_web_1...
Creating compose_memcached_1...

$ sudo -E /usr/local/bin/docker-compose ps
       Name                    Command             State                Ports
------------------------------------------------------------------------------------------
compose_memcached_1   memcached                    Up      54.178.132.195:11211->11211/tcp
compose_web_1         ruby /usr/local/bin/app.rb   Up      54.92.24.244:49153->4567/tcp

memcachedコンテナとweb_1コンテナが起動しました。試しにweb_1コンテナにアクセスしてみます。

$ curl 54.92.24.244:49153
count is 1

ちゃんとカウントが取れてますね。

コンテナをスケールアップさせる

それではオーケストレーションのキモ、コンテナをスケールさせてみます。

$ sudo -E /usr/local/bin/docker-compose scale web=5
Creating compose_web_2...
Creating compose_web_3...
Creating compose_web_4...
Creating compose_web_5...
Starting compose_web_2...
Starting compose_web_3...
Starting compose_web_4...
Starting compose_web_5...

一気に4つのコンテナが増えました。確認してみます。

$ sudo -E /usr/local/bin/docker-compose ps
       Name                    Command             State                Ports
------------------------------------------------------------------------------------------
compose_memcached_1   memcached                    Up      54.178.132.195:11211->11211/tcp
compose_web_1         ruby /usr/local/bin/app.rb   Up      54.92.24.244:49153->4567/tcp
compose_web_2         ruby /usr/local/bin/app.rb   Up      54.178.132.195:49155->4567/tcp
compose_web_3         ruby /usr/local/bin/app.rb   Up      54.178.180.56:49154->4567/tcp
compose_web_4         ruby /usr/local/bin/app.rb   Up      54.92.24.244:49156->4567/tcp
compose_web_5         ruby /usr/local/bin/app.rb   Up      54.92.24.244:49157->4567/tcp

Swarmノードに分散されて、Webコンテナが5つに増えています!

カウンタの動作を確認してみます。

$ curl 54.178.132.195:49155
count is 2

$ curl 54.178.180.56:49154
count is 3

$ curl 54.92.24.244:49156
count is 4

$ curl 54.92.24.244:49157
count is 5

問題なく、どのWebサーバにアクセスしても、カウントがアップされていますね!

コンテナをスケールダウンさせる

スケールダウンもコマンド一発でできます。

$ sudo -E /usr/local/bin/docker-compose scale web=1
Stopping compose_web_5...
Stopping compose_web_4...
Stopping compose_web_3...
Stopping compose_web_2...
Removing compose_web_5...
Removing compose_web_4...
Removing compose_web_3...
Removing compose_web_2...

$ sudo -E /usr/local/bin/docker-compose ps
       Name                    Command             State                Ports
------------------------------------------------------------------------------------------
compose_memcached_1   memcached                    Up      54.178.132.195:11211->11211/tcp
compose_web_1         ruby /usr/local/bin/app.rb   Up      54.92.24.244:49153->4567/tcp

簡単!

さいごに

まだまだベータリリースなので少々動作に気になる点はありますが(特にAPIサーバ側)、かなり楽に展開できました。こうなると今後のECSの展開が気になるところですねー。正式リリースが楽しみです。