ちょっとcookbook書いてちゃんと動くか試したいってときにいちいち新しくVagrantfileを用意してnode.json書いて、knife solo cookしてserverspecでテストして...とかやりたいことはrecipeを試したいだけなのに準備が大変なんですよね。
そんなときはその辺を一気に面倒みてくれる便利なtest-kitchenを使ってcookbookの開発をします。
test-kitchenとはchefのcookbookを任意の環境でテストするツールで、vagrantやec2、docker(LXC)上でcookbookを適用し、minitestやserverspecでテストできます。
もとはchefだけでしたが、プラグインを入れることでpuppetやansibleとも連携できるようです。
設定ファイル
test-kitchenの設定ファイルは.kitchen.ymlです。
kitchen initコマンドで生成できます。
$ bundle exec kitchen init
こんな感じのymlが生成されます。
vi .kitchen.yml
--- driver: name: vagrant provisioner: name: chef_solo platforms: - name: ubuntu-12.04 - name: centos-6.4 suites: - name: default run_list: attributes:
設定ファイルの用語
driver
- テストする仮想環境のこと
- vagrant
- EC2
- GCE
- docker 等
provisioner
- chefだけじゃなくansibleとかも使用できる(要追加プラグイン)
- chef-solo
- ansible
- puppet
platforms
suites
- テストスイート
- runlistやattributeを記述する
instance
テストに使うVMはinstanceと呼ばれます。
命名規則は suitesとplatforms に定義された名前になります。
例えばsuitesにapp01、platformsにcentos6.5と定義してあるとする。
この場合instanceの名前は app01-centos6.5 となります。
コマンド
$ kitchen create : インスタンスの起動を行う
$ kitchen setup : インスタンスにchefとbusserをインストールする
$ kitchen converge : 収束、なのでchefのrecipeを適用させる
$ kitchen verify : テストを実行
$ kitchen destroy : インスタンスを破棄
$ kitchen test : 上記の全ステップを一気に実行する
テスト
serverspecを使います。testを置くファイルパスは
CHEF_REPO/test/integration/SUITES_NAME/TESTING_FRAMEWORK/
なので、
CHEF_REPO/test/integration/app01/serverspec/
となり、このディレクトリ以下の、*_spec.rbが読み込まれます。
流れ
全体的な流れは以下のような感じ。 今回はDriverはvagrant、Provisionerはchef-solo、OSはcentos 6.5を使い、テストはserverspecにします。
まずは仮想マシンの準備。
$ vi .kitchen.yml
--- driver: name: vagrant provisioner: name: chef_solo platforms: - name: centos-6.5 suites: - name: default run_list: attributes:
以下のコマンドで状態を確認できます。
$ bundle exec kitchen list Instance Driver Provisioner Last Action default-centos-65 Vagrant ChefSolo <Not Created>
Last Action でマシンがどんな状態なのが把握できます。
仮想マシンを立ち上げます。
vagrantでいうところのvagrant upです。
$ bundle exec kitchen create default-centos-65
-----> Starting Kitchen (v1.3.1)
-----> Creating <default-centos-65>...
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'opscode-centos-6.5'...
==> default: Matching MAC address for NAT networking...
==> default: Setting the name of the VM: default-centos-65_default_1422170919471_91104
中略
Vagrant instance <default-centos-65> created.
Finished creating <default-centos-65> (0m57.51s).
-----> Kitchen is finished. (0m58.05s)
$ bundle exec kitchen list Instance Driver Provisioner Last Action default-centos-65 Vagrant ChefSolo Created
Last ActionがCreatedになりました。
これで仮想マシンの準備ができたのでrecipeを書きます。
$ vi cookbooks/zsh/recipes/default.rb
package 'zsh'
.kitchen.ymlにrecipeを追記
$ vi .kitchen.yml
--- driver: name: vagrant provisioner: name: chef_solo platforms: - name: centos-6.5 suites: - name: default run_list: - recipe[zsh::default] attributes:
converge でrecipeを仮想マシンに適用させます。chefでいうところのcookです。
$ bundle exec kitchen converge default-centos-65
-----> Starting Kitchen (v1.3.1)
-----> Converging <default-centos-65>...
Preparing files for transfer
Preparing dna.json
Preparing cookbooks from project directory
Removing non-cookbook files before transfer
Preparing data_bags
Preparing environments
Preparing roles
Preparing solo.rb
-----> Installing Chef Omnibus (install only if missing)
downloading https://www.chef.io/chef/install.sh
to file /tmp/install.sh
trying wget...
Downloading Chef for el...
downloading https://www.chef.io/chef/metadata?v=&prerelease=false&nightlies=false&p=el&pv=6&m=x86_64
to file /tmp/install.sh.2231/metadata.txt
trying wget...
url https://opscode-omnibus-packages.s3.amazonaws.com/el/6/x86_64/chef-12.0.3-1.x86_64.rpm
md5 3634d1a3b6ae2e5977361075da0f44cc
sha256 0ec6162b9d0ca2b2016ff02781d84905f712d64c7a81d01b0df88f977832f310
downloaded metadata file looks valid...
downloading https://opscode-omnibus-packages.s3.amazonaws.com/el/6/x86_64/chef-12.0.3-1.x86_64.rpm
to file /tmp/install.sh.2231/chef-12.0.3-1.x86_64.rpm
trying wget...
Comparing checksum with sha256sum...
Installing Chef
installing with rpm...
警告: /tmp/install.sh.2231/chef-12.0.3-1.x86_64.rpm: ヘッダ V4 DSA/SHA1 Signature, key ID 83ef826a: NOKEY
準備中... ########################################### [100%]
1:chef ########################################### [100%]
Thank you for installing Chef!
Transferring files to <default-centos-65>
Starting Chef Client, version 12.0.3
Compiling Cookbooks...
Converging 1 resources
Recipe: zsh::default
- install version 4.3.10-9.el6 of package zsh
Running handlers:
Running handlers complete
Chef Client finished, 1/1 resources updated in 2.158589696 seconds
Finished converging <default-centos-65> (2m57.70s).
-----> Kitchen is finished. (2m58.26s)
- chefが対象のホストに入っていなければomnibusインストールしてくれます
$ bundle exec kitchen list Instance Driver Provisioner Last Action default-centos-65 Vagrant ChefSolo Converged
Convergedになりました。
次にテストを追加します。
$ mkdir -p test/integration/default/serverspec/
$ vi test/integration/default/serverspec/zsh_spec.rb
require 'serverspec' set :backend, :exec describe package 'zsh' do it { should be_installed } end
verifyでテストを実行します。
$ bundle exec kitchen verify default-centos-65
-----> Starting Kitchen (v1.3.1)
-----> Verifying <default-centos-65>...
Removing /tmp/busser/suites/serverspec
Uploading /tmp/busser/suites/serverspec/zsh_spec.rb (mode=0644)
-----> Running serverspec test suite
/opt/chef/embedded/bin/ruby -I/tmp/busser/suites/serverspec -I/tmp/busser/gems/gems/rspec-support-3.1.2/lib:/tmp/busser/gems/gems/rspec-core-3.1.7/lib /opt/chef/embedded/bin/rspec --pattern /tmp/busser/suites/serverspec/\*\*/\*_spec.rb --color --format documentation --default-path /tmp/busser/suites/serverspec
Package "zsh"
should be installed
Finished in 0.12178 seconds (files took 0.37162 seconds to load)
1 example, 0 failures
Finished verifying <default-centos-65> (0m2.73s).
-----> Kitchen is finished. (0m3.23s)
- これはtestディレクトリを対象ホストへアップロード後、busser経由でserverspecをインストールしテストを実行してくれます。
$ bundle exec kitchen list Instance Driver Provisioner Last Action default-centos-65 Vagrant ChefSolo Verified
状態がVerifiedになりました!
この後はconvergeとverifyを繰り返してrecipeを作成し、完成したらdestroyで仮想マシンを破棄します。
$ bundle exec kitchen destroy default-centos-65
-----> Starting Kitchen (v1.3.1)
-----> Destroying <default-centos-65>...
==> default: Forcing shutdown of VM...
==> default: Destroying VM and associated drives...
Vagrant instance <default-centos-65> destroyed.
Finished destroying <default-centos-65> (0m6.84s).
-----> Kitchen is finished. (0m7.87s)
よいと思ったところ
- テスト対象のマシンの面倒を見てくれるのが良い
- 設定ファイルが.kitchen.ymlひとつ
- nodes/hostname.json を用意しなくていい
- Vagrantfileを用意しなくていい
- どのdriverやprovisionerを使ってもコマンドは同じ
- 今回はvagrantとchefを利用しましたが、ec2やpuppetを使っても
createとconverge
- 今回はvagrantとchefを利用しましたが、ec2やpuppetを使っても
あとはこれをそのままjenkinsやCircleCI上で実行できるようにすればcookbook単位のCIも可能ですね。
逆にあるserviceのサーバ構成全体をこれで管理しようとすると、
nodes/hostname.jsonと.kitchen.ymlにrecipeの定義が分散してしまって二重管理になりあまり良くない感じでした。