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


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

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

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

handson用コード
概要説明資料

Ansibleとは


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

TestKitchenとは


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

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

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

Ansible + TestKitche (infraTDDゴール)

事前準備(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

ハンズオン実施流れ

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

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

虎の巻として以下を展開

ansible tasks/main.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記法

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でよく使うテストの書き方まとめ

Ansibleのテストをtest-kitchenとServerspec、dockerで行う