Packer + Serverspecでテスト済み仮想マシンイメージを自動で生成する

2014/11/30

Packerを使うと、VagrantやVMware、Amazon EC2用のAMIなどなどのさまざまな仮想マシンのテンプレートを簡単に作成することが出来るのはご存知の通りです。

一方で作成した仮想マシンのテンプレートが必要な要件を満たしているかどうかは、仮想マシンのテンプレートを作るたびに検査しなければなりません。

ここでは、PackerとServerspecを組み合わせて、仮想マシンのテンプレートを作成する際に、テストも併せておこなう方法について解説します。

前提

今回仮想マシンのテンプレートを作成するにあたっては以下の方式で行ないます。

  • Packer 0.7.2
  • Packerでの仮想マシンの設定ではChef-SoloのProvisionerを利用
  • CookbookはBerkshelfを使って管理する
  • 作るテンプレートはDocker用のもの(但し他のものでもほとんど変わりません)

また、方式としては、仮想マシンが起動されて、各種セットアップや設定が終わったあとに、その仮想マシン内でServerspecを動作させます。つまり、Packerで仮想マシン内にテスト用のSpecファイルを転送したり、仮想マシン内でServerspecが動作するように設定する必要がある、ということになります。

処理の流れ

ここまでの方式を処理の流れにすると以下のようになります。

  • 予めBerksfileを用意しておき、導入したいCookbookを準備する
  • テンプレート生成の土台となる仮想マシンを起動する
  • Chef-Soloがインストールされていない場合はインストール
  • run_listに記載した内容に従ってクックブックを適用する
  • 別で用意しておいたテスト用のSpecファイルを転送する
  • 仮想マシン内でServerspecが動作する環境を用意する
  • 仮想マシン内でServerspecを実行する
  • これらが正常に終わったら仮想マシンからテンプレートを生成し、仮想マシンを破棄する

Berksfileの準備

BerksfileとはChefのCookbookを管理するBerkshelf用の設定ファイルです。 以下のような内容になります。

ここでは、導入するCookbookのバージョンやタグを細かく設定しています。これは仮想マシンのテンプレートを後から追跡するときに、どのバージョンのCookbookを利用したのかを把握できるようにしておいた方が良いためです。

source "https://supermarket.getchef.com"

cookbook 'yum', '3.5.1'
cookbook 'apache2-simple', :git => 'git://github.com/ryuzee-cookbooks/apache2-simple.git', ref:"c47d08933d16020f002fdf802ee32a8681c4db66"
cookbook 'memcached', :git => 'git://github.com/ryuzee-cookbooks/memcached.git', ref:"6f32a279cfff3c189a7d16ac3472b77299ce93da"
cookbook 'timezone', :git => 'git://github.com/ryuzee-cookbooks/timezone', ref:"bb758452e4efb83d5608eb51597be0ecc84ec185"
cookbook 'ca-certificates', :git => 'git://github.com/ryuzee-cookbooks/ca-certificates', tag: "v0.1.0"

ここまで出来たら、

berks vendor cookbooks

として、ローカル環境にCookbookをダウンロードしておきます。

仮想マシンの起動とプロビジョニング

通常テストなしでテンプレートを作成する場合はこれで準備は終わりです。 ここまででビルドするためには、以下のような、jsonファイルを用意します。

内容自体は特に特筆すべき点はありません。

  • 冒頭で作成する仮想マシンの種類を設定します。ここではDockerを使います。元となるイメージはここでは自作のものを使っていますが、適宜変えてください。
  • provisionersの箇所では仮想マシンの設定をどのようにおこなうかを設定します。ここではChef Soloを使っています。また利用するCookbookは先ほどBerkshelfを使って手元に用意したものを使い、run_listの箇所で適用するCookbookを、jsonの箇所で適宜Attributeを指定しています。
  • post-processorsの箇所では、プロビジョニングなどが終わったあとの処理を指定しており、ここでは最後にDockerのイメージを作成しています。
{
  "builders": [{
    "type": "docker",
    "image": "ryuzee/centos_chef:6.4",
    "run_command": ["-d", "--hostname=packer-sample", "-i", "-t", "{{.Image}}", "/bin/sh"],
    "export_path": "image.tar"
  }],

  "provisioners":[
  {
    "type": "chef-solo",
    "cookbook_paths": ["./cookbooks/"],
    "run_list": ["ca-certificates", "timezone", "apache2-simple", "memcached"],
    "json": {"memcached":{"maxcon":"512","cachesize":"512"}},
    "prevent_sudo": true,
    "skip_install": false 
  }
  ],
  "post-processors": [{
    "type": "docker-import",
    "repository": "ryuzee/packer-sample",
    "tag": "0.1"
  }]
}

ここまで出来たら、

packer build docker.json

のようにして仮想マシンを作成します。

Serverspecによるテストを組込み

ここからが肝です。まずChef Soloのプロビジョニングが終わったら、Serverspecが実行できるように準備します。 ここでは、Shell Provisionerを使います。

以下のようなスクリプトを用意し、scripts/serverspec.shに保存してください。

当たり前ですが、Serverspecの動作にはRubyが必要です。Rubyを仮想マシンにインストールしても良いのですが、既にChef Soloを動かすために、/opt/chef/embedded/bin以下にRubyがインストールされていますので、これを使うように設定します。

#!/bin/bash
export PATH=/opt/chef/embedded/bin:$PATH
cd /tmp/tests
bundle install --path=vendor
bundle exec rake spec

また実際のテストやRakefileを用意しないといけませんので、testsディレクトリを作成し、GemfileRakefile.rspec、そして実際のテストを用意します。

Gemfile

source "https://rubygems.org"

gem "rake"
gem "serverspec"

Rakefile

require 'rake'
require 'rspec/core/rake_task'

RSpec::Core::RakeTask.new(:spec) do |t|
  t.pattern = 'spec/*/*_spec.rb'
end

spec/spec_helper.rb

require 'serverspec'

set :backend, :exec

spec/localhost/sample_spec.rb

require 'spec_helper'

describe package('httpd'), :if => os[:family] == 'redhat' do
  it { should be_installed }
end

describe service('httpd'), :if => os[:family] == 'redhat' do
  it { should be_enabled }
  it { should be_running }
end

describe port(80) do
  it { should be_listening }
end

.rspec

--format documentation

ここまで出来たら、先ほど用意したpacker用のjsonを以下のように変更しましょう。 追加したのは、テスト関連のファイルを仮想マシン側の/tmp/testsに転送する処理と、用意したscripts/serverspec.shを動作させる箇所です。

{
  "builders": [{
    "type": "docker",
    "image": "ryuzee/centos_chef:6.4",
    "run_command": ["-d", "--hostname=packer-sample", "-i", "-t", "{{.Image}}", "/bin/sh"],
    "export_path": "image.tar"
  }],

  "provisioners":[
  {
    "type": "chef-solo",
    "cookbook_paths": ["./cookbooks/"],
    "run_list": ["ca-certificates", "timezone", "apache2-simple", "memcached"],
    "json": {"memcached":{"maxcon":"512","cachesize":"512"}},
    "prevent_sudo": true,
    "skip_install": false 
  },
  {
    "type": "file",
    "source": "tests",
    "destination": "/tmp"
  },
  {
    "type": "shell",
    "script": "scripts/serverspec.sh"
  }
  ],
  "post-processors": [{
    "type": "docker-import",
    "repository": "ryuzee/packer-sample",
    "tag": "0.1"
  }]
}

ここまでの作業のディレクトリ構成は以下のようになっているはずです。

.
├── Berksfile
├── Gemfile
├── docker.json
├── scripts/
│  └── serverspec.sh
└── tests/
    ├── .rspec 
    ├── Gemfile
    ├── Rakefile
    └── spec/
        ├── localhost/
        │  └── sample_spec.rb
        └── spec_helper.rb

ここまで出来たら、仮想マシンをビルドしましょう。いつも通り以下のような形でOKです。もしデバッグログが見たい場合は、PACKER_LOG=1を設定してください。

packer build docker.json

ビルドすると、以下のように、Serverspecによるテストが実行されることが分かります!

出力結果

(おまけ) Cookbookに含まれているテストをまとめて実行する方法

この手順を応用すると、利用したCookbookに含まれているテストを全部一気に実行することが出来ます。

やり方は簡単です。Chef Soloプロビジョナーでは、/tmp/packer-chef-solo/cookbooks-0などにCookbookを転送します。従ってこのディレクトリ全体の中の*_spec.rbをテスト実行の対象にすれば良いわけです。 (なお、このパスは元のjsonの設定によって変わります)

require 'rake'
require 'rspec/core/rake_task'

RSpec::Core::RakeTask.new(:spec) do |t|
  t.pattern = '/tmp/packer-chef-solo/cookbooks-0/**/*_spec.rb'
end

これで仮想マシンのテンプレートを作成する際に全部のテストを改めてまとめて実行することもできます。



2014/11/30

著作

CakePHPで学ぶ継続的インテグレーション

著者/訳者:渡辺 一宏 吉羽 龍太郎 岸田 健一郎 穴澤 康裕

出版社:インプレス( 2014-09-19 )

定価:¥ 4,320


Chef実践入門 ~コードによるインフラ構築の自動化 (WEB+DB PRESS plus)

著者/訳者:吉羽 龍太郎 安藤 祐介 伊藤 直也 菅井 祐太朗 並河 祐貴

出版社:技術評論社( 2014-05-22 )

定価:¥ 2,992


SCRUM BOOT CAMP THE BOOK

著者/訳者:西村直人 永瀬美穂 吉羽龍太郎

出版社:翔泳社( 2013-02-13 )

定価:¥ 2,520


Software in 30 Days スクラムによるアジャイルな組織変革“成功"ガイド

著者/訳者:Ken Schwaber、Jeff Sutherland著、角征典、吉羽龍太郎、原田騎郎、川口恭伸訳

出版社:アスキー・メディアワークス( 2013-03-08 )

定価:¥ 1,680


How to Change the World 〜チェンジ・マネジメント3.0〜

著者/訳者:Jurgen Appelo, 前川哲次(翻訳), 川口恭伸(翻訳), 吉羽龍太郎(翻訳)

出版社:達人出版会

定価:500円

どうすれば自分たちの組織を変えられるだろう?それには、組織に変革を起こすチェンジ・マネジメントを学習することだ。アジャイルな組織でのマネージャーの役割を説いた『Management 3.0』の著者がコンパクトにまとめた変化のためのガイドブック


寄稿

実践 Vagrant

著者/訳者:Mitchell Hashimoto

出版社:オライリージャパン( 2014-02-21 )

定価:¥ 2,808


Ryuzeeについて
Certified Scrum Professional (CSP) / CSM / CSPO in Japan. Twitterアカウントは@ryuzee →サイトが役立ったのでお布施する!

タグ
diary delphi books 書評 trac agile php apache インストールマニアックス maniax iis mysql postgresql perl sqlserver ruby オープンソース wordpress agilo scrum cakephp ユニットテスト yyyayeyaey publication tram 組織 linux プロダクトバックログ リーン ストーリーポイント ベロシティ ストーリー テスト 事例 契約 オフショア 管理職 スクラムマスター プロダクトオーナー デイリースクラム ふりかえり 受託開発 見積もり コーチ リーダー yyyoyy zen xp アンチパターン 可視化 doneの定義 recommended レビュー kaltrua vmware 自動化 fixture hudson 継続的インテグレーション kanban スプリント スクラム道 リリースプランニング カバレージ subversion scrum-of-scrum netbeans 朝会 バーンダウンチャート 調査結果 コミット devlove チーム bdd selenium アジリティ スプリント0 フィードバック ユーザーストーリー tdd sprint task スプリントレビュー スプリント計画会議 scrum-boot-camp scrumbc alm 継続的デリバリー ci user-story migration vagrant product-owner 継続的デプロイ continuous-delivery continuous-deploy continuous-integration jenkins デプロイ どうでもよいこと 日記 centos vim test commitment movie コードレビュー devops リリース 登壇 スコープ 評価 プランニングポーカー 見積り done ready agile-buffet agile-japan 講演 azure team-foundation-server team-foundation-service tfs 導入 eclipse visual-studio microsoft 技術的負債 defects lean daily-scrum grooming scrum-boot-camp-premium git ubuntu homeserver 監視 chef aws sahara packer lxc serverspec sensu dashing capistrano graphite 寿司 grafana docker slack deploy AWS Packer