VagrantとAnsibleを使って Docker Swarm 環境を構築

# 概要
vagrant up コマンド一発で Swarmモードの Docker Machine が複数台上がる状態をつくってみる。
プロビジョニングはAnsibleにて行う。(vagrantでansibleを使ったプロビジョニングまで実施されるように設定)

単純に Swarm の環境をつくるのなら、docker-machineコマンドで作っていくのが一番はやいですが、練習がてら今回はスッピンのCentOS7.2のBoxを使ってAnsibleを利用してプロビジョニングを行います。
けど、docker-machineとして認識されてないと、操作するのが辛いので、ローカルマシンからdocker-machineコマンドで確認可能になるところまでやります。

Vagrant と Ansible を触り始めてまだ１週間程度なので、もっとこうした方が良いとかあったら、ご意見頂けますと幸いです。

# 構築するのに準備した環境 (システム要件)
* macOS El Capitan
* Docker 1.13.1
* Ansible 2.2.1.0
* Vagrant 1.8.1
* VirtualBox 5.0.26

## PlayBookで使用するロール
Ansible Galaxy で公開されてるロールをダウンロードして使用させてもらう

* [atosatto.docker-swarm](https://galaxy.ansible.com/atosatto/docker-swarm/)

※ロールのダウンロード手順は下記に記載しております。


# 最終的に実行するコマンドとその結果
```bash
# Vagrantfile が配置されてるディレクトリに移動
$ cd ${WORKSPACE}

# CentOS7.2 の Box を追加しておく
vagrant box add centos7.2 https://github.com/CommanderK5/packer-centos-template/releases/download/0.7.2/vagrant-centos-7.2.box

# 必要なロールは Ansible Galaxy から取得しておく
$ ansible-galaxy install atosatto.docker-swarm --roles-path ${WORKSPACE}/roles

# VM作成 〜 プロビジョニング完了まで
$ vagrant up

# 構築されたVM群を docker-machine コマンドで確認
$ docker-machine ls
NAME                     ACTIVE   DRIVER       STATE     URL                        SWARM   DOCKER    ERRORS
docker-swarm-manager01   -        generic      Running   tcp://192.168.44.11:2376           v1.13.1
docker-swarm-worker01    -        generic      Running   tcp://192.168.44.31:2376           v1.13.1
docker-swarm-worker02    -        generic      Running   tcp://192.168.44.32:2376           v1.13.1

```

あとは、[docker-compose with Swarm for Docker 1.13](http://qiita.com/SightSeekerTw/items/b5ad80fef7521cf96c9a) に記載の手順などで、クラスタが組めているか確認してみると良いかも。

# ファイル/ディレクトリ構成
```
${WORKSPACE}
├── Vagrantfile # 構築するVirtualBoxのVMの定義とプロビジョニングの定義を記載したファイル
└── playbook    # プロビジョニングの定義を記載
    ├── group_vars
    │   └── all.yml # すべてのグループで有効な変数定義
    ├── host_vars
    │   └── docker-swarm-manager01.yml # docker-swarm-manager01 の設定値
    ├── inventory # インベントリファイル (各種ホストやグループの設定が記載)
    └── site.yml  # PlayBook本体
```
これに Ansible Galaxy から取得するロールのディレクトリが追加されます。

## それぞれのファイルの中身
githubでの公開は検討中。。。とりま、以下に記載。

```rb:Vagrantfile
# -*- mode: ruby -*-
# vi: set ft=ruby :

VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  # 追加したBoxを使ってVMを構築する
  config.vm.box = "centos7.2"

  # 構築するVMは共通の秘密鍵を利用する
  config.ssh.insert_key = false

  # Swarm の マネージャーノード と ワーカーノード の数の設定
  number_of_manager_node = 1
  number_of_worker_node = 2

  # 構築するVMで共通の設定
  config.vm.provider "virtualbox" do |vb|
    vb.customize ["modifyvm", :id, "--memory", "1024"] # メモリサイズ
    vb.customize ["modifyvm", :id, "--cpus",   "1"]    # CPU数
  end

  # Docker Swarm における Managerノード 用のVM設定
  (1..number_of_manager_node).each do |i|
    config.vm.define "docker-swarm-manager0#{i}" do |node|
      node.vm.hostname = "docker-swarm-manager0#{i}"
      node.vm.network :private_network, ip: "192.168.44.#{i + 10}"
    end
  end

  # Docker Swarm における Workerノード 用のVM設定
  (1..number_of_worker_node).each do |i|
    config.vm.define "docker-swarm-worker0#{i}" do |node|
      node.vm.hostname = "docker-swarm-worker0#{i}"
      node.vm.network :private_network, ip: "192.168.44.#{i + 30}"
    end
  end

  # Ansible を使ってのプロビジョニングを行うようにする設定
  config.vm.provision "ansible" do |ansible|
    ansible.inventory_path = "playbook/inventory"
    ansible.playbook = "playbook/site.yml"
  end
end
```

```:playbook/inventory
docker-swarm-manager01 ansible_ssh_host=192.168.44.11 --private-key=~/.vagrant.d/insecure_private_key
docker-swarm-worker01 ansible_ssh_host=192.168.44.31 --private-key=~/.vagrant.d/insecure_private_key
docker-swarm-worker02 ansible_ssh_host=192.168.44.32 --private-key=~/.vagrant.d/insecure_private_key

# Docker Engine をインストールするホストのグループ
[docker_engine]
docker-swarm-manager01
docker-swarm-worker01
docker-swarm-worker02

# Docker Swarm の マネージャーノード とするホストのグループ
[docker_swarm_manager]
docker-swarm-manager01

# Docker Swarm の ワーカーノード とするホストのグループ
[docker_swarm_worker]
docker-swarm-worker01
```

```yaml:playbook/site.yml
- name: Provision Docker Swarm Nodes
  hosts: all
  user: vagrant
  become: yes

  # Docker Swarm　を構成してくれるロール
  roles:
    - { role: atosatto.docker-swarm }

  # Docker Machine として認識させるためのタスク
  tasks:

    # こいつが無いと docker-machine create 時に実施される yum update で失敗する
    - name: Install GPG Key for Puppet
      rpm_key:
        key: https://yum.puppetlabs.com/RPM-GPG-KEY-puppet

    # docker-machine create コマンドで netstat コマンドが実行されるようで、CentOS7.2はデフォで入ってないので入れとく
    - name: Install net-tools
      yum:
        name: net-tools

    # ローカルマシンにdocker-machineとして認識させる (Driver に Generic を指定すれば、構築済のノードを Docker Machine として認識させられる)
    - name: Adds Docker Machine
      become: no
      local_action: |
        command docker-machine create --driver generic \
          --generic-ip-address {{ ansible_enp0s8.ipv4.address }} \
          --generic-ssh-key ~/.vagrant.d/insecure_private_key \
          --generic-ssh-user vagrant {{ ansible_hostname }}
```

以下、atosatto.docker-swarm で利用する変数の定義。

```yaml:playbook/group_vars/all.yml
# 全グループ同じインターフェースを利用する (デフォルトインターフェースで良い場合は定義不要だが、VirtualBoxを利用している都合上、そうも行かなかった(´・ω・｀))
docker_swarm_interface: enp0s8
```

```yaml:playbook/host_vars/docker-swarm-manager01.yml
# Docker Swarm の マネージャーノード1号機のIPアドレスの設定 (うまく ansible_fats の変数から導出できなかった(´・ω・｀))
# Swarm として JOIN したりするのに利用するらしい
docker_manager_address: "192.168.44.11"
```

# 課題
* グループやホスト毎の設定が、 group_vars や host_vars と inventory が分散してるから、まとめるのかまとめないのかはっきりしたほうが良かったのかな？
* どうしても、`docker_manager_address`が導出できなかった。。。 docker-swarm-manager01 以外のプロビジョニングにおいて、docer-swarm-manager01 のIPアドレスが導出できない。。。