CircleCI で docker + serverspecを実行する
前回はローカルで docker 上で serverspecを実行した。
今回は、CircleCI上で dockerを起動し、knife-soloで構築し、
serverspecでテストができるようにしようと思う。
全体のワークフローとしては、以下の順序となる。
- Githubにchefのコードをpushする
- CircleCI上でdockerを起動する
- dockerのimageを作成し、コンテナを起動。
- そのコンテナに対し、knife-soloを実行し、インフラを構築。
- 構築したコンテナに対して、serverspecを実行し、テストを行う
そうすると、Githubの Merge Pull Request ボタンにテストの結果が表示される。
CircleCIの始め方などは、割愛。
Dockerfileを使用して、dockerイメージを作成する
まず、以下のDockerfileを作成し、ssh可能なコンテナを作成できるようにする。
FROM centos:centos6 RUN yum install -y passwd RUN yum install -y openssh RUN yum install -y openssh-server RUN yum install -y openssh-clients RUN yum install -y sudo RUN useradd moock RUN passwd -f -u moock RUN mkdir -p /home/moock/.ssh; chown moock /home/moock/.ssh; chmod 700 /home/moock/.ssh ADD authorized_keys /home/moock/.ssh/ RUN chown moock /home/moock/.ssh/authorized_keys; chmod 600 /home/moock/.ssh/authorized_keys RUN echo "moock ALL=(ALL) ALL" >> /etc/sudoers.d/moock RUN sed -i -e "s:^UsePAM yes$:#UsePAM yes:" /etc/ssh/sshd_config RUN /etc/init.d/sshd start RUN /etc/init.d/sshd stop
注意点としては、sshd_configのファイルでPAMを使用する設定になっていたが、 こうすると、ログインした後すぐにログアウトしてしまったので、PAMを使用しないようにした。
また、authorized_keysはcircle.ymlで作成する。
CircleCIの設定
次にCircleCIの設定を行う。
circle.yml は以下のように設定した。
machine: ruby: version: 2.0.0 timezone: Asia/Tokyo services: - docker dependencies: post: - echo "Host circle" >> ~/.ssh/config - echo " HostName 127.0.0.1" >> ~/.ssh/config - echo " User moock" >> ~/.ssh/config - ssh-keygen -N "" -t rsa -f ~/.ssh/id_rsa - cp ~/.ssh/id_rsa.pub authorized_keys test: pre: - docker build -t moock/sshd . override: - cd chef-repo && container_id=`docker run -d -p 22 moock/sshd /usr/sbin/sshd -D` && ssh_port=`docker inspect --format='{{ if index .NetworkSettings.Ports "22/tcp" }}{{ (index (index .NetworkSettings.Ports "22/tcp") 0).HostPort }}{{ end }}' $container_id` && bundle exec knife solo prepare circle -p $ssh_port && bundle exec knife solo cook circle -p $ssh_port && bundle exec rake serverspec:circle SSH_PORT=$ssh_port: timeout: 1200
testの項目をoverrideし、knife-soloの実行とserverspecの実行を行っている。
CircleCIでの流れとしては、
- dockerのサービスを起動
- dockerでログインするホストに対しcircleというHost名を設定する。
(knife-soloでホスト名.jsonで使用するのと、serverspecで、テスト先のホスト名を使用するため) - knife-soloでsshでログインするので、ログインするための秘密鍵と公開鍵を作成。
Dockerfileでauthorized_keysを設定するため、公開鍵をauthorized_keysとしてコピー。
Dockerfileを使用して、docker imageを作成し、コンテナ実行。
- 作成したコンテナにknife-soloを実行。
- serverspecでテスト。
という感じになる。
knife-solo周りのコマンドは、前回のを流用。
ハマった点としては、test項目で timeout の設定をしないと、標準出力に3分間出力がないと
timeoutエラーになってしまうところ。
chefでrbenvなどを使って、rubyをコンパイルしたりすると、確実にtimeoutエラーになってしまうので、
タイムアウトの時間を20分に設定した。
あと、なんか汚いからもう少しきれいにしたい。。
knife-soloの設定
CircleCIで実行するレシピを指定する。ファイル名は .ssh/config
で指定したホスト名を使用するため、
ここでは、circle.jsonとなる。
例として、nginxのレシピを作成し、実行する。
{ "run_list":[ "recipe[nginx]" ] }
serverspecの設定
serverspecの設定としては、例としてspec/web/nginx_spec.rb
を作成し、
property.ymlにテストする項目として追加する。
circle: :roles: - web
これで、Githubにchefのコードをpushすれば、自動でテストを行うようになった。
改善点
一応、環境は構築できたのだが、改善点がある。
Dockerfileを使用してコンテナを作成しているが、ここの部分はそれなりに時間がかかるし、毎回作成するのは、やっぱり無駄っぽい。
たぶんこの辺は、DockerHubを使用すれば、解決するのではないかと思う。