インフラのデプロイ¶
このステップでは、複数の 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-machine env keystore)
を実際の値に置き換えてください。
タスク1:keystore (キーストア)サーバの作成¶
Docker コンテナ・ネットワークと Swarm ディスカバリを有効化するために、キーバリュー・ストアのデプロイが必要です。キーストアはディスカバリ・バックエンドとして、Swarm マネージャが使うクラスタのメンバ一覧を常に更新し続けます。Swarm マネージャはこの一覧を使い、ノードにタスクを割り当てます。
オーバレイ・ネットワークはキーバリュー・ストアが必要です。キーバリュー・ストアはネットワーク状態を保持するために使います。ネットワーク状態には、ディスカバリ、ネットワーク、エンドポイント、IP アドレス等を含みます。
様々なバックエンドをサポートしています。今回のサンプルでは Consul コンテナを使います。
keystore
という名称の「マシン」を作成します。
$ docker-machine create -d virtualbox --virtualbox-memory "2000" \
--engine-opt="label=com.function=consul" keystore
Engine デーモンにオプションを指定するには --engine-opt
フラグを使います。Engine インスタンスをラベル付けするのに使います。
- ローカルのシェルを
keystore
Docker ホストに接続します。
$ eval $(docker-machine env keystore)
consul
コンテナ を起動します。
$ docker run --restart=unless-stopped -d -p 8500:8500 -h consul progrium/consul -server -bootstrap
-p
フラグはコンテナ上のポート 8500 を公開します。これは Consul サーバがリッスンするためです。また、サーバ上では他のポートも公開します。確認するには docker ps
コマンドを使います。
$ 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
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-store
と cluster-advertise
オプションが keystore
サーバを参照するようにします。これらのオプションは後にコンテナ・ネットワークの作成時に使います。
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
ラベルも指定します。
- ローカルのシェルを
manager
Docker ホストに向けます。
$ eval $(docker-machine env manager)
- 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 証明書を作成します。これはクラスタ上の他マシンにマネージャが接続する時に使います。
- ホスト上で Docker デーモンのログを参照し、正常に動いているか確認します。
$ docker-machine ssh manager
<-- 出力を省略 -->
docker@manager:~$ tail /var/lib/boot2docker/docker.log
time="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=consul
time="2016-04-06T23:12:33.069387215Z" level=debug msg="Watch triggered with 1 nodes" discovery=consul
time="2016-04-06T23:12:53.069471308Z" level=debug msg="Watch triggered with 1 nodes" discovery=consul
time="2016-04-06T23:13:13.069512320Z" level=debug msg="Watch triggered with 1 nodes" discovery=consul
time="2016-04-06T23:13:33.070021418Z" level=debug msg="Watch triggered with 1 nodes" discovery=consul
time="2016-04-06T23:13:53.069395005Z" level=debug msg="Watch triggered with 1 nodes" discovery=consul
time="2016-04-06T23:14:13.071417551Z" level=debug msg="Watch triggered with 1 nodes" discovery=consul
time="2016-04-06T23:14:33.069843647Z" level=debug msg="Watch triggered with 1 nodes" discovery=consul
出力内容から consul
と manager
が正常に通信できているのが分かります。
- Docker ホストから抜けます。
docker@manager:~$ exit
タスク3:ロードバランサの追加¶
Interlock アプリケーションと Nginx をロードバランサとして使います。ロードバランサ用のホストを作る前に、Nginx で使う設定を作成します。
- ローカルホスト上に
config
ディレクトリを作成します。
config
ディレクトリに変更します。
$ cd config
- Swarm マネージャ・ホストの IP アドレスを取得します。
例:
$ docker-machine ip manager
192.168.99.101
- 任意のエディタで
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 = 1024
Port = 80
- 設定ファイルにおいて、
SWARM_MANAGE_IP
は手順3で取得したmanager
の IP アドレスに書き換えてください。
この値はロードバランサがマネージャのイベント・ストリームを受信するために使います。
config.toml
ファイルを保存して閉じます。
- ロードバランサ用にマシンを作成します。
$ docker-machine create -d virtualbox --virtualbox-memory "2000" \
--engine-opt="label=com.function=interlock" loadbalancer
- 環境を
loadbalancer
に切り替えます。
$ eval $(docker-machine env loadbalancer)
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
イメージが実行中でなければ、 docker ps -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
ディレクトリ内で docker run
を実行したのが原因でしょう。コマンドを実行し、次のような衝突が表示する場合があります。
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.
このような時は、 docker rm interlock
で interlock コンテナを削除し、再度試みてください。
- ロードバランサ上で
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"
これらのラベルはアプリケーション・コンテナを開始した後に使います。以降のコマンドで、各ノードに対してラベルを適用します。
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
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
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
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
- 動作確認をします。
この時点では、アプリケーションが必要なインフラをデプロイ完了しました。テストは、次のようにマシンが実行しているか一覧表示します。
$ 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
- Swarm マネージャが全てのノードを一覧表示するのを確認します。
$ docker -H $(docker-machine ip manager):3376 info
Containers: 4
Running: 4
Paused: 0
Stopped: 0
Images: 3
Server 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 10 22: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 10 22: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 10 22: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 10 22: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: 4
Total Memory: 8.017 GiB
Name: bb13b7cf80e8
このコマンドは Swarm ポートに対して処理しているため、クラスタ全体の情報を返します。操作対象Swarm マネージャあり、ノードではありません。
次のステップ¶
キーストア、ロードバランサ、Swarm クラスタのインフラが動きました。これで 投票アプリケーションの構築と実行 ができます。
参考
- Deploy your infrastructure
- https://docs.docker.com/swarm/swarm_at_scale/deploy-infra/