インフラエンジニアのCI事始め

# はじめに
全世界数億人のインフラエンジニアの皆々様、CIサーバーを利用しているでしょうか？
自分は1年半前くらいまで利用せずに、自分のPCにて `knife solo cook [vagrant]` みたいなことをやっていました。
ですが、手元のPCのファンがうるさくなったり熱くなったりするのに嫌気がさして基本的には利用することをやめ、jenkinsおじさんに基本的にお任せすることにしました。
そもそも、自分の手元で実行したものが他人の環境でも同じように動くかどうかわからないですし。
ということで、自分がchef/ansibleなどのプロビジョニングツールを利用する際にどのようにjenkinsを利用してるかを書いていきたいと思います。


# やっていること
とはいえ、やっていることはそんなに難しくなく、下記の２つくらいです。
1. pushされたら、webhookを利用してjenkinsサーバーでvagrantを立ち上げて、vagrantに対してプロビジョニングするjobを登録する。
2. GitHub pull request builder pluginを利用して、pull requestが送られたらjenkinsサーバーでvagrantを立ち上げて、vagrantに対してプロビジョニングするjobを登録する。

## webhookを利用する
```
fork元：infra/hoge-(cookbooks|playbooks)
↓
fork先：eigo-s/hoge-(cookbooks|playbooks)
```
このように、複数人でプロジェクトのcookbookやplaybookを触ることを想定して、forkした先でコードを書いています。
ブランチはfork先にdevelopブランチを切り、developブランチにpushされたら、jenkinsで下記のようなシェルスクリプトが実行されるようにしています。

```bash:dev_tester.sh
#!/bin/sh

## WORKSPACEにcdし、developブランチに切り換え
cd $WORKSPACE
git checkout develop

## Vagrantfileを配置し、boxを立ち上げ、ssh-configをファイルに吐き出す
cp $WORKSPACE/vagrantfiles/Vagrantfile.sample ./Vagrantfile
vagrant up
vagrant ssh-config --host=cheftest > vagrant-ssh.conf

## bootstrap実行＆admin用アカウント作成
knife solo bootstrap cheftest nodes/create_admin.json -F vagrant-ssh.conf

## 実行させたいコンポーネントに切り替えてchefの実行を行う
knife solo cook cheftest nodes/web_hostname.json -F vagrant-ssh.conf  -V || RET=$?
#knife solo cook cheftest nodes/api_hostname.json -F vagrant-ssh.conf -V || RET=$?
#knife solo cook cheftest nodes/manage_hostname.json -F vagrant-ssh.conf -V || RET=$?
#knife solo cook cheftest nodes/jenkins_hostname.json -F vagrant-ssh.conf -V || RET=$?
#knife solo cook cheftest nodes/redis_hostname.json -F vagrant-ssh.conf -V || RET=$?
#knife solo cook cheftest nodes/master_db_hostname.json -F vagrant-ssh.conf -V || RET=$?
#knife solo cook cheftest nodes/slave_db_hostname.json -F vagrant-ssh.conf -V || RET=$?
#knife solo cook cheftest nodes/zabbix_hostname.json -F vagrant-ssh.conf -V || RET=$?

## chefの実行可否を判定
if [ -z ${RET} ] ; then
  vagrant destroy -f
else
  vagrant destroy -f
  exit ${RET}
fi
```

webhookでは、このように開発/本番環境でのコンポーネントを想定して切り替えつつjobを走らせています。
※本当はもっとスマートなやり方ありそうだなぁ、、、と思いつつ、この方法に落ち着いてしまっております(◞‸◟)


## GitHub pull request builder pluginを利用する
ある程度fork先でコードが出来上がったら、fork元に対してpull requestを送ります。
GitHub pull request builder pluginでは、下記のようなスクリプトを実行し、開発チームの方々のlocalVMをあわせて作成する、といったことをしています。


```bash:local_tester.sh
## WORKSPACEにcdし、developブランチに切り換え
cd $WORKSPACE
git checkout develop

## Vagrantfileを配置し、boxを立ち上げ、ssh-configをファイルに吐き出す
cp $WORKSPACE/vagrantfiles/Vagrantfile.sample ./Vagrantfile
vagrant up
vagrant ssh-config --host=cheftest > vagrant-ssh.conf

## bootstrap実行＆admin用アカウント作成
knife solo bootstrap cheftest nodes/create_admin.json -F vagrant-ssh.conf

## localVM向けchef実行
knife solo cook cheftest nodes/local_web.json -F vagrant-ssh.conf -V || RET=$?

## 成功したら、box容量を小さくするためにゴミ掃除をしつつboxを作成する
if [ -z ${RET} ] ; then
  ssh cheftest -F vagrant-ssh.conf "rm -f /etc/udev/rules.d/70-persistent-net.rules"
  ssh cheftest -F vagrant-ssh.conf "sudo yum clean all"
  ssh cheftest -F vagrant-ssh.conf "rm -rf /tmp/*"
  ssh cheftest -F vagrant-ssh.conf "rm -rf /home/vagrant/chef-repo/"
  ssh cheftest -F vagrant-ssh.conf "rm -f ~/.bash_history"
  vagrant halt -f
  vagrant package --output local-web.box
  rm -f /var/lib/jenkins/userContent/local-web-old.box
  mv -f /var/lib/jenkins/userContent/local-web.box /var/lib/jenkins/userContent/local-web-old.box
  mv -f local-web.box /var/lib/jenkins/userContent/
  vagrant destroy -f
else
  vagrant destroy -f
  exit ${RET}
fi
```

ここでlocalVMを作っているのは、localVMが複数コンポーネントが相乗りしてることの方が
大半のプロジェクトで開発体制的に多いため、複数コンポーネントのchef実行テストも兼ねています。


# 気をつけていること
## vagrant boxについて
jenkinsで立ち上げているvagrant boxですが、自分でpackerを利用してboxの作成しています。
弊社では、PXEサーバーを利用してOSインストールを行うことが多いのですが、
このpackerテンプレートで利用するkickstartファイルと開発/本番環境で利用するkickstartファイルをOSインストール時にインストールされているパッケージは同じようにして、
プロビジョニングツール実行前のOSインストール後にはほぼ同じ構成(パーティション周りとか以外)になるようにしておきます。
そうすることで、実際の環境構築時の手戻りをなくすことや開発チームのlocalVMの環境差異を極力なくすことを意識しています。


# ということで
以上が自分のjenkinsおじさんの利用方法でした。
本来は、chefやansibleをvagrantに対して実行したあとに、serverspecを流してテストも行えると良いのですが、
まずは事始め的な感じで気軽にjenkinsおじさんを利用して、自分の書いたコードが正しく実行されるかどうかを試してみてはいかがでしょうか？