werckerでのAnsibleとSeverspecの自動実行

**注　2016年現在、werckerの仕様変更に伴い、これは動作しません。**

## 概要
GithubへのPush毎に、werckerでAnsibleのPlaybookとServerspecでのテストを自動実行するようにしました。
拙作の[ansible-Redmine](https://github.com/volanja/ansible-Redmine)のv3.0.2対応に併せて実現しています。
これまではVagrantを起動して確認していましたが、GithubへのPush毎に自動的に実行されるので、楽になりそうです。


作成にあたっては次のエントリを参考にさせて頂きました。

[CircleCIでDockerコンテナに対してansibleを実行しserverspecでテストをする](http://blog.kenjiskywalker.org/blog/2014/11/13/circleci-docker-ansible-serverspec/)
[[drone]OSS版DroneでDockerコンテナに対してansibleを実行しserverspecでテストをする](http://d.hatena.ne.jp/toritori0318/20141113/1415898291)

エントリと違う点としては、次の3点があります。

+ wercker以外の別のDockerホストの環境でも使いやすいことを目指した。
+ AnsibleとServerspec専用のコンテナを用意した。
+ Ansibleの実行先に専用のコンテナを用意することで、実行先の設定を予め固定するなど実際の環境になるべく近いようにした。


[ansible-Redmine](https://github.com/volanja/ansible-Redmine)に[wercker.yml](https://github.com/volanja/ansible-Redmine/blob/master/wercker.yml)を設置し、[wercker - ANSIBLE-REDMINE](https://app.wercker.com/#applications/543fd9c9d8c8e771360712ad)で実行しています。
wercker.ymlをシェルスクリプトに書き換えると、他のDockerホストでも簡単に実行できると思います。

今回の構成図は次のような形になります。
![wecker_and_docker.png](https://qiita-image-store.s3.amazonaws.com/0/29901/e92a951c-dfed-92b5-7ad2-39d26a209ce4.png "wecker_and_docker.png")


## volanja/docker-ruby2.2.0コンテナ
CentOS6をベースに、Ruby2.2.0をインストール済みのコンテナです。
Redmineインストール毎にRubyをインストールするのは時間が足りないので、予め用意しました。

DockerのAutomated Buildで作成しています。
[Docker Hub - volanja/docker-ruby2.2.0](https://registry.hub.docker.com/u/volanja/docker-ruby2.2.0/)
SSH鍵はビルド毎に作成しており、受け渡しにvolumeを使用しています。
起動後はSSH公開鍵の設定などを行います。

```bash
docker run -d -P --cap-add=NET_ADMIN --hostname=cadence -v `pwd`/ssh:/var/tmp:rw --name target volanja/docker-ruby2.2.0
echo 'service sshd restart; mkdir /root/.ssh/ ; cat /var/tmp/authorized_keys >> /root/.ssh/authorized_keys' | /usr/local/bin/docker-enter target
```

### dockerコンテナ上でのiptables設定
[Docker Hub - volanja/docker-ruby2.2.0](https://registry.hub.docker.com/u/volanja/docker-ruby2.2.0/)の注意点です。


Ansibleのplaybook中でiptablesの設定ファイル(/etc/sysconfig/iptables)の書き換えとiptablesの再起動を行いますが、docker上では2つの問題が有り、対応しています。

+ /etc/sysconfig/iptablesがない。  
centos:centos6にはファイルがありません。  
そこで、Dockerコンテナのビルド時にCOPYすることで対応しました。
+ iptablesの再起動が出来ない。  
dockerコンテナのビルド時に`echo 'IPTABLES_MODULES_UNLOAD=no' >> /etc/sysconfig/iptables-config`を行うと共に、docker runの実行時に`--cap-add=NET_ADMIN`を付加することで対応しました。  
次のエントリを参考にさせて頂きました。  
[Dockerコンテナ内で service iptables stop/status をエラーにしない](http://qiita.com/udzura/items/500209a62877c5435952)

## volanja/docker-ansibleコンテナ
CentOS6をベースに、AnsibleとServerspecをインストール済みのコンテナです。
DockerのAutomated Buildで作成しています。
[Docker Hub - volanja/docker-ansible](https://registry.hub.docker.com/u/volanja/docker-ansible/)
SSH鍵はビルド毎に作成しており、受け渡しにvolumeを使用しています。
Ansible Playbookの受け渡しにもvolumeを使用しています。
SSH鍵の設置を行った後に、AnsibleのPlaybook実行とServerspecの実行を行います。

```bash
docker run -d -P --name serv --link target:dest -v `pwd`:/root:rw -v `pwd`/ssh:/var/tmp:rw -t volanja/docker-ansible
echo 'env; mkdir ~/.ssh; cp /var/tmp/id_rsa_docker ~/.ssh/id_rsa ; chmod 600 ~/.ssh/id_rsa ' | /usr/local/bin/docker-enter serv
echo 'cd /root; ansible-playbook site_wercker.yml -i hosts_wercker' | /usr/local/bin/docker-enter serv
echo 'cd /root; rake serverspec:Install_Redmine' | /usr/local/bin/docker-enter serv

```

## docker-ansibleとdocker-ruby2.2.0間の通信
### Docker Links
2つのコンテナ間のdockerのLinksと呼ばれる機構を利用して通信しました。
これにより、コンテナのみで通信することが出来ます。

初めにdocker-ruby2.2.0コンテナを起動します。

```bash
# (必要な部分のみ抜粋)
docker run -d -P --name target volanja/docker-ruby2.2.0

```

続いて、docker-ansibleコンテナをdocker-ruby2.2.0にリンクする形で起動します。
linksを使用する場合は、`コンテナ名:エイリアス名`と指定します。エイリアス名は`dest`としました。

```bash
# (必要な部分のみ抜粋)
docker run -d -P --name serv --link target:dest -t volanja/docker-ansible
```

docker-ansibleコンテナ内にはdocker-ruby2.2.0コンテナのIPアドレスやポートの情報が環境変数と`/etc/hosts`内に書き込まれます。
Ansibleのhosts情報には`dest`を指定します。

```bash
/usr/local/bin/docker-enter serv
env |grep DEST
DEST_PORT=tcp://172.17.0.8:22
DEST_PORT_22_TCP=tcp://172.17.0.8:22
DEST_PORT_80_TCP=tcp://172.17.0.8:80
DEST_PORT_22_TCP_ADDR=172.17.0.8
DEST_PORT_80_TCP_ADDR=172.17.0.8
DEST_ENV_RUBY_VERSION=2.2.0
DEST_PORT_22_TCP_PORT=22
DEST_PORT_80_TCP_PORT=80
DEST_NAME=/serv/dest
DEST_PORT_22_TCP_PROTO=tcp
DEST_PORT_80_TCP_PROTO=tcp
```

```bash
cat /etc/hosts |grep dest
172.17.0.8	dest
```

次のエントリを参考にさせて頂きました。
[Dockerコンテナ間のlink，database.ymlの書き方](http://deeeet.com/writing/2014/03/20/docker-link-container/)



### SSH鍵の共有
docker-ansibleからdocker-ruby2.2.0にはSSHで接続します。
SSH鍵は毎回wecker上で作成し、共有ディレクトリ経由で各コンテナに渡します。

SSH鍵の作成

```bash
mkdir `pwd`/ssh
ssh-keygen -f `pwd`/ssh/id_rsa_test -N ''
cat `pwd`/ssh/id_rsa_test.pub >> `pwd`/ssh/authorized_keys
```

## Dockerを使うときの注意点
### werckerのdockerは`docker exec`が使えない。
wercker.ymlを書くときの注意点です。

Dockerのバージョンが古く、docker execが使用できません。
代替策として`jpetazzo/nsenter`で`docker-enter`をインストールして使用しています。

```
$ docker -v
Docker version 1.2.0, build fa7b24f
```



以上