自分の備忘録兼、社内ハンズオン用の資料なので、足りないところが多いかもしれません。
記事の最後まで進んだ状態が以下にありますので、参考にどうぞ。
honeniq/docker-circleci-sample
事前に必要なもの
- ローカルでDockerが使える環境
- Docker-Toolboxなど
- DockerHubのアカウント
- GitHubのアカウント
- CircleCIはGitHubアカウントでログインできます
- Ruby
- Bundlerも必要
大体の手順
- GitHubでリポジトリを作って、ローカルにクローン
-
Gemfile
を作成 - テストの準備をする
- テストと実装コードを書く
- CircleCIの設定
- GitHubフローでCIを回す
- DockerHubに自動デプロイ
GitHubでリポジトリを作って、ローカルにクローン
項目として作ってみたけど、特に書くことがない。
Gemfile
を作成
こんな感じの内容で作成。
source 'https://rubygems.org/'
gem 'docker-api'
group :test do
gem 'specinfra', '2.12.7'
gem 'serverspec'
end
specinfraのバージョンを指定しているのは、CircleCIとの相性から。
参照: CircleCIでDockerコンテナをテストしようとしたらエラーになるとき
保存したら、コンソールからbundle
コマンドを叩く。
$ bundle
Fetching gem metadata from https://rubygems.org/.......
Fetching version metadata from https://rubygems.org/..
Resolving dependencies....
Using diff-lcs 1.2.5
Using excon 0.45.4
~
Using serverspec 2.8.2
Using bundler 1.9.9
Bundle complete! 3 Gemfile dependencies, 16 gems now installed.
Use `bundle show [gemname]` to see where a bundled gem is installed.
テストの準備をする
.rspec
を作成する
--color
--format documentation
設定しておかないとテストの結果表示が味気ないので。
spec_helper.rb
を作成する
require "docker"
require "serverspec"
set :backend, :docker
set :docker_url, ENV["DOCKER_HOST"]
set :docker_image, "honeniq/docker-circleci-sample"
Excon.defaults[:ssl_verify_peer] = false
set :backend, :docker
でDockerコンテナに対してテストするように指定してる。
イメージ名を直接書いてるのがイケてないので、そのうち修正する。
テストのテスト
この状態でrspec
コマンドを叩くと、空のテストが回る。
$ bundle exec rspec
No examples found.
Finished in 0.0003 seconds (files took 0.06445 seconds to load)
0 examples, 0 failures
テストと実装コードを書く
とりあえず今回はnginxが入ればOKという要件で。
web_spec.rb
を作成する
require 'spec_helper'
# Workaround needed for circleCI
if ENV['CIRCLECI']
class Docker::Container
def remove(options={}); end
alias_method :delete, :remove
end
end
describe "nginx" do
describe package("nginx") do
it { should be_installed }
end
end
上半分は、これまたCircleCIで動かすためのコード。
この状態でrspec
すると、Dockerイメージが見つからないと怒られる。
Failures:
1) nginx Package "nginx"
Failure/Error: Unable to find matching line from backtrace
Docker::Error::NotFoundError:
No such image: honeniq/docker-circleci-sample
# (eval):1:in `backend'
Dockerfile
を作成する
FROM ubuntu
とりあえずイメージがビルドできるだけ。
docker build
を叩いてイメージを作る。イメージ名はspec_helper.rb
で指定しているもの。
$ docker build -t honeniq/docker-circleci-sample .
Sending build context to Docker daemon 67.58 kB
Step 0 : FROM ubuntu
---> d2a0ecffe6fa
これで、rspec
のコケ方が変わる。
Failures:
1) nginx Package "nginx" should be installed
Failure/Error: it { should be_installed }
expected Package "nginx" to be installed
# ./spec/web/web_spec.rb:13:in `block (3 levels) in <top (required)>'
テストを通す
nginxをインストールするようにDockerfile
を編集する。
FROM ubuntu
RUN apt-get update
RUN apt-get install -y nginx
再度docker build
してイメージに反映させる。
$ docker build -t honeniq/docker-circleci-sample .
Sending build context to Docker daemon 73.22 kB
Step 0 : FROM ubuntu
---> d2a0ecffe6fa
Step 1 : RUN apt-get update
---> Using cache
---> cb24a07d1bd2
Step 2 : RUN apt-get install -y nginx
---> Running in 5fd7387700fa
Reading package lists...
~
---> 1d87758f46a8
Removing intermediate container 5fd7387700fa
Successfully built 1d87758f46a8
これでテストも無事通るようになる。
$ bundle exec rspec
nginx
Package "nginx"
should be installed
Finished in 12.72 seconds (files took 0.26434 seconds to load)
1 example, 0 failures
ローカルでテストが通るようになったので、GitHubにPushしておく。
CircleCIの設定
新規プロジェクト作成
CircleCIのメニューから、 Add Projects を選んで、GitHubに作ったリポジトリ名の横にある Build project を押す。
しばらくすると1回目のテストが走って・・・コケる。
CircleCIがDockerコンテナを使う設定になっていないのが原因。
circle.yml
を作成する
machine:
services:
- docker
dependencies:
override:
- docker info
- docker build -t honeniq/docker-circleci-sample .
test:
override:
- bundle
- bundle exec rspec
大体見たまんまの内容で、CircleCIでテストを走らせるホストでDockerを使えるようにして、テストの前段でdocker build
を実行、あとはbundle
で必要なgemを入れたあとにrspec
しているだけ。
作成したらGitHubにPush。
CircleCIがリポジトリの更新を検知して、2回目のテストが走る。
通った!
GitHubフローでCIを回す
参照: GitHub Flow
Featureブランチを作る
nginxのindexページの中身を変更する、って体で。
テストコードを書き換える
後半のみ抜粋。
describe "nginx" do
describe package("nginx") do
it { should be_installed }
end
describe file("/usr/share/nginx/html/index.html") do
its(:content) { should match /Welcome to test container/ }
its(:content) { should_not match /Welcome to nginx/ }
end
end
当然、rspec
はコケる。
Dockerfile
を書き換える
FROM ubuntu
RUN apt-get update
RUN apt-get install -y nginx
RUN sed -i 's/Welcome to nginx/Welcome to test container/g' /usr/share/nginx/html/index.html
テストが通るように修正。
Pull Requestを投げる
自分で自分のリポジトリに投げることになるけど気にしない。
CircleCIがPRを検知して、自動的にFeatureブランチのテストを始めてくれる。
こんな感じに、masterと区別してテスト状況が確認できる。
Pull Requestをマージする
自分で自分のPRをマージすることになるけど気にしない。
GitHub上でもCircleCIのテスト結果が確認できるので非常に分かりやすい。
PRがmasterブランチにマージされると、masterブランチの更新を検知してCircleCIがまたテストを走らせてくれる。
DockerHubに自動デプロイ
masterでもテストが通ったら、DockerイメージをDockerHubに自動デプロイするように変更する。
Featureブランチを作る
一応、GitHubフローに沿うように。
ただ、今回の変更内容はmasterブランチ上でしか検証できないので、あんまり意味ないかもしれない。
circle.yml
を修正する
machine:
services:
- docker
dependencies:
override:
- docker info
- docker build -t honeniq/docker-handson .
test:
override:
- bundle
- bundle exec rspec
deployment:
hub:
branch: master
commands:
- docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS
- docker push honeniq/docker-handson
deploymentタスクを追加。
branch: master
で、masterブランチの時のみ実行するように絞っている。
途中、docker login
でDockerHubにログインしてもらう必要があるけど、直接コードにユーザー名やパスワードを書くわけにはいかないので、環境変数に入れる。
CircleCIに環境変数を登録
circle.yml
に指定した3つの環境変数を返せるように、CircleCI側にも登録してあげる。
Project Setting → Tweaks / Environment Variables と進んで、環境変数を登録する。
「Name」に環境変数名、「Value」に対応する値を入力して保存。以下3つを登録。
- DOCKER_EMAIL : DockerHubに登録しているメールアドレス
- DOCKER_USER : DockerHubのユーザー名
- DOCKER_PASS : DockerHubのパスワード
Pull Requestを投げてマージする
先ほどと同じく、自分で自分にPRを投げてマージする。
masterブランチのテストも問題なく通れば、追加したdeploymentタスクが走ってDockerHub上のイメージが更新される。
これで、デプロイまで一通り流れるようになった。