Dockerコンテナをクラスタリングする


Dockerを本番運用する際、
負荷分散やスケールアウトを簡単に行えるように
Docker Swarmで、コンテナをクラスタリングします。

## 1. 実行環境
* OS: MacOSX

## 2. 必要ソフトウェア
* docker
* docker-machine
* docker-swarm
* virtualbox

全て`brew`からインストールできます。


```bash
$ brew search docker                             
boot2docker			  docker-machine (installed)	    homebrew/versions/boot2docker141  homebrew/versions/docker141	homebrew/versions/docker171
docker (installed)		  docker-swarm (installed)	    homebrew/versions/boot2docker162  homebrew/versions/docker150
docker-compose (installed)	  homebrew/versions/boot2docker133  homebrew/versions/docker133	      homebrew/versions/docker162
homebrew/completions/boot2docker-completion	   homebrew/emacs/dockerfile-mode		      Caskroom/cask/docker-compose			 Caskroom/cask/docker
homebrew/completions/docker-completion		   Caskroom/cask/boot2docker-status		      Caskroom/cask/docker-machine-driver-parallels	 Caskroom/cask/dockertoolbox
homebrew/completions/docker-machine-completion	   Caskroom/cask/boot2docker			      Caskroom/cask/docker-machine

$ brew cask search virtualbox 
==> Exact match
virtualbox
==> Partial matches
virtualbox-extension-pack
```

## 3. トークンを発行
クラスタリングを構成するノードを判別するための、トークンを発行する必要があります。
dockerコマンドを使う必要があるため、適当にVMを立ち上げて発行します。

```
$ docker-machine create -d virtualbox dev
$ eval "$(docker-machine env dev)"
$ docker run --rm swarm create
14c49ec7d3841b86b3964edf9bb70bf3 # token
```

トークンを控えて、VMを削除します。

```
$ docker-machine rm dev
```

## 4. SwarmマネージャーとなるVMを作成
Swarmのクラスタリングを管理するサーバーを作成します。

```
docker-machine create -d virtualbox --swarm --swarm-master --swarm-discovery token://<トークン> cl-manager
```

## 5. SwarmノードとなるVMを作成
Swarmノードとなるサーバーを作成します。

```
$ docker-machine create -d virtualbox --swarm --swarm-discovery token://<トークン> cl-node1
$ docker-machine create -d virtualbox --swarm --swarm-discovery token://<トークン> cl-node2
```

## 6. クラスタリング構成を確認

ここまでの作業で、クラスタリングが構成されました。
以下のコマンドで構成内容を確認できます。

```
$ eval $(docker-machine env --swarm cl-manager)
$ docker info
Containers: 4
Images: 3
Role: primary
Strategy: spread
Filters: health, port, dependency, affinity, constraint
Nodes: 3
 cl-manager: 192.168.99.104: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
 cl-node1: 192.168.99.105: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
 cl-node2: 192.168.99.106: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: 3
Total Memory: 3.064 GiB
```

## 7. Httpdサーバーを各サーバーで起動する
SwarmマネージャーでRUNするだけでコンテナが、各サーバーに自動で振り分けられて起動します。

```
$ docker run -d -p 80:80 tutum/hello-world
$ docker run -d -p 80:80 tutum/hello-world
$ docker run -d -p 80:80 tutum/hello-world
```

各サーバーで起動されていることを確認します。

```
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                       NAMES
2aca15f85d35        tutum/hello-world   "/bin/sh -c 'php-fpm "   39 seconds ago      Up 39 seconds       192.168.99.105:80->80/tcp   cl-node1/hopeful_wright
0b5dd1506ebf        tutum/hello-world   "/bin/sh -c 'php-fpm "   40 seconds ago      Up 40 seconds       192.168.99.104:80->80/tcp   cl-manager/adoring_hugle
17599cbe83ce        tutum/hello-world   "/bin/sh -c 'php-fpm "   42 seconds ago      Up 41 seconds       192.168.99.106:80->80/tcp   cl-node2/romantic_kare
```

ブラウザや、curlでアクセスできることを確認します。

```
$ curl http://192.168.99.105
$ curl http://192.168.99.104
$ curl http://192.168.99.106
```