以前、下記のPostをしていて、この時は一つのホストに複数のコンテナをDocker Composeを用いて構築していました。
ELK(ElasticSearch, Logstash, Kibana)+fluentdの環境をDocker Composeで構築しつつ、試しにCloudWatchの統計データを収集してみた
このときのdockerの--linkオプションでは、別のホストマシン上に起動してあるコンテナのhosts情報を渡せなかったのですが、
Docker Engine 1.9で追加されたマルチホストネットワーキングを使えば、複数ホスト間でネットワークを共有し、--linkで渡した名前を元にしたアクセスが可能になるかと思い試してみました。
→ --linkオプションはマルチホストネットワーキングではサポートされていませんでした。
また、将来的にDockerから削除されるそうです。
マルチホストネットワーキングではコンテナ名でIPが引けるので、
下ではこれを使うように変更しています。
前回と同様にDocker Composeを用いて複数ホスト(上の図でいうnode1とnode2)にまたがってコンテナを構築するのが目標なので、そのために下ではDocker Swarmも使いました。
(SwarmのmasterノードにComposeを実行して、複数のノードにコンテナを起動させるようにしています)
環境
今回試した環境と、ツール類のバージョンは下記のとおりです。
環境 | バージョンなど |
---|---|
OS | EI Capitan(10.11.3) |
Docker Engine | 1.9.1 |
Docker Machine | 0.5.6 |
Docker Compose | 1.5.2 |
Docker Toolboxのインストール
マルチホストネットワーキングを行うにはDocker Engine, VirtualBoxを使用するため、それらをインストールする必要があります。
私はDocker Engine, Compose, Swarm, Machine, ViratualBox +αをまとめてインストールできるDocker Toolboxをインストールしました。
Macでhomebrewを使っているなら下記でインストール。
$ brew cask install dockertoolbox
インストーラーをダウンロードして、インストールする場合は、下記から。
https://www.docker.com/docker-toolbox
Key-Valueストア(KVS)の準備
ホストオンリーネットワークの構築にはノードからアクセスできるところにKVSのサービスを立てておく必要があります。
このKVSにはネットワークのステータス(discovery, networks, endpoints, IP addresses等)を登録するとのこと。
マルチホストネットワーキングでサポートしているKVSはConsul, Etcd, ZooKeeperとのこと。
ここではサンプルに習ってConsulを用いました。
Docker Machineを使って構築したVMにてConsulを動作させます。
VMの作成
$ docker-machine create -d virtualbox mh-keystore
Running pre-create checks...
Creating machine...
(mh-keystore) Copying /Users/[user]/.docker/machine/cache/boot2docker.iso to /Users/[user]/.docker/machine/machines/mh-keystore/boot2docker.iso...
(mh-keystore) Creating VirtualBox VM...
(mh-keystore) Creating SSH key...
(mh-keystore) Starting the VM...
(mh-keystore) Waiting for an IP...
Waiting for machine to be running, this may take a few minutes...
Machine is running, waiting for SSH to be available...
Detecting operating system of created instance...
Detecting the provisioner...
Provisioning with boot2docker...
Copying certs to the local machine directory...
Copying certs to the remote machine...
Setting Docker configuration on the remote daemon...
Checking connection to Docker...
Docker is up and running!
To see how to connect Docker to this machine, run: docker-machine env mh-keystore
VM上でConsulサービスを起動
コンテナを実行してホストと8500/tcpポートをポートマッピングします。
$ docker $(docker-machine config mh-keystore) run -d \
-p "8500:8500" \
-h "consul" \
progrium/consul -server -bootstrap
Unable to find image 'progrium/consul:latest' locally
latest: Pulling from progrium/consul
3b4d28ce80e4: Pull complete
e5ab901dcf2d: Pull complete
30ad296c0ea0: Pull complete
3dba40dec256: Pull complete
f2ef4387b95e: Pull complete
53bc8dcc4791: Pull complete
75ed0b50ba1d: Pull complete
17c3a7ed5521: Pull complete
8aca9e0ecf68: Pull complete
4d1828359d36: Pull complete
46ed7df7f742: Pull complete
b5e8ce623ef8: Pull complete
049dca6ef253: Pull complete
bdb608bc4555: Pull complete
8b3d489cfb73: Pull complete
c74500bbce24: Pull complete
9f3e605442f6: Pull complete
d9125e9e799b: Pull complete
Digest: sha256:8cc8023462905929df9a79ff67ee435a36848ce7a10f18d6d0faba9306b97274
Status: Downloaded newer image for progrium/consul:latest
957db0c166612c435d5379da0f1c325ab028d2d02c7fe01d77d503526a5c8755
docker psでConsulが立ち上がっていることを確認
Dockerのクライアントの向け先を作成したVMに向けます。
$ eval "$(docker-machine env mh-keystore)"
下記で確認します。起動していれば下記のように表示されます。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
957db0c16661 progrium/consul "/bin/start -server -" 2 minutes ago Up 2 minutes 53/tcp, 53/udp, 8300-8302/tcp, 0.0.0.0:8500->8500/tcp, 8301-8302/udp, 8400/tcp big_cray
Consul自体は下記からダウンロードできるので、コンテナを使わなくてもホストマシンでそれを実行できます。
https://www.consul.io/
ここはサンプル通りコンテナを利用して構築してみました。コンテナで実行するのはとても楽でした。
コンテナを起動するための複数のノードを起動
今回、Docker Composeで複数ノードにまたがってコンテナを起動したいので、Docker Swarmを使ってクラスタを構築しました。
ホストオンリーネットワークを使うだけならSwarmのクラスタは必須ではありません。
Docker Machineも必須ではありません。
Swarm masterの作成
まずクラスタのmasterになるノードを作成します。
$ docker-machine create \
-d virtualbox \
--swarm --swarm-master \
--swarm-discovery="consul://$(docker-machine ip mh-keystore):8500" \
--engine-opt="cluster-store=consul://$(docker-machine ip mh-keystore):8500" \
--engine-opt="cluster-advertise=eth1:2376" \
node1
Running pre-create checks...
Creating machine...
(node1) Copying /Users/[user]/.docker/machine/cache/boot2docker.iso to /Users/[user]/.docker/machine/machines/node1/boot2docker.iso...
(node1) Creating VirtualBox VM...
(node1) Creating SSH key...
(node1) Starting the VM...
(node1) Waiting for an IP...
Waiting for machine to be running, this may take a few minutes...
Machine is running, waiting for SSH to be available...
Detecting operating system of created instance...
Detecting the provisioner...
Provisioning with boot2docker...
Copying certs to the local machine directory...
Copying certs to the remote machine...
Setting Docker configuration on the remote daemon...
Configuring swarm...
Checking connection to Docker...
Docker is up and running!
To see how to connect Docker to this machine, run: docker-machine env node1
Docker Machineを使わずにマルチホストネットワーキングを利用するには、VM上でDocker Engineのデーモンを起動する際に、下記のオプションを設定すればよい、ということですね。
- --cluster-store
- --cluster-advertise
Docker Machineで起動したVM上ではデーモン起動のコマンドは下記のようになっていました。
/usr/local/bin/docker daemon -D -g /var/lib/docker \
-H unix:// -H tcp://0.0.0.0:2376 --label provider=virtualbox \
--cluster-store=consul://192.168.99.100:8500 \
--cluster-advertise=eth1:2376 --tlsverify \
--tlscacert=/var/lib/boot2docker/ca.pem \
--tlscert=/var/lib/boot2docker/server.pem \
--tlskey=/var/lib/boot2docker/server-key.pem -s aufs
Swarm clusterの作成
続いてクラスタノードを追加します。
$ docker-machine create -d virtualbox \
--swarm \
--swarm-discovery="consul://$(docker-machine ip mh-keystore):8500" \
--engine-opt="cluster-store=consul://$(docker-machine ip mh-keystore):8500" \
--engine-opt="cluster-advertise=eth1:2376" \
node2
Running pre-create checks...
Creating machine...
(node2) Copying /Users/[user]/.docker/machine/cache/boot2docker.iso to /Users/[user]/.docker/machine/machines/node2/boot2docker.iso...
(node2) Creating VirtualBox VM...
(node2) Creating SSH key...
(node2) Starting the VM...
(node2) Waiting for an IP...
Waiting for machine to be running, this may take a few minutes...
Machine is running, waiting for SSH to be available...
Detecting operating system of created instance...
Detecting the provisioner...
Provisioning with boot2docker...
Copying certs to the local machine directory...
Copying certs to the remote machine...
Setting Docker configuration on the remote daemon...
Configuring swarm...
Checking connection to Docker...
Docker is up and running!
To see how to connect Docker to this machine, run: docker-machine env node2
構築内容の確認
ここまでで下記のように、3つ作成されていればOKです。
$ docker-machine ls
NAME ACTIVE URL STATE URL SWARM DOCKER ERRORS
mh-keystore * virtualbox Running tcp://192.168.99.100:2376 v1.9.1
node1 - virtualbox Running tcp://192.168.99.101:2376 node1 (master) v1.9.1
node2 - virtualbox Running tcp://192.168.99.102:2376 node1 v1.9.1
次に、masterノードからSwarmクラスタのノード情報を確認してみます。
Dockerクライアントの実行をmasterノードに向けます。
$ eval $(docker-machine env --swarm node1)
確認してみます。
$ docker info
Containers: 3
Images: 2
Role: primary
Strategy: spread
Filters: health, port, dependency, affinity, constraint
Nodes: 2
node1: 192.168.99.101:2376
└ Status: Healthy
└ Containers: 2
└ Reserved CPUs: 0 / 1
└ Reserved Memory: 0 B / 1.021 GiB
└ Labels: executiondriver=native-0.2, kernelversion=4.1.13-boot2docker, operatingsystem=Boot2Docker 1.9.1 (TCL 6.4.1); master : cef800b - Fri Nov 20 19:33:59 UTC 2015, provider=virtualbox, storagedriver=aufs
node2: 192.168.99.102:2376
└ Status: Healthy
└ Containers: 1
└ Reserved CPUs: 0 / 1
└ Reserved Memory: 0 B / 1.021 GiB
└ Labels: executiondriver=native-0.2, kernelversion=4.1.13-boot2docker, operatingsystem=Boot2Docker 1.9.1 (TCL 6.4.1); master : cef800b - Fri Nov 20 19:33:59 UTC 2015, provider=virtualbox, storagedriver=aufs
CPUs: 2
Total Memory: 2.043 GiB
Name: node1
マルチホストネットワーキングを構築します
下記、コマンドでmy-netというネットワークを作成します。
$ docker network create --driver overlay my-net
ca21981bd1e31ec3d7d40336edffdddc49d318492f6248323fb038b6307b3d32
作成されたことを確認します。
$ docker network ls
NETWORK ID NAME DRIVER
a6c941a4d77e node2/bridge bridge
722e0e348884 node2/none null
3260beae2418 node2/host host
e90de0c47ecb node1/none null
4b5140f289f8 node1/host host
ad297effc7c5 node1/bridge bridge
ca21981bd1e3 my-net overlay
my-netというネットワークがoverlayというDRIVERで作成されていれば成功です。
Docker Composeをもちいて構築
準備が整ったので、Docker Composeで構築してみます。
ELK(ElasticSearch, Logstash, Kibana)+fluentdの環境をDocker Composeで構築しつつ、試しにCloudWatchの統計データを収集してみたのdocker-compose.ymlを下記のように変更しました。
環境変数のconstraint:nodeでノード名を指定すると、指定したノードにコンテナを起動してくれます。(ここはSwarmの機能)
linksオプションはサポートされていないので、コンテナ名を環境変数で渡すように変更しています。(コンテナ名でマルチホストネットワーキングのIPが引けます。)
# elasticsearch
elasticsearch:
image: khiraiwa/docker-elasticsearch:1.0.0
environment:
- "constraint:node==node1"
volumes:
- /data_elasticsearch:/data_elasticsearch
ports:
- "9200:9200"
- "9300:9300"
# kibana
kibana:
image: khiraiwa/docker-kibana:1.1.0
environment:
- "constraint:node==node2"
- "ELASTICSEARCH_HOST=elk_elasticsearch_1"
volumes:
- /data_kibana:/data_kibana
ports:
- "5601:5601"
# logstash
logstash:
image: khiraiwa/docker-logstash:1.1.0
environment:
- "constraint:node==node2"
- "ELASTICSEARCH_HOST=elk_elasticsearch_1"
volumes:
- /data_logstash:/data_logstash
environment:
- AWS_ACCESS_KEY_ID=dummy
- AWS_SECRET_ACCESS_KEY=dummy
# tdagent
tdagent:
image: khiraiwa/docker-tdagent:1.1.0
environment:
- "constraint:node==node2"
- "ELASTICSEARCH_HOST=elk_elasticsearch_1"
volumes:
- /data_tdagent:/etc/td-agent
environment:
- AWS_ACCESS_KEY_ID=dummy
- AWS_SECRET_ACCESS_KEY=dummy
実行前にmasterに向けます。
$ eval $(docker-machine env --swarm node1)
masterに対してdocker-composeでコンテナを構築します。
マルチホストネットワーキングを使用するときは--x-networkingのオプションが必要です。
$ docker-compose --x-networking --project-name=elk up -d
Creating elk_tdagent_1
Creating elk_elasticsearch_1
Pulling logstash (khiraiwa/docker-logstash:1.1.0)...
node2: Pulling khiraiwa/docker-logstash:1.1.0... : downloaded
node1: Pulling khiraiwa/docker-logstash:1.1.0... : downloaded
Creating elk_logstash_1
Pulling kibana (khiraiwa/docker-kibana:1.1.0)...
node2: Pulling khiraiwa/docker-kibana:1.1.0... : downloaded
node1: Pulling khiraiwa/docker-kibana:1.1.0... : downloaded
Creating elk_kibana_1
docker psコマンドを実行した結果です。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b08e6bd64157 khiraiwa/docker-kibana:1.1.0 "/bin/sh -c 'sed -i -" 15 seconds ago Up 14 seconds 192.168.99.102:5601->5601/tcp node2/elk_kibana_1
d679cc7a97d6 khiraiwa/docker-logstash:1.1.0 "/bin/sh -c 'sudo cho" 2 minutes ago Up 2 minutes node2/elk_logstash_1
eed341792147 khiraiwa/docker-elasticsearch:1.0.0 "/bin/sh -c 'sudo cho" 4 minutes ago Up 4 minutes 192.168.99.101:9200->9200/tcp, 192.168.99.101:9300->9300/tcp node1/elk_elasticsearch_1
2288e18e3fef khiraiwa/docker-tdagent:1.1.0 "/bin/sh -c 'if [ ! -" 4 minutes ago Up 4 minutes 5170/tcp, 9880/tcp, 5160/udp, 24224/udp, 24224/tcp node2/elk_tdagent_1
これにて、node1, node2にまたがってコンテナが起動してマルチホストネットワークも構築されたことになります。
下記、node2のelk_kibana_1コンテナにログインして、ネットワークインタフェースをチェックしてみたものです。
eth0がマルチホストネットワーキングで使用しているmy-netに属しています。
$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
30: eth0@if31: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default
link/ether 02:42:0a:00:02:05 brd ff:ff:ff:ff:ff:ff
inet 10.0.2.5/24 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::42:aff:fe00:205/64 scope link
valid_lft forever preferred_lft forever
32: eth1@if33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:12:00:04 brd ff:ff:ff:ff:ff:ff
inet 172.18.0.4/16 scope global eth1
valid_lft forever preferred_lft forever
inet6 fe80::42:acff:fe12:4/64 scope link
valid_lft forever preferred_lft forever
試しに、別ノード(node1)のElasticSearchに対して、コンテナ名を指定してpingを打ってみると応答が返ってきました。
同じネットワークに属していて、コンテナ名でIPが引けていることがわかります。
$ ping elk_elasticsearch_1
PING elk_elasticsearch_1 (10.0.2.3) 56(84) bytes of data.
64 bytes from elk_elasticsearch_1 (10.0.2.3): icmp_seq=1 ttl=64 time=0.819 ms
64 bytes from elk_elasticsearch_1 (10.0.2.3): icmp_seq=2 ttl=64 time=0.742 ms
64 bytes from elk_elasticsearch_1 (10.0.2.3): icmp_seq=3 ttl=64 time=0.790 ms
64 bytes from elk_elasticsearch_1 (10.0.2.3): icmp_seq=4 ttl=64 time=0.693 ms
/etc/hostsを見てみると、下記のようにコンテナ名で名前解決できるように設定されていることがわかります。
$ cat /etc/hosts
10.0.2.5 b08e6bd64157
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
10.0.2.4 elk_logstash_1.elk
10.0.2.2 elk_tdagent_1
10.0.2.2 elk_tdagent_1.elk
10.0.2.3 elk_elasticsearch_1
10.0.2.3 elk_elasticsearch_1.elk
10.0.2.4 elk_logstash_1
Kibanaを表示する
下記で、Kibanaが起動しているノードのIPを取得します。
$ docker-machine ip node2
192.168.99.101
下記のコマンドでKibanaの起動しているノードにポートマッピングします。
(sshのデフォルトパスワードはtcuserになります。)
$ ssh docker@$(docker-machine ip node2) -L 5601:localhost:5601
ブラウザで、
http://localhost:5601/
にアクセスするとKibanaが表示されます。