概要
Docker 1.9 からマルチホスト・ネットワーク機能が利用可能となった。動作検証として、DigitalOcean の環境上に、Docker Machine で Swarm クラスタを作り、オーバレイ・ネットワーク上を作成。最終的に、複数ホスト上にウェブとデータベースを分散した WordPress の環境を作成する。ここでは Docker Compose を使用し、オーバレイ・ネットワークの自動構築も試みる。
Docker 1.9 のネットワーク機能については、以下 URL を参照のこと。
- 【参考訳】 Docker 1.9 発表:Swarm とマルチホスト・ネットワーキングのプロダクション対応
- 【参考訳】 プロダクションに対応するマルチホスト Docker ネットワーク機能
- 参考訳:マルチホスト・ネットワーキングを始めよう - Qiita
- 参考訳:Docker コンテナ・ネットワークの理解 - Qiita
前提条件と環境について
- Docker 1.9~
- Linux Kernel 3.16~
- DigitalOcean
DockerのドキュメントはVirtualBox上だったが、実際に近い環境で試したかったので、DigitalOcean上に先の図のような環境構築を試みる。検証として、WordPressのweb
とdb
コンテナを、複数のホスト上でありながら、同一のネットワーク上に配置する。
※偶然にも眼前の環境が DigitalOcean だっただけで、他の環境でも、同様に動くはず。
環境構築手順
3台のサーバ(KVS、Swarmマスタ、Swarmノード)を準備する。
KVS ( Consul ) 用マシンの作成
クラスタ全体の制御は Docker Swarm を通して行う。そのため、Docker Swarm クラスタが使用する KVS として Consul 用の環境を Docker Machine で作成する。
事前に DigitalOcean の API トークンを取得し、環境変数として定義する。
$ DO_TOKEN=3f0f0xxxxf65f
次に Docker Machine でマシン swarm-kvs
を作成する。
$ docker-machine create \
--driver digitalocean \
--digitalocean-access-token $DO_TOKEN \
--digitalocean-region sgp1 \
swarm-kvs
正常に作成できると、docker-machine ls
コマンドで次のように表示されている。
$ docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM
swarm-kvs - digitalocean Running tcp://188.166.225.62:2376
それから、作成したマシン内に consul
をサーバ・モードで実行する。
$ docker $(docker-machine config swarm-kvs) run -d \
-p "8500:8500" \
-h "consul" \
progrium/consul -server -bootstrap
Swarm マスタ用マシンの作成
Docker Machine を使い、swarm-node0
マシンの作成と、Swarm マスタ用(クラスタ管理)の自動構築も行う。
docker-machine create \
--driver digitalocean \
--digitalocean-access-token $DO_TOKEN \
--digitalocean-region sgp1 \
--swarm \
--swarm-image="swarm:1.0.0" \
--swarm-master \
--swarm-discovery="consul://$(docker-machine ip swarm-kvs):8500" \
--engine-opt="cluster-store=consul://$(docker-machine ip swarm-kvs):8500" \
--engine-opt="cluster-advertise=eth0:2376" \
swarm-node0
正常に実行されると、docker-machine ls
では次のように2台のマシンが表示される。
$ docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM
swarm-kvs - digitalocean Running tcp://188.166.225.62:2376
swarm-node0 - digitalocean Running tcp://188.166.225.83:2376 swarm-node0 (master)
次に、DigitalOcean の Ubuntu 14.04 LTS3 は Kernel バージョンが古く、オーバレイ・ネットワーク機能が利用出来ない。そのため、サーバにログインし、手動で Kernel のバージョンアップを行う。
- DigitalOcean の GUI にアクセス
-
Dropets
から対象のドロップレット(サーバ) をクリック -
Settings
->Kernel
->Ubuntu 14.10 x64 vmlinuz-3.16.0-41-generic
を選択し、Change
をクリック -
docker-machine ssh swarm-node0
でこの環境に SSH ログイン -
/sbin/poweroff
コマンドでインスタンスを停止(rebootでは反映されない) - GUI からドロップレットの情報を開き、
Power On
- 再度
docker-machine ssh swarm-node0
でこの環境に SSH ログイン - kernel が更新された事を確認
root@swarm-node0:~# uname -a
Linux swarm-node0 3.16.0-41-generic #57-Ubuntu SMP Thu Jun 18 08:44:16 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
9. apt-get install -y -q linux-image-extra-3.16.0-41-generic
を実行
10. /sbin/reboot
で再起動
動作確認は、docker クライアントの環境変数を切り替えて行う。環境変数を指定すると、docker
コマンドはローカルではなく、ここで指定したリモート環境に対する操作を行う。単なる Docker デーモンのポートだけでなく、Swarm のポートを指定すると、クラスタ全体を操作できる。
$ eval $(docker-machine env --swarm swarm-node0)
docker ps
や docker info
の情報が、Docker デーモンの情報ではなく、クラスタに関する情報に切り替わっていることを確認する。
Swarm ノード用マシンの作成
swarm-node1
という名称のマシンを作成する。
docker-machine create \
--driver digitalocean \
--digitalocean-access-token $DO_TOKEN \
--digitalocean-region sgp1 \
--swarm \
--swarm-image="swarm:1.0.0" \
--swarm-discovery="consul://$(docker-machine ip swarm-kvs):8500" \
--engine-opt="cluster-store=consul://$(docker-machine ip swarm-kvs):8500" \
--engine-opt="cluster-advertise=eth0:2376" \
swarm-node1
作成後は先ほど同様、kernel のバージョンアップ作業を行う。
この時点で3台の環境が準備できた。
$ docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM
swarm-kvs - digitalocean Running tcp://188.166.225.62:2376
swarm-node0 * digitalocean Running tcp://188.166.225.83:2376 swarm-node0 (master)
swarm-node1 - digitalocean Running tcp://128.199.242.128:2376 swarm-node0
動作確認は docker info
コマンド実行時、リソース情報で2台分(Swarm マスタとノード)表示されていることを確認。
$ eval $(docker-machine env --swarm swarm-node0)
$ docker info
Containers: 3
Images: 2
Role: primary
Strategy: spread
Filters: health, port, dependency, affinity, constraint
Nodes: 2
swarm-node0: 188.166.225.83:2376
m Containers: 2
m Reserved CPUs: 0 / 1
m Reserved Memory: 0 B / 514 MiB
m Labels: executiondriver=native-0.2, kernelversion=3.16.0-41-generic, operatingsystem=Ubuntu 14.04.3 LTS, provider=digitalocean, storagedriver=aufs
swarm-node1: 128.199.242.128:2376
m Containers: 1
m Reserved CPUs: 0 / 1
m Reserved Memory: 0 B / 514.5 MiB
m Labels: executiondriver=native-0.2, kernelversion=3.13.0-57-generic, operatingsystem=Ubuntu 14.04.3 LTS, provider=digitalocean, storagedriver=aufs
CPUs: 2
Total Memory: 1.004 GiB
Name: 6bbe5d40c009
オーバレイ・ネットワークの作成
以降の作業では、Swarm クラスタに対する操作を行う。常に、次の環境変数の定義されているものとする。
$ eval $(docker-machine env --swarm swarm-node0)
ネットワーク情報を見るには、docker network ls
コマンドを実行する。次のように swarm-node1
と swam-node0
の各ホスト上に host
や bridge
という Docker 標準ネットワーク情報を確認できる。これは各ホスト毎に存在している。そして、別々のネットワーク ID を持つ。
$ docker network ls
NETWORK ID NAME DRIVER
392db5e3bd70 swarm-node1/host host
9d23b56deb9f swarm-node0/bridge bridge
5ab9066e5c50 swarm-node0/none null
bb18b404a6c6 swarm-node0/host host
dd8fc71c6bbc swarm-node1/bridge bridge
a747d9e4ef62 swarm-node1/none null
オーバレイ・ネットワークは、ホスト毎にまたがるネットワークであり、ネットワーク ID も共通している。手動で internal
という名称のネットワークを作成するには、次のように実行する。
$ docker network create internal
1b2b66f54a72b83d5151bad8af84ac7244a3cc74a18151fbaeaf4bf4ff92b8de
再び docker network ls
を実行すると、所属するホスト名がない DRIVER
が overlay
のネットワークが作成できる。
$ docker network ls
NETWORK ID NAME DRIVER
bb18b404a6c6 swarm-node0/host host
1b2b66f54a72 internal overlay
9d23b56deb9f swarm-node0/bridge bridge
dd8fc71c6bbc swarm-node1/bridge bridge
a747d9e4ef62 swarm-node1/none null
392db5e3bd70 swarm-node1/host host
5ab9066e5c50 swarm-node0/none null
nginx コンテナを手動で作成して、挙動の確認
この時点で docker ps
を実行しても、Swarm クラスタ上にはコンテナが作成していないため、次のように実行中のコンテナはなにも表示されない(実際には各ホスト上で swarm 用のコンテナが実行中だが、Swarm を通すと表示されない)
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
Swarm クラスタで、web という名称の nginx コンテナを起動する。constraint
フィルタを指定し、起動するホストをswarm-node0
と指定している(指定しない場合は、ノードのいずれかがランダムに選択される。あるいは Swarm のステラテジに依存する。フィルタやストラテジの詳細は Docker Swarm 入門を参照のこと)。
$ docker run -d --name=web --net=internal --env="constraint:node==swarm-node0" nginx
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6473ca45464d nginx "nginx -g 'daemon off" 25 seconds ago Up 23 seconds 80/tcp, 443/tcp swarm-node0/web
この状態で、もう1つのホスト swarm-node1
を指定して busybox コンテナを起動し、疎通を確認する。
$ docker run -it --net=internal --env="constraint:node==swarm-node1" busybox
シェルが表示され、コンテナ内で操作が可能になる。/etc/hosts
を見ると、自動的に先ほど作成されたホスト名と IP アドレスが自動的に追加されているのが分かる。
/ # cat /etc/hosts
10.0.0.3 5656bd4c2072
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.0.2 web
10.0.0.2 web.internal
※ネットワークは docker network connect xxx
で接続、docker network disconnect xxx
で、任意のコンテナに対し、任意のネットワークの追加・削除が動的に可能。設定を適用した瞬間、コンテナ内のインターフェースと /etc/hosts エントリに追加・削除される。
この状態で web
という名称で名前確認が可能なため、次のように ping
の疎通確認や wget
によるコンテンツ取得がオーバレイ・ネットワークを通して可能となる。この2つのコンテナは別々のホスト上に存在しているが、オーバレイ・ネットワーク機能のおかげで、同一のネットワーク上に存在しているように見えるため。
/ # ping web
PING web (10.0.0.2): 56 data bytes
64 bytes from 10.0.0.2: seq=0 ttl=64 time=0.680 ms
64 bytes from 10.0.0.2: seq=1 ttl=64 time=0.600 ms
64 bytes from 10.0.0.2: seq=2 ttl=64 time=0.731 ms
^C
--- web ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.600/0.670/0.731 ms
/ # wget -O - http://web
Connecting to web (10.0.0.2:80)
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
(省略)
Docker Compose で WordPress を分散実行
従来の Docker Compose は1つのホスト上でのみ複数コンテナの操作が可能だった。Docker Compose 1.5 と Docker Swarm 1.0, Docker Engine 1.9 の組み合わせにより、複数のホスト上で複数のコンテナを起動し、かつ名前解決が可能となる。
ここでは cms
という Compose プロジェクトを使い、オーバレイ・ネットワークの自動起動と、コンテナの自動起動・ネットワークの割り当てを行う。
web
と db
という名称のコンテナを定義する。web
コンテナは swarm-node0
上で実行する設定とするが、db
は Swarm のストラテジに従う(デフォルトは Spread 方式なので、リソースが空いている別のサーバ上でコンテナは起動する)。
mkdir cms
cd cms
cat << EOF > docker-compose.yml
web:
image: wordpress
environment:
- "WORDPRESS_DB_HOST=cms_db_1"
- "WORDPRESS_DB_USER=root"
- "WORDPRESS_DB_PASSWORD=example"
- "constraint:node==swarm-node0"
ports:
- 8080:80
db:
image: mariadb
environment:
MYSQL_ROOT_PASSWORD: example
EOF
オーバレイ・ネットワーク機能を有効にしてコンテナを起動するには --x-networking --x-network-driver
を実行する。
$ docker-compose --x-networking --x-network-driver overlay up -d
Creating network "cms" with driver "overlay"
Pulling web (wordpress:latest)...
swarm-node1: Pulling wordpress:latest... : downloaded
swarm-node0: Pulling wordpress:latest... : downloaded
Creating cms_web_1
Pulling db (mariadb:latest)...
swarm-node0: Pulling mariadb:latest... : downloaded
swarm-node1: Pulling mariadb:latest... : downloaded
Creating cms_db_1
実行状態の確認は docker-compose ps
を実行する。
$ docker-compose ps
Name Command State Ports
--------------------------------------------------------------------------------
cms_db_1 /docker-entrypoint.sh mysqld Up 3306/tcp
cms_web_1 /entrypoint.sh apache2-for ... Up 188.166.225.83:8080->80/tcp
この例では、ブラウザから http://188.166.225.83:8080
にアクセスすると、WordPress の初期画面が表示される。あとは docker-compose stop
での停止や docker-compose rm
の環境削除は、通常の Compose コマンドと変わりない。
注意点としては、docker-compose up
時に各マシン上でイメージのダウンロードが開始される。そのため、一見すると止まって見える場合も有る。また、今回の例でタイムアウトして自動起動に失敗して見える場合 stop
start
を繰り返すと正常に起動する。
どこのノード上にどのコンテナを実行するかは、基本的に Swarm のストラテジとフィルタに依存する。
Swarm 全般については以下、
Compose 全般については以下参照。