個人開発してるitamaeプラグインのCI環境を作り直したのでその知見
tl;dr;
itamaeプラグインのCIにDockerを活用してモダンになった
今までのCI
下記のブログに詳しく書いています
sue445.hatenablog.com
問題点
元々この構成は オライリーのServerspec本 を参考に構築してたのですが、長年使ってきて下記のような問題点がありました
DigitalOcean依存による問題
- 同一OSでもローカル(VirtualBox)とCI(DigitalOcean)とでイメージが違うので、ローカルだとOKでもCIだとビルドがコケることがある
- WerckerからDigitalOceanでVMを立ち上げる時に、VMの起動に失敗することが稀によくある
- ssh越しにitamaeを実行するので遅い
- DigitalOceanに利用にもお金がかかるのでビルドを回す度にお金が減る
- itamaeプラグイン6個でweeklyビルドを実行して月1ドル前後
Vagrant依存による問題
- 古いVagrantに依存しているため最新のbundlerと相性が悪い *1
- CI実行時に毎回Vagrantをダウンロードしてインストールしてるのでその分ビルドが遅い
新しいCIの構成
やったこと
https://github.com/sue445/itamae-plugin-recipe-tig/pull/13 をかいつまんで説明
gemの依存にdocker-apiを追加
spec.add_development_dependency "docker-api"
spec/spec_helper.rbを修正
require 'serverspec'
require 'docker'
set :backend, :docker
set :docker_image, ENV['DOCKER_IMAGE']
set :docker_container, ENV['DOCKER_CONTAINER']
require "yaml"
require "itamae/node"
def node
return @node if @node
hash = YAML.load_file("#{__dir__}/../recipes/node.yml")
@node = Itamae::Node.new(hash, Specinfra.backend)
end
自分の場合spec内でnodeの値を使うことが多いので上記のような構成にしてるので不要な場合は node
メソッドを削除してください。あとnode.ymlのパスは必要に応じて要微調整。
spec_helper.rbは下記が参考しています
joe-noh.hatenablog.com
serviceを使わない場合
env
の IMAGE
でDockerイメージの名前を渡してマトリクステストできるようにしています
language: ruby
sudo: required
services:
- docker
rvm:
- 2.3
env:
- IMAGE=centos:7
- IMAGE=debian:jessie
bundler_args: "--jobs=4"
cache: bundler
before_install:
- gem update --system --no-document
- gem install bundler --no-document
script:
- bundle exec itamae docker --node-yaml=recipes/node.yml recipes/install.rb --image=$IMAGE --tag itamae-plugin:latest
- DOCKER_IMAGE=itamae-plugin:latest bundle exec rspec
serviceを使う場合
CentOS 7だけかもしれないんですが普通に docker run
した状態でserviceを起動しようと「Failed to get D-Bus connection: No connection to service manager.」というエラーになるので itamae-plugin-recipe-consul では下記のように書いていました。
before_script:
- docker run --privileged -d --name container-with-service $IMAGE /sbin/init
script:
- bundle exec itamae docker --node-yaml=recipes/node.yml recipes/install.rb --container=container-with-service --tag itamae-plugin:latest
- DOCKER_CONTAINER=container-with-service bundle exec rspec
このエラーの解決には下記が参考になりました
qiita.com
メリット
一番大きなところでは、ビルドの時間が速くなってます。
外部クラウドに対してVM起動することがなくなったり、ssh越しにコマンドを実行せずにローカルのDockerコンテナに対してコマンドを実行するようになったことから全体的にビルド時間が速くなりました
修正前後での1回辺りのビルド時間を集計しましたが、軒並み速くなっているのが確認できます。(修正前後ともに3~5回くらいビルドを実行した時の平均時間を記載)
|
修正前のビルド時間 (秒) |
修正後のビルド時間 (秒) |
itamae-plugin-recipe-consul |
288.3 |
197.5 |
itamae-plugin-recipe-git_now |
328.3 |
248 |
itamae-plugin-recipe-omori_gohan |
300.6 |
205 |
itamae-plugin-recipe-tig |
374.2 |
322 |
itamae-plugin-resource-encrypted_remote_file |
441.4 |
315 |
itamae-plugin-resource-tmux |
612.6 |
255.75 |
その他メリット
- 不安定なビルドがだいぶなくなった
- 修正前はDigitalOceanのVM起動が不安定だったのですが、TravisCIでDockerを起動することによりビルドがだいぶ安定するようになりました。*2
- ローカルとCIで完全に同じ環境が使えるようになった
- ローカルでも
--provider=digital_ocean
つければいいわけなのですが、自分以外の人がローカルで確認するためだけにDigitalOceanに登録してもらう必要があるので強制しづらい
- DigitalOceanを使わなくなったのでその分のコストが浮いた
デメリット
- Docker依存の問題によりレシピが実行できないことがある
- 他にもDocker由来の問題でハマりどころはあるかもしれない
おまけ:同じ構成をCircleCIで書いた場合
最初全く同じ構成をCircleCIで書いていたのですがymlが膨大になりすぎて途中でTravisCIに移行しました。
最初に書いていたCircleCIの設定ファイル
https://github.com/sue445/itamae-plugin-recipe-tmux/blob/fb1ee0273d5445e48c572fa8ac1528907e38b05c/.circleci/config.yml
CircleCIも悪くはないんですが、マトリクステストしたい場合にはTravisCIの方が簡潔に書けていいですね。