circle ci and docker+serverspec
TRANSCRIPT
motivation (1): chatops
● “GitHub 時代のデプロイ戦略”http://d.hatena.ne.jp/naoya/20140502/1399027655
● “Slack / Hubot / GitHub / CircleCI によるChatOpsなデプロイ方法”http://qiita.com/s-kiriki/items/26bdf537169891b22653
motivation (2): Docker
● “Build and deploy Docker containers on CircleCI” https://circleci.com/integrations/docker
● “Continuous Integration and Delivery with Docker” https://circleci.com/docs/docker
● Circle CIのビルドコンテナ内でのdockerの実行をサポート
motivation (3): SSH
● “SSH access to builds” https://circleci.com/docs/ssh-build
● GithubのSSH公開鍵でログイン● 30分ほどで切断される● sudo 利用可能
pricing“Continuous Integration and Deployment on CircleCI just got better: now it’s free.” http://blog.circleci.com/continuous-integration-and-deployment-on-circleci-just-got-better-now-its-free/● 1コンテナは無料● 追加1コンテナあたり $50/Month● OSSプロジェクトでは追加で3コンテナ無料で利用可能(計4
コンテナ無料)
Demo: Getting Started with Circle CI
https://circleci.com/docs/getting-started1. Circle CIにサインアップ2. Circle CI に Github へのアクセス許可3. プロジェクトをクリック
demo: minimum2scp/tdiary-style-gfmを Circle CI でテストしてみます。
example of circle.ymlmachine:
ruby:
version: 2.2.0
dependencies:
override:
- bundle install
test:
override:
- bundle exec rake spec
circle.yml how to
● “Configuring CircleCI” https://circleci.com/docs/configuration
● “Sample circle.yml file“ https://circleci.com/docs/config-sample
circle.yml: machinemachine:
ruby:
version: 2.2.0
services:
- elasticsearch
rvmでRuby 2.2.0を使用する
rubyの他にも nodejs, python, php, java などが使用可能です。https://circleci.com/docs/languagesPostgreSQLやMySQL, Redis, MongoDB など書かなくても起動しているデータベースもあります。https://circleci.com/docs/environment#databases
データベースやサービスを起動する
circle.yml: dependenciesdependencies:
override:
- bundle install
依存ライブラリをインストールするコマンド
- Gemfile = bundle install (ruby) - requirements.txt = pip install (python) - package.json = npm install (nodejs)のように自動的に依存ライブラリのインストール方法を推測して実行するので、override しなくてもインストールすることも可能です。
circle.yml: test
test:
override:
- bundle exec rake spec
テストを実行するコマンド
Ruby, Railsでは Test::Unit, RSpec などのテストを自動的に推測して実行してくれますので、(場合によりますが)overrideを書かなくてもテストを実行することが可能です。(もちろん他の言語でも→ https://circleci.com/docs/languages)
minimum2scp/dockerfiles
https://github.com/minimum2scp/dockerfiles● Debian sid amd64ベースのDockerコンテナ
集のリポジトリ
● serverspecによるコンテナのテスト● Circle CI上でコンテナのビルドとテスト
circle.yml (Docker+Serverspec)machine:
services:
- docker
dependencies:
override:
- cd baseimage;docker build -t minimum2scp/baseimage:latest .
- bundle install
test:
override:
- bundle exec rake spec:baseimage
Dockerfileに従ってDockerコンテナをビルド
dockerコマンドが使えるようになる
ビルドしたコンテナに対してserverspecでテスト
Serverspecdescribe package('git') do
it { should be_installed }
end
describe file('/etc/timezone') do
its(:content){ should include 'Asia/Tokyo' }
end
describe user('debian') do
it { should belong_to_group 'sudo' }
end
describe service('sshd') do
it { should be_enabled }
end
docker backend of serverspec
specinfra 2.12.3 (2015-02-01) の実装(抜粋)
module Specinfra::Backend
class Docker < Exec
# (snip)
def run_command(cmd, opts={})
cmd = build_command(cmd)
cmd = add_pre_command(cmd)
docker_run!(cmd)
end
specinfraのdockerバックエンドのコード
テストに応じてコンテナに対してコマンドを実行
def docker_run!(cmd, opts={})
opts = # (snip)
container = ::Docker::Container.create(opts)
begin
container.start
begin
stdout, stderr = container.attach(:logs => true)
result = container.wait
return CommandResult.new :stdout => stdout.join, :stderr =>
stderr.join, :exit_status => result['StatusCode']
rescue
container.kill
end
ensure
container.delete
# (snip)
コンテナの削除ここで例外
コンテナ起動
コンテナ内でのコマンド実行結果待ち
“docker rm” on Circle CI…?machine:
services:
- docker
dependencies:
override:
- docker pull minimum2scp/baseimage:latest
test:
override:
- docker run --name c1 -d minimum2scp/baseimage:latest
- docker stop c1
- docker rm c1
コンテナを起動して停止して削除するだけの簡単なテスト
docker rm: error message $ docker rm c1
Error response from daemon: Cannot destroy container c1:
Driver btrfs failed to remove root filesystem 431a239…
(snip)…: Failed to destroy btrfs snapshot: operation not
permitted
FATA[0000] Error: failed to remove one or more containers
docker rm c1 returned exit code 1
answer from supportthis is a known limitation of our container permissions model. We have a "root" user in the container which has a subset of the capabilities of the real root user, this enables it to perform many of the same actions that you would ordinarily need the real root user to perform.
Unfortunately, removing a btrfs snapshot to rm a docker image requires greater capabilities than we can securely grant to the "root" user in the container
Fortunately you don't need to worry about any docker filesystems you've created during the build. We completely destroy the container's filesystem when the build is finished, removing any docker filesystems too
日本語でおk
● 既知の問題(セキュリティのための制限)● docker rm -> btrfs スナップショット削除に必要
となる権限を与えられていない● ビルド終了時に全部消えるから docker rm でき
ないことは気にしなくていい
monkey patch
## workaround for Circle CI
if ENV['CIRCLECI']
class Docker::Container
def remove(options={}); end
alias_method :delete, :remove
end
end
spec/spec_helper.rb
CircleCIではコンテナを削除しない
more problems
✔ docker rm でエラー→コンテナを削除しない
❌ 遅い
● OS 種別の判定に数秒● 70exampleの実行に約30秒
❌ まれによく偶発的にfailしていた
● CircleCIでは頻繁にランダムに発生● ローカルPCではまれ(docker pullとテスト併走で再現)
use ssh backend
require 'serverspec'
require 'docker'
container = ::Docker::Container.create({'Image' => ENV['DOCKER_IMAGE']})
container.start
set :backend, :ssh
set :host, container.json['NetworkSettings']['IPAddress']
set :ssh_options, {:user => 'debian', :password => 'debian'}
set :os, :family => 'debian', :arch => 'x86_64', :release => '8.0'
sleep 3
docker-api gemを利用してコンテナを起動
コンテナのIPアドレス等設定
OSの自動判定をスキップコンテナ内のsshd起動を待つ
spec/spec_helper.rb
SSHバックエンドを使用
specinfra v2.13.0 (2015-02-13)https://github.com/serverspec/specinfra/pull/315
“docker exec” on Circle CI…?machine:
services:
- docker
dependencies:
override:
- docker pull minimum2scp/baseimage:latest
test:
override:
- docker run --name c1 -d minimum2scp/baseimage:latest
- docker exec c1 uname -a
コンテナを起動してdocker execでコマンド実行するだけの簡単なテスト
docker exec: error message $ docker exec c1 uname -a
FATA[0000] Error response from daemon:
Unsupported: Exec is not supported by the
lxc driver docker exec c1 uname -a returned
exit code 1
answer from supportI'm afraid that we don't support docker exec in CircleCI at the moment. We are planning on a fix in the next month or so.Would that work for you? Is it possible if you use another workaround for the moment?
来月(2015年4月)あたりdocker exec使えるようになるらしいです!
newsWe are planning to release an upgraded Linux container image on 2015-03-12 which includes a number of updates many people have been asking for, notably:
● Postgres is updated to 9.4● iojs is pre-installed on the container image● Firefox is updated to 36
If you use Firefox for browser testing you should upgrade to Selenium 2.45 at your earliest convenience. We'll be upgrading Chrome shortly, in the next container image we release which is currently slated for the following week.
see also:
“Changelog”https://circleci.com/changelog
“The Circle Blog | Testing made easy” http://blog.circleci.com/