Ansible + TestKitchen (Serverspec) for Docker（初級者向け）

## Ansible + TestKitchen for Docker　社内ハンズオン

**ターゲット：Ansibleを始めて利用する方向け**

今回、社内でAnsible + TestKitchenを使った、インフラのテスト駆動開発handsonを実施しました。
その内容を公開いたします。

[handson用コード](https://github.com/vSakumoto/ansible_hands_on)
[概要説明資料](http://www.slideshare.net/xshsaku/ansibleinfratdd)
## Ansibleとは
---

一言で**「エージェントレスで手軽に利用出来る構成管理ツール」**で
**Chef/Puppet/Itamae**など様々あるプロビジョナーと並ぶツールです。

## TestKitchenとは
---

こちらは主にテスト環境への構成のプロビジョニングと構成管理が正しく実装されているかをチェックするためのツールです。
様々なプロビジョナーと連携しつつ、構成管理対象のターゲットをvagrant / dockerなど適用できるため、今回採用しました。

## 今回のハンズオンでやったこと

AnsibleとTestkitchenを用いてインフラのコード化及びTDDを実践する
テスト実行環境はDocker / 本番環境はあらかじめOpenStack上に作成したUbuntu 14.04のサーバーにて実行をする

### Ansible + TestKitche (infraTDDゴール）

<img width="530" alt="インフラTDDゴール" src="https://qiita-image-store.s3.amazonaws.com/0/93976/34a70c5f-e087-703f-ad49-bc3b3a1ab251.png">


## 事前準備（Mac 環境構築)

```
$ bundler -v
Bundler version 1.12.5
$ ruby -v
ruby 2.1.5
$ docker -v
Docker version 1.12.0-rc2
または
Docker version 1.11.2
```

前提として ruby 2.1.1<で話を進めていくため、以下を事前にインストールすることを推奨とする(Mac) 
※gemの関係上provisionerにansible_playbookが認識できない事象あり

```
$ brew update
$ brew install rbenv ruby-build
$ brew update
$ brew install rbenv ruby-build　（もしくは、brew update rbenv ruby-build）

$ rbenv install 2.1.5
$ rbenv global 2.1.5
$ rbenv rehash

# PATH に追加
$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile

# .bash_profile に追加
$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile

# 上記設定の再読み込み
$ exec $SHELL -l

$ ruby -v
ruby 2.1.5p273 (2014-11-13 revision 48405) [x86_64-darwin14.0]

$ rbenv exec gem install bundler
Bundler version 1.12.5
```

## Dockerインストール

```
$ brew cask install virtualbox
$ brew install docker
$ brew install docker-machine
$ docker -v
Docker version 1.11.2, build b9f10c9

# 初期設定
$ docker-machine create -d virtualbox ansible-hands-on
$ eval $(docker-machine env ansible-hands-on)
# VPNソフトを起動しているとエラーが出る場合があるよ！FAQ参照
```

## ansibleインストール！

```
$ brew install ansible
$ git clone https://github.com/vSakumoto/ansible_hands_on.git ~/ansible
$ cd ~/ansible
$ bundle install
```

## ハンズオン実施流れ

うちの会社では以下の流れで実施しました

```text:
1. 概要資料の説明
2. gitからcloneしていただいたplaybookを実行して、DockerでのTDD及びstaging環境へのプロビジョニング実施
3. git clone ファイルを編集し、実際にtasksを書き換え　パッケージの追加・テスト及びstaging環境へのプロビジョニングを実施する
```

虎の巻として以下を展開

ansible tasks/main.yml

```yml:main.yml
--- #<- マジックメソッド！！　記述の際には必ず記述する
- name: HOGEHOGE INSTALL #<-- 1タスクを記述するディレクティブ設定
  apt: pkg=nginx state=present update_cache=yes #<-- apt-get install -y nginx を実施
  sudo: yes # sudoをつけて実行するかを選択記載なければssh接続設定となっているユーザーで実行
  tags: nginx # ansbile-playbook -i hoge -t nginxとすることで対象のタグのみを実行させることが可能 別用途としてはprd | stgなど切って本番|stgのプロビジョニングを変更するなど
  when: ansible_os_family == 'Ubuntu' # Ubuntu のみの場合に実施
  
- name: HOGEHOGE INSTALL
  yum: pkg=nginx state=present update_cache=yes
  sudo: yes
  when: ansible_os_family == 'RedHat' # RedHat系（CentOS)
  tags: nginx
  
# リポジトリ追加
- name: add php repo
  apt_repository: repo="ppa:ondrej/php5-5.6"
  tags: repo
  when: ansible_os_family == 'Ubuntu'
  sudo: yes
  
- name: Add repository
  yum_repository:
    name: epel
    description: EPEL YUM repo
    baseurl: http://download.fedoraproject.org/pub/epel/$releasever/$basearch/
   when: ansible_os_family == 'RedHat'
  
# ファイルコピー
- name: Upload Test File
  copy: src="bash_profile" dest="/home/vSakumoto/.bash_profile" owner=vSakumoto group=vSakumoto mode=0644
  tags: home_set
  sudo: yes
  
# ディレクトリ作成
- name: private directory
  file: path="/home/vSakumoto/foo" state=directory owner=vSakumoto group=vSakumoto mode=0700
  tags: home_set
  sudo: yes

```

serverspec記法

```ruby:webservers_spec.yml
require 'spec_helper'
 
describe package('nginx'), :if => os[:family] == 'ubuntu' do # os[:family]の環境変数からubuntu判定をし実行
  it { should be_installed } # package nginxがインストールされているか
end 
  
describe service('nginx'), :if => os[:family] == 'ubuntu' do
  it { should be_enabled } # 自動起動がONになっているか
  it { should be_running } # nginxが動作しているか
end
  
describe port(80) do
  it { should be_listening } # 指定ポートが空いているかどうか
end
  
# kitchen groupがあるか
describe group('kitchen') do
  it { should exist }
end
  
# kitchen userがいるか
describe user('kitchen') do
  it { should belong_to_group 'kitchen' }
end
  
# 配列でチェック
%w{vSakumoto xshsaku kitchen}.each do |users|
  describe user(users) do
    it { should belong_to_group users }
  end
end
  
# ファイル有無
describe file('/home/vSakumoto/.bash_profile') do
  it { should be_file }
end
  
# ディレクトリ有無
describe file("/home/vSakumoto/public_html") do
  it { should be_directory }
end
```

ハンズオン時間は約2hぐらいを目安にし、無事完了しました。

### ハンズオンを通して・・・
**インフラ屋さんももちろんだけども、プログラマの方にコードでインフラを「管理できる・構築できる」メリットを伝えられるいいチャンスかもしれない**


参考サイト：
[Serverspecでよく使うテストの書き方まとめ](http://qiita.com/minamijoyo/items/467ddd13c0cab15330bf)

[Ansibleのテストをtest-kitchenとServerspec、dockerで行う]
(http://qiita.com/minamijoyo/items/467ddd13c0cab15330bf)