インフラのデプロイ

このステップでは、複数の Docker ホストを作成し、そこでアプリケーション・スタックを実行します。進める前に、 アプリケーション・アーキテクチャを学ぶ 必要があります。

構築手順について

以降のサンプルを実行する想定システムは、Mac あるいは Windows です。システム上で Docker Machine を経由して VirtualBox 仮想マシンをローカルにプロビジョニングし、Docker Engine の docker コマンドを使えるようにします。作業は6つの VirtualBox 仮想マシンをインストールします。

今回のサンプルでは Docker Machine を使いますが、任意のインフラ上で実行できます。希望するインフラ上であれば、どこでも環境を構築できる設計です。例えば、Azure や Digital Ocean などのようなパブリックのクラウド・プラットフォーム上で実行できるだけでなく、データセンタ上のオンプレミスや、ノート PC 上のテスト環境ですら動かせます。

なお、これら手順では複数の値を設定するにあたり、一般的な bash コマンド代入技術を使います。次のコマンドを例に考えましょう。

$ eval$(docker-machine env keystore)

Windows 環境では、このような代入指定に失敗します。Widows 上で実行する場合は、この $(docker-machineenvkeystore) を実際の値に置き換えてください。

タスク1:keystore (キーストア)サーバの作成

Docker コンテナ・ネットワークと Swarm ディスカバリを有効化するために、キーバリュー・ストアのデプロイが必要です。キーストアはディスカバリ・バックエンドとして、Swarm マネージャが使うクラスタのメンバ一覧を常に更新し続けます。Swarm マネージャはこの一覧を使い、ノードにタスクを割り当てます。

オーバレイ・ネットワークはキーバリュー・ストアが必要です。キーバリュー・ストアはネットワーク状態を保持するために使います。ネットワーク状態には、ディスカバリ、ネットワーク、エンドポイント、IP アドレス等を含みます。

様々なバックエンドをサポートしています。今回のサンプルでは Consul コンテナを使います。

  1. keystore という名称の「マシン」を作成します。

$ docker-machine create -d virtualbox --virtualbox-memory "2000"\--engine-opt="label=com.function=consul" keystore

Engine デーモンにオプションを指定するには --engine-opt フラグを使います。Engine インスタンスをラベル付けするのに使います。

  1. ローカルのシェルを keystore Docker ホストに接続します。

$ eval$(docker-machine env keystore)
  1. consulコンテナ を起動します。

$ docker run --restart=unless-stopped -d -p 8500:8500 -h consul progrium/consul -server -bootstrap

-p フラグはコンテナ上のポート 8500 を公開します。これは Consul サーバがリッスンするためです。また、サーバ上では他のポートも公開します。確認するには dockerps コマンドを使います。

$ docker ps
CONTAINER ID IMAGE ... PORTS NAMES
372ffcbc96ed progrium/consul ... 53/tcp, 53/udp, 8300-8302/tcp, 8400/tcp, 8301-8302/udp, 0.0.0.0:8500->8500/tcp dreamy_ptolemy
  1. curl コマンドを使い、ノードが応答するかテストします。

$ curl $(docker-machine ip keystore):8500/v1/catalog/nodes[{"Node":"consul","Address":"172.17.0.2"}]

タスク2:Swarm マネージャの作成

このステップでは、Swarm マネージャを作成し、 keystore インスタンスに接続します。Swarm マネージャ・コンテナは Swarm クラスタの心臓部です。Docker コマンドを受け取り、クラスタに送り、クラスタ間のスケジューリングをする役割を持ちます。実際のプロダクションへのデプロイでは、高可用性(HA)のためにセカンダリの Swarm レプリカ・マネージャを設定すべきでしょう。

--eng-opt フラグを使い cluster-storecluster-advertise オプションが keystore サーバを参照するようにします。これらのオプションは後にコンテナ・ネットワークの作成時に使います。

  1. manager ホストを作成します。

$ docker-machine create -d virtualbox --virtualbox-memory "2000"\--engine-opt="label=com.function=manager"\--engine-opt="cluster-store=consul://$(docker-machine ip keystore):8500"\--engine-opt="cluster-advertise=eth1:2376" manager

デーモンに対して manager ラベルも指定します。

  1. ローカルのシェルを manager Docker ホストに向けます。

$ eval$(docker-machine env manager)
  1. Swarm マネージャのプロセスを開始します。

$ docker run --restart=unless-stopped -d -p 3376:2375 \-v /var/lib/boot2docker:/certs:ro \swarm manage --tlsverify \--tlscacert=/certs/ca.pem \--tlscert=/certs/server.pem \--tlskey=/certs/server-key.pem \consul://$(docker-machine ip keystore):8500

このコマンドは boot2docker.iso あるいはマネージャ用の TLS 証明書を作成します。これはクラスタ上の他マシンにマネージャが接続する時に使います。

  1. ホスト上で Docker デーモンのログを参照し、正常に動いているか確認します。

$ docker-machine ssh manager
<-- 出力を省略 -->
docker@manager:~$ tail /var/lib/boot2docker/docker.logtime="2016-04-06T23:11:56.481947896Z"level=debug msg="Calling GET /v1.15/version"time="2016-04-06T23:11:56.481984742Z"level=debug msg="GET /v1.15/version"time="2016-04-06T23:12:13.070231761Z"level=debug msg="Watch triggered with 1 nodes"discovery=consultime="2016-04-06T23:12:33.069387215Z"level=debug msg="Watch triggered with 1 nodes"discovery=consultime="2016-04-06T23:12:53.069471308Z"level=debug msg="Watch triggered with 1 nodes"discovery=consultime="2016-04-06T23:13:13.069512320Z"level=debug msg="Watch triggered with 1 nodes"discovery=consultime="2016-04-06T23:13:33.070021418Z"level=debug msg="Watch triggered with 1 nodes"discovery=consultime="2016-04-06T23:13:53.069395005Z"level=debug msg="Watch triggered with 1 nodes"discovery=consultime="2016-04-06T23:14:13.071417551Z"level=debug msg="Watch triggered with 1 nodes"discovery=consultime="2016-04-06T23:14:33.069843647Z"level=debug msg="Watch triggered with 1 nodes"discovery=consul

出力内容から consulmanager が正常に通信できているのが分かります。

  1. Docker ホストから抜けます。

docker@manager:~$ exit

タスク3:ロードバランサの追加

Interlock アプリケーションと Nginx をロードバランサとして使います。ロードバランサ用のホストを作る前に、Nginx で使う設定を作成します。

  1. ローカルホスト上に config ディレクトリを作成します。

  1. config ディレクトリに変更します。

$ cd config
  1. Swarm マネージャ・ホストの IP アドレスを取得します。

例:

$ docker-machine ip manager192.168.99.101
  1. 任意のエディタで config.toml ファイルを作成し、次の内容をファイルに書き込みます。

ListenAddr=":8080"DockerURL="tcp://SWARM_MANAGER_IP:3376"TLSCACert="/var/lib/boot2docker/ca.pem"TLSCert="/var/lib/boot2docker/server.pem"TLSKey="/var/lib/boot2docker/server-key.pem"[[Extensions]]Name="nginx"ConfigPath="/etc/conf/nginx.conf"PidPath="/etc/conf/nginx.pid"MaxConn=1024Port=80
  1. 設定ファイルにおいて、 SWARM_MANAGE_IP は手順3で取得した manager の IP アドレスに書き換えてください。

この値はロードバランサがマネージャのイベント・ストリームを受信するために使います。

  1. config.toml ファイルを保存して閉じます。

  1. ロードバランサ用にマシンを作成します。

$ docker-machine create -d virtualbox --virtualbox-memory "2000"\--engine-opt="label=com.function=interlock" loadbalancer
  1. 環境を loadbalancer に切り替えます。

$ eval$(docker-machine env loadbalancer)
  1. interlock コンテナを起動します。

$ docker run \ -P \ -d \ -ti \ -v nginx:/etc/conf \ -v /var/lib/boot2docker:/var/lib/boot2docker:ro \ -v /var/run/docker.sock:/var/run/docker.sock \ -v $(pwd)/config.toml:/etc/config.toml \ --name interlock \ ehazlett/interlock:1.0.1 \ -D run -c /etc/config.toml

このコマンドは現在のディレクトリにある config.toml ファイルを読み込みます。コマンド実行後、イメージを実行しているのを確認します。

$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d846b801a978 ehazlett/interlock:1.0.1 "/bin/interlock -D ru"2 minutes ago Up 2 minutes 0.0.0.0:32770->8080/tcp interlock

イメージが実行中でなければ、 dockerps-a を実行してシステム上で起動した全てのイメージを表示します。そして、コンテナが起動に失敗していれば、ログを取得できます。

$ docker logs interlock
INFO[0000] interlock 1.0.1 (000291d)DEBU[0000] loading config from: /etc/config.toml
FATA[0000]read /etc/config.toml: is a directory

このエラーであれば、通常は config.toml ファイルがある同じ config ディレクトリ内で dockerrun を実行したのが原因でしょう。コマンドを実行し、次のような衝突が表示する場合があります。

docker: Error response from daemon: Conflict. The name "/interlock" is already in use by container d846b801a978c76979d46a839bb05c26d2ab949ff9f4f740b06b5e2564bae958. You have to remove (or rename) that container to be able to reuse that name.

このような時は、 dockerrminterlock で interlock コンテナを削除し、再度試みてください。

  1. ロードバランサ上で nginx コンテナを起動します。

$ docker run -ti -d \ -p 80:80 \ --label interlock.ext.name=nginx \ --link=interlock:interlock \ -v nginx:/etc/conf \ --name nginx \ nginx nginx -g "daemon off;" -c /etc/conf/nginx.conf

タスク4:他の Swarm ノードを作成

Swarm クラスタのホストを「ノード」と呼びます。既にマネージャ・ノードを作成しました。ここでの作業は、各ノード用の仮想ホストを作成します。3つのコマンドが必要です。

  • Docker Machine でホストを作成

  • ローカル環境から新しい環境に切り替え

  • ホストを Swarm クラスタに追加

Mac あるいは Windows 以外で構築している場合、swarm ノードに追加するには join コマンドを実行するだけです。それだけで Consul ディスカバリ・サービスに登録します。また、ノードの作成時には次の例のようにラベルを付けます。

--engine-opt="label=com.function=frontend01"

これらのラベルはアプリケーション・コンテナを開始した後に使います。以降のコマンドで、各ノードに対してラベルを適用します。

  1. frontend01 ホストを作成し、Swarm クラスタに追加します。

$ docker-machine create -d virtualbox --virtualbox-memory "2000"\--engine-opt="label=com.function=frontend01"\--engine-opt="cluster-store=consul://$(docker-machine ip keystore):8500"\--engine-opt="cluster-advertise=eth1:2376" frontend01
$ eval$(docker-machine env frontend01)$ docker run -d swarm join --addr=$(docker-machine ip frontend01):2376 consul://$(docker-machine ip keystore):8500
  1. frontend02 仮想マシンを作成します。

$ docker-machine create -d virtualbox --virtualbox-memory "2000"\--engine-opt="label=com.function=frontend02"\--engine-opt="cluster-store=consul://$(docker-machine ip keystore):8500"\--engine-opt="cluster-advertise=eth1:2376" frontend02
$ eval$(docker-machine env frontend02)$ docker run -d swarm join --addr=$(docker-machine ip frontend02):2376 consul://$(docker-machine ip keystore):8500
  1. worker01 仮想マシンを作成します。

$ docker-machine create -d virtualbox --virtualbox-memory "2000"\--engine-opt="label=com.function=worker01"\--engine-opt="cluster-store=consul://$(docker-machine ip keystore):8500"\--engine-opt="cluster-advertise=eth1:2376" worker01
$ eval$(docker-machine env worker01)$ docker run -d swarm join --addr=$(docker-machine ip worker01):2376 consul://$(docker-machine ip keystore):8500
  1. dbstore 仮想マシンを作成します。

$ docker-machine create -d virtualbox --virtualbox-memory "2000"\--engine-opt="label=com.function=dbstore"\--engine-opt="cluster-store=consul://$(docker-machine ip keystore):8500"\--engine-opt="cluster-advertise=eth1:2376" dbstore
$ eval$(docker-machine env dbstore)$ docker run -d swarm join --addr=$(docker-machine ip dbstore):2376 consul://$(docker-machine ip keystore):8500
  1. 動作確認をします。

この時点では、アプリケーションが必要なインフラをデプロイ完了しました。テストは、次のようにマシンが実行しているか一覧表示します。

$ docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
dbstore - virtualbox Running tcp://192.168.99.111:2376 v1.10.3
frontend01 - virtualbox Running tcp://192.168.99.108:2376 v1.10.3
frontend02 - virtualbox Running tcp://192.168.99.109:2376 v1.10.3
keystore - virtualbox Running tcp://192.168.99.100:2376 v1.10.3
loadbalancer - virtualbox Running tcp://192.168.99.107:2376 v1.10.3
manager - virtualbox Running tcp://192.168.99.101:2376 v1.10.3
worker01 * virtualbox Running tcp://192.168.99.110:2376 v1.10.3
  1. Swarm マネージャが全てのノードを一覧表示するのを確認します。

$ docker -H $(docker-machine ip manager):3376 info
Containers: 4 Running: 4 Paused: 0 Stopped: 0Images: 3Server Version: swarm/1.1.3
Role: primary
Strategy: spread
Filters: health, port, dependency, affinity, constraint
Nodes: 4 dbstore: 192.168.99.111:2376 └ Status: Healthy └ Containers: 1 └ Reserved CPUs: 0 / 1 └ Reserved Memory: 0 B / 2.004 GiB └ Labels: com.function=dbstore, executiondriver=native-0.2, kernelversion=4.1.19-boot2docker, operatingsystem=Boot2Docker 1.10.3 (TCL 6.4.1); master : 625117e - Thu Mar 1022:09:02 UTC 2016, provider=virtualbox, storagedriver=aufs └ Error: (none) └ UpdatedAt: 2016-04-07T18:25:37Z frontend01: 192.168.99.108:2376 └ Status: Healthy └ Containers: 1 └ Reserved CPUs: 0 / 1 └ Reserved Memory: 0 B / 2.004 GiB └ Labels: com.function=frontend01, executiondriver=native-0.2, kernelversion=4.1.19-boot2docker, operatingsystem=Boot2Docker 1.10.3 (TCL 6.4.1); master : 625117e - Thu Mar 1022:09:02 UTC 2016, provider=virtualbox, storagedriver=aufs └ Error: (none) └ UpdatedAt: 2016-04-07T18:26:10Z frontend02: 192.168.99.109:2376 └ Status: Healthy └ Containers: 1 └ Reserved CPUs: 0 / 1 └ Reserved Memory: 0 B / 2.004 GiB └ Labels: com.function=frontend02, executiondriver=native-0.2, kernelversion=4.1.19-boot2docker, operatingsystem=Boot2Docker 1.10.3 (TCL 6.4.1); master : 625117e - Thu Mar 1022:09:02 UTC 2016, provider=virtualbox, storagedriver=aufs └ Error: (none) └ UpdatedAt: 2016-04-07T18:25:43Z worker01: 192.168.99.110:2376 └ Status: Healthy └ Containers: 1 └ Reserved CPUs: 0 / 1 └ Reserved Memory: 0 B / 2.004 GiB └ Labels: com.function=worker01, executiondriver=native-0.2, kernelversion=4.1.19-boot2docker, operatingsystem=Boot2Docker 1.10.3 (TCL 6.4.1); master : 625117e - Thu Mar 1022:09:02 UTC 2016, provider=virtualbox, storagedriver=aufs └ Error: (none) └ UpdatedAt: 2016-04-07T18:25:56Z
Plugins: Volume: Network:
Kernel Version: 4.1.19-boot2docker
Operating System: linux
Architecture: amd64
CPUs: 4Total Memory: 8.017 GiB
Name: bb13b7cf80e8

このコマンドは Swarm ポートに対して処理しているため、クラスタ全体の情報を返します。操作対象Swarm マネージャあり、ノードではありません。

次のステップ

キーストア、ロードバランサ、Swarm クラスタのインフラが動きました。これで 投票アプリケーションの構築と実行 ができます。