Chefとserverspecでサーバ構築とテストをプログラマブルにできるようになったため、Jenkinsによりサーバ構築からテストまでを自動化してみました。
やりたいこと
以下のように、Chefのリポジトリの更新をトリガーに、サーバ構築からテストまでをJenkinsにて自動化します。
- Chefのレシピをリモートリポジトリへgit pushすると、Jenkinsが通知を検知
- JenkinsからChefを実行し、サーバを構築
- サーバの構築が正常終了すれば、Jenkinsからserverspecを実行し、サーバの状態をテスト
構成
CentOS 6.5 : Chef、serverspec、Jenkins、Gitをインストール
Ubuntu 12.04 : サーバ構築、テスト対象
※上記2台のサーバはVMware ESXi 5.1上で動作しています。
設定
各ソフトウェアの設定について説明していきます。
※SSH認証の設定は完了しているものとします。
Chef
まず、Chefのリポジトリを作成します。
$ knife solo init chef-repo
サーバ構築用のcookbookを作成します。
今回は、apache2をインストールするレシピを用意します。
$ cd chef-repo/ $ knife cookbook create apache2 -o site-cookbooks $ vi site-cookbooks/apache2/recipes/default.rb # Apacheをインストール # sudo apt-get -y install apache2 package "apache2" do action :apache2 end
JSONファイルが作成されるため、実行するapache2のcookbookを指定します。
$ vi nodes/<サーバのIPアドレス>.json { "run_list":[ "recipe[apache2]" ] }
serverspec
Chefのrootディレクトリに移動し、serverspecの初期設定を行います。
$ cd chef-repo/ $ serverspec-init Select OS type: 1) UN*X 2) Windows Select number: 1 #UN*Xを選択 Select a backend type: 1) SSH 2) Exec (local) Select number: 1 #SSHを選択 Vagrant instance y/n: n #nを選択 Input target host name: 192.168.xxx.xxx #テスト対象サーバのIPアドレスを指定 + spec/ + spec/192.168.xxx.xxx/ + spec/192.168.xxx.xxx/httpd_spec.rb + spec/spec_helper.rb + Rakefile
apache2がインストールされているか確認するテストコードを書きます。
$ mv spec/192.168.xxx.xxx/httpd_spec.rb spec/192.168.xxx.xxx/apache2_spec.rb $ vi spec/192.168.xxx.xxx/apache2_spec.rb require 'spec_helper' describe package('apache2') do it { should be_installed } end
Git
Chef・serverspec用のリモートリポジトリを作成します。
$ mkdir /var/lib/git $ mkdir /var/lib/git/chef-cookbooks.git $ cd /var/lib/git/chef-cookbooks.git $ git --bare init
Chef・serverspec用のローカルリポジトリを作成します。
chef-repoのディレクトリに移動し、リポジトリの初期化を行い、ローカルリポジトリを作成します。
リモートリポジトリには何も入っていないため、ローカルリポジトリの内容を追加します
$ cd chef-repo/ $ git init $ git add . $ git commit -m "first commit" $ git remote add origin /var/lib/git/chef-cookbooks.git $ git push origin master
Jenkins
Jenkinsでのジョブは、jenkinsユーザにより実行されるため、パスワードなしでsudoを実行する設定を入れておきます。
$ visudo jenkins ALL=(ALL) NOPASSWD: ALL # ←最終行に追加
Jenkinsにログイン後、[新規ジョブの作成]をクリックし、ジョブ名とビルドを設定します。
以下のように設定を入れ、[OK]をクリックします。
- ジョブ名: chef-cookbooks
- フリースタイル・プロジェクトのビルド オン
上記で作成したリポジトリと連携するため、[ソースコード管理]を以下のように設定します。
- ソースコード管理
- Git オン
- Repositories
- Repository URL: /var/lib/git/chef-cookbooks.git
- Credentials: なし
- Branches to build
- Branch Specifier (blank for 'any'): */master
リポジトリのgit pushを検知するために、[ビルド・トリガ]を以下のように設定します。
- ビルド・トリガ
- SCMをポーリング チェック
- スケジュール 下記に記載
- post-commitフックを無視 チェックオフ
- SCMをポーリング チェック
スケジュールはcronのように設定できます。
今回は、15分毎にチェックが走るように、以下のように設定します。
H/15 * * * *
Chefとserverspecのコマンドを実行するために、[ビルド手順を追加]>[シェルの実行]をクリックし、[シェルの実行]を以下のように設定します。
- ビルド
- シェルの実行
sudo /root/.rbenv/shims/knife solo bootstrap <ユーザ名>@192.168.xxx.xxx sudo /root/.rbenv/shims/rake spec
※bootstrapはprepareとcookを同時に実行するオプションです。
上記の設定ができたら、[保存]をクリックします。
実行
以下のように、Chefのファイルを修正後、commitし、git pushを実行します。
$ cd chef-repo/ $ vi site-cookbooks/apache2/recipes/default.rb $ git add . $ git commit -m "first commit" $ git push origin master
スケジュールのタイミングによりgit pushの通知が検知されます。
通知を検知すると、JenkinsのワークスペースにChefのリポジトリがコピーされます。
ジョブが実行されたら、[ジョブ名]>[ビルド履歴]>[ビルド番号]へ移動し、[コンソール出力]をクリックします。ジョブが正常終了すれば、コンソール出力の末尾に「Finished: SUCCESS」と表示されます。
以下は、Chefとserverspecの実行が正常終了していることを示しています。
SCMのポーリングが実行 ビルドします。 ワークスペース: /var/lib/jenkins/workspace/chef-cookbooks Fetching changes from the remote Git repository Fetching upstream changes from /var/lib/git/chef-cookbooks.git Checking out Revision 187f8b995de5ddc053a18a3d114f1aa5018f1979 (origin/master) [chef-cookbooks] $ /bin/sh -xe /tmp/hudson7478251361203469042.sh + sudo /root/.rbenv/shims/knife solo bootstrap <ユーザ名>@192.168.xxx.xxx Running Chef on 192.168.xxx.xxx... Checking Chef version... : Running handlers complete [0m Chef Client finished, 1/1 resources updated in 8.041423413 seconds[0m + sudo /root/.rbenv/shims/rake spec /root/.rbenv/versions/2.0.0-p451/bin/ruby -S rspec spec/192.168.xxx.xxx/httpd_spec.rb . Finished in 0.10092 seconds 1 example, 0 failures Finished: SUCCESS
実行が失敗した場合は、以下のようにエラーが表示され、そこでJenkinsのジョブは停止します。
Build step 'シェルの実行' marked build as failure Finished: FAILURE
Chefの実行で失敗した場合は、serverspecは実行されないため、正常終了すればサーバ構築からテストまですべて終了したことになります。
おわりに
今回構築した環境は、共同でChefのレシピやserverspecのテストコードを書くフローを想定していました。各メンバーは、PCでChefやserverspecのコードを作成後、VirtualBoxでテストし、問題がなければリモートリポジトリへgit pushします。リモートリポジトリへgit pushすれば、後はJenkinsがサーバ構築からテストまでを自動で行い、正常終了すれば本番環境へ適用するといった流れです。ただし、今回の環境ではテスト環境をクリアすることは含まれていないため、スナップショットを手動で戻してやる手間が残ってしまいました。
次回は、このあたりの問題を解決していきたいと考えてます。