- やってること
- メモ
— Jenkins を動かす環境
— Docker イメージ
— itamae レシピ
— Serverspec テスト
— Jenkins の準備
—– プラグイン
—– Docker 周り
—– ジョブ
—– infra-itamae の設定
—– infra-serverspec の設定 - 動いてる図
— Build Pipeline
— ログ - 以上
やってること
今更かもしれないけど, ギョームで以下のようなことをやって, ここ数日で運用も回ってきた気がするのでメモしておく.
- itamae のレシピを amazonlinux コンテナに適用
- 適用したコンテナに対して Serverspec でテスト
- 1 と 2 を Jenkins のビルドパイプラインで流す
- 3 が正常に終了したら, pull request を作成, 又はマージ
- master ブランチのレシピをサーバーに手動で適用
Jenkins のポテンシャルと itamae と Serverspec の使いやすさに改めて感動した次第.
メモ
Jenkins を動かす環境
- Amazon Linux AMI release 2017.09
- Docker Server / Client 17.12.0-ce
- OpenJDK 1.8.0_161
Docker イメージ
- amazonlinux
- 素の amazonlinux イメージだと色々と辛かったので, 以下のような Dockerfile を用意してイメージを作成
以下, Dockerfile.
FROM amazonlinux RUN yum install -y sudo util-linux which diffutils RUN useradd ec2-user RUN echo 'ec2-user ALL = NOPASSWD: ALL' > /etc/sudoers.d/ec2-user RUN yum reinstall -y glibc-common ADD clock /etc/sysconfig/clock ADD cloud.cfg /etc/cloud/cloud.cfg ENV LANG ja_JP.UTF-8
以下, clock と cloud.cfg の中身.
# clock ZONE="UTC" UTC=true
cloud.cfg を直接編集するのは良くないらしい.
# cloud.cfg # WARNING: Modifications to this file may be overridden by files in # /etc/cloud/cloud.cfg.d # If this is set, 'root' will not be able to ssh in and they # will get a message to login instead as the default user (ec2-user) disable_root: true # This will cause the set+update hostname module to not operate (if true) preserve_hostname: true datasource_list: [ Ec2, None ] repo_upgrade: security repo_upgrade_exclude: - kernel - nvidia* - cudatoolkit mounts: - [ ephemeral0, /media/ephemeral0 ] - [ swap, none, swap, sw, "0", "0" ] # vim:syntax=yaml
clock と cloud.cfg は, itamae の中でこれらを書き換える為のレシピを用意する為, 事前に書き換えられる前のファイルを用意した.
itamae レシピ
以下のようなレシピを用意した.
# cookbooks/common/default.rb # Package install %w(wget git).each do |pkg| package pkg end # Edit /etc/sysconfig/clock file '/etc/sysconfig/clock' do action :edit block do |content| content.gsub!('ZONE="UTC"', 'ZONE="Asia/Tokyo"') content.gsub!('UTC=true', 'UTC=false"') end end # Set LocalTime local_file_exists = 'ls /usr/share/zoneinfo/Japan' execute 'Set LocalTime' do command 'ln -nfs /usr/share/zoneinfo/Japan /etc/localtime' only_if local_file_exists end # Disable Package Update and Set Locale Language remote_file '/etc/cloud/cloud.cfg.d/99_customize.cfg' do action :create mode '0644' owner 'root' group 'root' source 'files/etc/cloud/cloud.cfg.d/99_customize.cfg' end
itamae のディレクトリ構造は以下の通り.
$ tree . -L 2 . ├── Gemfile ├── Gemfile.lock ├── Rakefile ├── cookbooks │ └── common ├── docker │ ├── Dockerfile │ ├── clock │ └── cloud.cfg ├── node.json ├── roles │ └── docker-test.rb └── vendor └── bundle 6 directories, 8 files
Serverspec テスト
以下のようなテストを用意.
require "spec_helper" %w(wget git).each do |pkg| describe package(pkg) do it { should be_installed } end end describe file('/etc/sysconfig/clock') do it { should exist } its(:content) { should match /ZONE="Asia\/Tokyo"/ } its(:content) { should match /UTC=false/ } end describe file('/etc/localtime') do it { should be_symlink } end describe file('/etc/cloud/cloud.cfg.d/99_customize.cfg') do it { should exist } it { should be_mode 644 } it { should be_owned_by 'root' } it { should be_grouped_into 'root' } end describe command('date') do its(:stdout) { should contain('JST') } end describe command('locale') do its(:stdout) { should contain('ja_JP.UTF-8') } end
spec_helper.rb にちょっとひと手間加えて, 環境変数に Docker イメージを指定して rspec が走るようにしておく.
require 'serverspec' require 'net/ssh' require 'json' properties = YAML.load_file('properties.yml') if ENV['DOCKER_IMAGE'] begin require 'docker' rescue LoadError fail "docker-api is not available. Try installing it." end set :backend, :docker set :docker_image, ENV['DOCKER_IMAGE'] else ... 省略 ... end
ディレクトリ構造は以下の通り.
$ tree . -L 2 . ├── Gemfile ├── Gemfile.lock ├── Rakefile ├── properties.yml ├── spec │ ├── common │ └── spec_helper.rb └── vendor └── bundle 4 directories, 5 files
Jenkins の準備
プラグイン
以下のプラグインを利用した.
- rbenv plugin
- Parameterized Trigger plugin
- Build Pipeline Plugin
Build Pipeline Plugin は必須では無い.
Docker 周り
jenkins ユーザーで docker コマンド叩けるようにしておく.
sudo gpasswd -a jenkins docker
こんな感じ.
$ sudo -u jenkins docker version Client: Version: 17.12.0-ce API version: 1.35 Go version: go1.9.2 Git commit: 3dfb8343b139d6342acfd9975d7f1068b5b1c3d3 Built: Mon Mar 5 20:42:27 2018 OS/Arch: linux/amd64 Server: Engine: Version: 17.12.0-ce API version: 1.35 (minimum version 1.12) Go version: go1.9.2 Git commit: 402dd4a/17.12.0-ce Built: Mon Mar 5 20:43:34 2018 OS/Arch: linux/amd64 Experimental: false
ジョブ
以下のようにジョブを 2 つ用意した. (ジョブ名はなんでもいい)
- infra-itamae
- infra-serverspec
個々のジョブで共通して以下の内容を設定した.
- ソースコード管理 (今回も Backlog Git を利用)
- rbenv build wrapper で Ruby 2.5.0 を利用するようにした
以下のように infra-itamae が成功したら, infra-serverspec が実行されるように設定した.
infra-itamae の設定
[ビルド] の [シェル実行] に以下のようにシェルスクリプトを書いた.
cd itamae.sandbox bundle install --path vendor/bundle cd docker docker build -t itamae-test . cd ../ bundle exec itamae docker --image=itamae-test roles/docker-test.rb --log-level=info --no-color 2>&1 | tee test.log if [ "$(cat test.log | tail -1 | awk -F":" '{print $4}')" != "" ];then echo -n "DOCKER_IMAGE=$(cat test.log | tail -1 | awk -F":" '{print $4}')" > ${WORKSPACE}/docker_image.txt else exit 1 fi
itamae は Docker コンテナに対してプロビジョニングして, コンテナイメージを作成することが出来る.
$ bundle exec itamae --help docker Usage: itamae docker RECIPE [RECIPE...] Options: [--recipe-graph=PATH] # [EXPERIMENTAL] Write recipe dependency graph in DOT -j, [--node-json=NODE_JSON] -y, [--node-yaml=NODE_YAML] -n, [--dry-run], [--no-dry-run] [--shell=SHELL] # Default: /bin/sh [--login-shell], [--no-login-shell] [--ohai], [--no-ohai] # This option is DEPRECATED and will be unavailable. [--profile=PATH] # [EXPERIMENTAL] Save profiling data [--detailed-exitcode], [--no-detailed-exitcode] # exit code 0 - The run succeeded with no changes or failures, exit code 1 - The run failed, exit code 2 - The run succeeded, and some resources were changed -l, [--log-level=LOG_LEVEL] # Default: info [--color], [--no-color] # Default: true -c, [--config=CONFIG] [--image=IMAGE] # This option or 'container' option is required. [--container=CONTAINER] # This option or 'image' option is required. [--tls-verify-peer], [--no-tls-verify-peer] # Default: true [--tag=TAG] Create Docker image
[ビルド後の処理] で [Trigger parameterize build on other projects] を指定し, 以下のパラメータを設定した.
パラメータ名 | 値 | 概要 |
---|---|---|
Projects to build | infra-serverspec | 下流プロジェクトを指定 |
Trigger when build is | Stable | 下流プロジェクトがビルドされる基準 |
Perameters from properties file | 選択 | ファイルからパラメータを指定する |
Use properties from file | docker_image.txt | ${WORKSPACE} 以下に生成されるファイル名を指定 |
Use properties from file で指定するファイルは以下のようなフォーマットである必要がある.
KEY=value
今回だと, 下流プロジェクトである infra-serverspec で利用する Docker イメージ名を環境変数に指定しておきたいので, 以下のような内容になる.
DOCKER_IMAGE=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
尚, itamae 実行時に --no-color
オプションを付与しておかないと, ログ出力にカラーコードが含まれてしまい, 意図しない環境変数が定義されるので注意する.
infra-serverspec の設定
[General] の [ビルドのパラメータ化] にチェックを入れて, 以下のように設定した.
- テキストの [名前] には
DOCKER_IMAGE
を指定
[ビルド]の [シェル実行] に以下のようにシェルスクリプトを書いた.
cd serverspec.sandbox bundle install --path vendor/bundle bundle exec rake serverspec:docker-test && docker rmi -f ${DOCKER_IMAGE}
動いてる図
Build Pipeline
ログ
以下, infra-itamae の実行ログ (コンソール出力).
Started by user xxxxxxx Building in workspace /var/lib/jenkins/workspace/infra-itamae > git rev-parse --is-inside-work-tree # timeout=10 Fetching changes from the remote Git repository ... INFO : Image created: sha256:fc7d8989c992a4035da943f19ff13758d659dc2c66e85b354a81ed35eac092a9 ++ cat test.log ++ tail -1 ++ awk -F: '{print $4}' + '[' fc7d8989c992a4035da943f19ff13758d659dc2c66e85b354a81ed35eac092a9 '!=' '' ']' ++ cat test.log ++ tail -1 ++ awk -F: '{print $4}' + echo -n DOCKER_IMAGE=fc7d8989c992a4035da943f19ff13758d659dc2c66e85b354a81ed35eac092a9 Triggering a new build of infra-serverspec Finished: SUCCESS
以下, infra-serverspec の実行ログ (コンソール出力).
Started by upstream project "infra-itamae" build number 3 originally caused by: Started by user xxxxxxxx Building in workspace /var/lib/jenkins/workspace/infra-serverspec > git rev-parse --is-inside-work-tree # timeout=10 Fetching changes from the remote Git repository ... Command "date" stdout should contain "JST" Command "locale" stdout should contain "ja_JP.UTF-8" Finished in 1.39 seconds (files took 0.36337 seconds to load) 12 examples, 0 failures + docker rmi -f 21f1cc87aee8a670710128fc65699f8554de4b38027c355dc39048a026850819 Deleted: sha256:21f1cc87aee8a670710128fc65699f8554de4b38027c355dc39048a026850819 Deleted: sha256:6605e21eb4b68cca7fa9c95da3f4f927f40988798c038ed7f42fc68caabb5f84 Deleted: sha256:1e12645118a9dbb47e9963ee37669022e91bb0a07c2a5757f30aaf88e83fde46 Deleted: sha256:2e643788655c8c760d1e980eca0b46251b7301af1b759b5df5ab7bbe642b0c9d Deleted: sha256:00f5d50a957784ab20fd7b550fdfeca505dc4e550959ba7f73f2def824041d44 Deleted: sha256:e0f2d8168d9eaa1ed9592791b8a4e436b5476db41b99fa12bf32076891b9fd22 Deleted: sha256:b7937fd11c3afb70b655e281ef6acdc4d3afc3cd912a19fe14cfb3b93c0e7688 Deleted: sha256:9989831a58db4d3c31f5f18d590c5ffc08ad41ac4f424b3ea870fded4440e591 Deleted: sha256:4ac2d011c778bf4d55459f2549bb80bc89b3327e747384446c1f08652997bbfb Deleted: sha256:7522d03ea4bb3188185376f4aa675724bc8c46e961fa0625dc73b164408b5736 Deleted: sha256:f0a3ff27c8c1d0e4242beb150786fae71a8b52a328b3810581c0a50d9101c89d Deleted: sha256:95f9b360e9435265a8e1888110af30e93a90e563fe969c8249f14d446791c996 Deleted: sha256:be94791a1fc4eb636d443b0fb18b56eed7c32b0cd3a2b3912b10b7945d840179 Deleted: sha256:fff1c0462adfdaa1e8c815e4fc17c228b205479a23161cd717342dad5d9345b2 Finished: SUCCESS
テストが通った時だけ, コンテナイメージを削除しちゃう.
以上
ざっくりとしたメモでした.
元記事はこちら
「もう 2018 年だけど, Jenkins + Docker + itamae + Serverspec でインフラ CI っぽいことをやってるのでメモ