CircleCI + Docker による Itamaeレシピの継続的インテグレーション


クービックではこれまで Vagrantで作成したVMを用いて、ローカルマシンで itamae のテストを実行していました。

管理すべきロールが増えるにつれ毎回テストを回すのがツラくなってきたため、CircleCI による継続的インテグレーションを検討することにしました。

利用環境は以下の通りです。

| Env / Tool | Version |
|:-----------|------------:|
| OS       |        Ubuntu 14.04 |
| Provisioning     |      itamae (1.3.6) |
| Test     |      serverspec (2.19.0) |


また、リポジトリの構成は以下の通りです。
cookbooks には Itamae のレシピが、spec にはテストが入っています。

```
$ tree -L 1
.
├── .ssh
├── Dockerfile
├── Gemfile
├── Gemfile.lock
├── Rakefile
├── circle.yml
├── cookbooks
└── spec
```



## 事例調査
CircleCI で Serverspecによるテストの事例をいくつか調査してみました。

#### Vagrant + EC2
* [KAIZEN platform Inc.における運用自動化](
http://sssslide.com/speakerdeck.com/naoya/kaizen-platform-inc-niokeruyun-yong-zi-dong-hua)

#### Docker + Serverspec + Itamae

* [CircleCI で Docker Container を Serverspec でテストする](http://ja.ngs.io/2015/09/26/circleci-docker-serverspec/)

* [itamaeに入門してDocker調理してみた]
(http://www.slideshare.net/NaokiIshibashi/itamaedocker)

* [Docker on CircleCIでchefのcookbookをserverspecでテスト]
(http://hoppie.hatenablog.com/entry/2015/02/02/014455)


production ではコンテナを利用していないので、prodution と test 環境で乖離が発生するのがやや気になりますが、Docker なら特に追加費用が掛からず、起動も速いので Docker を使うこととしました。


## Docker


何はともあれ、ローカルで Docker を動かすための環境を構築します。
Mac OS X であれば、[Docker Toolbox](https://www.docker.com/docker-toolbox) を使うのが最もカンタンと思われます。

Docker に触れたことがなければ、[Get Started with Docker for Mac OS X](http://docs.docker.com/mac/started/) を一通り試すのがよいです。


### backend

ローカル環境構築が済んだら、docker との I/O を検討します。

Itamae と Serverspec どちらも内部で Specinfra を利用しており、backend として ssh あるいは docker の指定が可能です。production では backend に ssh を利用してるので、docker にも ssh 経由でアクセスすることにします。


なお、[Why you don't need to run SSHd in your Docker containers](http://blog.docker.com/2014/06/why-you-dont-need-to-run-sshd-in-docker/) という議論もありますが、コンテナはCircleCIでしか利用しないので今回はよしとしました。


### Dockerfile

ssh でアクセスできるようなイメージを準備します。

```
FROM ubuntu:14.04

RUN apt-get update && apt-get -y upgrade && apt-get install -y build-essential libssl-dev libreadline-dev zlib1g-dev language-pack-ja
RUN apt-get -y install openssh-server ufw curl
RUN mkdir /var/run/sshd

RUN useradd -m docker && echo "docker:docker" | chpasswd && gpasswd -a docker sudo
RUN mkdir -p /home/docker/.ssh; chown docker /home/docker/.ssh; chmod 700 /home/docker/.ssh
 
ADD ./authorized_keys /home/docker/.ssh/authorized_keys
RUN chown docker /home/docker/.ssh/authorized_keys; chmod 600 /home/docker/.ssh/authorized_keys

CMD /usr/sbin/sshd -D && tail -f /dev/null
```

工夫したポイントをいくつか。

```
RUN useradd -m docker && echo "docker:docker" | chpasswd && gpasswd -a docker sudo
```

で docker ユーザを作成し、sudo グループに登録しています。


```
CMD /usr/sbin/sshd -D && tail -f /dev/null
```

/dev/null を tail -f するのは sshd を再起動した際に、コンテナが exit しないための工夫です。


## CircleCI

circle.yml を準備します。

```yaml
machine:
  services:
    - docker

dependencies:
  pre: 
    - ssh-keygen -t rsa -b 2048 -N "" -C "docker" -f  ~/.ssh/id_rsa.docker
    - cat ~/.ssh/id_rsa.docker.pub > authorized_keys
    - cat .ssh/config >> ~/.ssh/config
    - docker build -t kotaroito/ubuntu .
    - docker run --privileged -d -p 2222:22 kotaroito/ubuntu
test:
  pre:
    - env SUDO_PASSWORD=docker bundle exec itamae ssh -h example cookbooks/recipe.rb
  override:
    - env SUDO_PASSWORD=docker bundle exec rake spec
```


docker ユーザで ssh するために、ssh-keygen で 秘密鍵・公開鍵を生成して、docker build 時に authorized_keys を image に組み込んでいます。 

また、.ssh/config ファイルを用意しておき、itamae ssh -h examle できるようにします。 

```
Host example
  HostName localhost
  User docker
  Port 2222
  StrictHostKeyChecking no
  PasswordAuthentication no
  IdentityFile /home/ubuntu/.ssh/id_rsa.docker
```

なお、privileged オプションは itamae で ufw 等を実行する場合に指定する必要があります。


### 実行結果

![circleci.png](https://qiita-image-store.s3.amazonaws.com/0/20304/2bd63284-e6ed-b763-64fb-4f6cdbaccc24.png "circleci.png")


無事 CircleCI + Docker で Itamae レシピの継続的インテグレーションをすることができました。


## 参考サイト
Dockerfile と circle.yml は、以下を参考にさせていただきました。

 * http://tech.feedforce.jp/serverci-by-docker.html
 * http://qiita.com/comutt/items/1251cc19885947cd6d3d