PackerでChef適用済みAMIをサクッと作成する(chef-solo provisionerの活用)

2013.08.26

ども、大瀧です。Amazon EC2のテンプレートであるAMI(Amazon Machine Image)の作成が設定ファイルとコマンドラインで簡単にできる、Packerというツールを以前ご紹介しました。
その記事の後半で触れていたchef-solo provisioner(Chef連携機能)が、3日前にようやくmasterにマージされたので試してみました。

chef-solo provisionerとは

Packerは、AWS環境だとEC2インスタンスを作成し(下図1)、設定ファイル(Template)を元に一定の構成を行い(下図2)、そこから新たなAMIを作成できます(下図3)。

chef-solo provisionerは、下図2のEC2インスタンスの構成としてChefのインストールchef-soloによるcookbooks/recipeを実行する機能を持ちます。Packerおよびchef-solo provisionerは、ChefでEC2を管理するときの従来の懸念事項だった以下が解消できる画期的ソリューションになります!

  • Chefの1回目の実行が遅い(ソフトウェアのインストール/ビルドが行われるため)
  • あらかじめChefを1回実行したAMIを作ると、AMIの管理が煩雑になる(AMIは1つに統一したい、AMIのバージョンアップに追随したい)

packer02

1. ソースからPackerをビルドする

ビルド済みパッケージがリリースされました(バージョン0.3.5)!ダウンロードページからダウンロードし、通常のセットアップで導入できるようになりました。以下のビルド作業は不要です。

本日(2013/08/26)時点では、ビルド済みのリリースパッケージにはまだ含まれていないため、githubのソースから自分でビルドする必要があります。Packerのビルド手順はREADMEのDeveloping Packerを参照してください。GoとMercurialを事前にインストールしておく必要があります。

$ packer -v
Packer v0.3.5.dev (99dd3ccec5cf84659fced53f5c7b6a304263e03f)
$

2. Cookbookの準備

適用するChefのCookbookを準備します。といっても、Packer向けの特別な設定は必要ありません。今回はBerkshelfでnginxのCommunity Cookbookを用意しました。

$ ls cookbooks/nginx/
Berksfile        Gemfile.lock     TESTING.md       definitions/     metadata.rb
CHANGELOG.md     LICENSE          attributes/      files/           recipes/
CONTRIBUTING.md  README.md        chefignore       metadata.json    templates/
$ cat cookbooks/nginx/README.md | head -n 20
Description
===========

Installs nginx from package OR source code and sets up configuration
handling similar to Debian's Apache2 scripts.
 (略)
$

3. Templateの作成

では、chef-soloをProvisinerとして実行するためのPackerのTemplateを以下のように作成します。今回は、Amazon Linux 2013.03 64bit公式AMI(ami-39b23d38)を使用します。

packer.json

{
  "builders": [{
    "type": "amazon-ebs",
    "access_key": "XXXXXXXXXXXXXXXX",
    "secret_key": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "region": "ap-northeast-1",
    "source_ami": "ami-39b23d38",
    "instance_type": "t1.micro",
    "ssh_username": "ec2-user",
    "ssh_timeout": "5m",
    "ami_name": "packer-example {{timestamp}}"
  }],
 "provisioners": [{
    "type": "chef-solo",
    "cookbooks_paths": ["./cookbooks"],
    "recipes": ["nginx"],
    "json": {},
    "prevent_sudo": false,
    "skip_install": false
  }]
}

以下補足です。

  • 11行目の{{timestamp}}は、前回の記事で{{.CreateTime}}と記述していた箇所です。書き方が変わりました。
  • 14行目のtypeアトリビュートにchef-soloと記述し、chef-soloの設定を続けていきます。まだドキュメント化されていない部分なので、なんとなく読み取ってください(苦笑)。

4. Packerの実行

Templateができたら、いよいよPackerを実行します。EC2インスタンスの作成ログからchef-soloの実行結果、AMIの作成ログまで順に出力されていきます。

$ packer build packer.json
amazon-ebs output will be in this color.

==> amazon-ebs: Creating temporary keypair for this instance...
==> amazon-ebs: Creating temporary security group for this instance...
==> amazon-ebs: Authorizing SSH access on the temporary security group...
==> amazon-ebs: Launching a source AWS instance...
==> amazon-ebs: Waiting for instance (i-XXXXXXXX) to become ready...
==> amazon-ebs: Waiting for SSH to become available...
==> amazon-ebs: Connected to SSH!
==> amazon-ebs: Installing Chef Solo
    amazon-ebs: % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
    amazon-ebs: Dload  Upload   Total   Spent    Left  Speed
100  6790  100  6790    0     0   6980      0 --:--:-- --:--:-- --:--:--  8864--:--:--     0
    amazon-ebs: Downloading Chef  for el...
    amazon-ebs: Installing Chef
    amazon-ebs: warning: /tmp/tmp.IoOUBQU5/chef-.x86_64.rpm: Header V4 DSA/SHA1 Signature, key ID 83ef826a: NOKEY
    amazon-ebs: Preparing...                ########################################### [100%]
    amazon-ebs: 1:chef                   ########################################### [100%]
    amazon-ebs: Thank you for installing Chef!
==> amazon-ebs: Creating Chef configuration file...
==> amazon-ebs: Creating and uploading Chef attributes file
==> amazon-ebs: Copying cookbook path: ./cookbooks
==> amazon-ebs: Beginning Chef Solo run
    amazon-ebs: Starting Chef Client, version 11.6.0
    amazon-ebs: Compiling Cookbooks...
    amazon-ebs: Recipe: ohai::default
    amazon-ebs: * remote_directory[/etc/chef/ohai_plugins] action create
    amazon-ebs: - create new directory /etc/chef/ohai_plugins
    amazon-ebs: - change mode from '' to '0755'Recipe: <Dynamically Defined Resource>
    amazon-ebs: * cookbook_file[/etc/chef/ohai_plugins/README] action create
    amazon-ebs: - create new file /etc/chef/ohai_plugins/README
    amazon-ebs: - update content in file /etc/chef/ohai_plugins/README from none to 775fa7
    amazon-ebs: --- /etc/chef/ohai_plugins/README	2013-08-26 08:03:22.915209544 +0000
    amazon-ebs: +++ /tmp/.README20130826-3857-14m7zaz	2013-08-26 08:03:22.915209544 +0000
    amazon-ebs: @@ -0,0 +1 @@
    amazon-ebs: +This directory contains custom plugins for Ohai.
    amazon-ebs: - change mode from '' to '0644'
    amazon-ebs:
    amazon-ebs: Recipe: ohai::default
    amazon-ebs: * ohai[custom_plugins] action reload
    amazon-ebs: - re-run ohai and merge results into node attributes
    amazon-ebs: [2013-08-26T08:03:23+00:00] WARN: Cloning resource attributes for service[nginx] from prior resource (CHEF-3694)
    amazon-ebs: [2013-08-26T08:03:23+00:00] WARN: Previous service[nginx]: /tmp/provision/chef-solo/cookbooks/cookbooks/nginx/recipes/default.rb:42:in `from_file'
    amazon-ebs: [2013-08-26T08:03:23+00:00] WARN: Current  service[nginx]: /tmp/provision/chef-solo/cookbooks/cookbooks/nginx/recipes/default.rb:49:in `from_file'
    amazon-ebs: Converging 19 resources
    amazon-ebs: Recipe: nginx::ohai_plugin
    amazon-ebs: * ohai[reload_nginx] action nothing (skipped due to action :nothing)
    amazon-ebs: * template[/etc/chef/ohai_plugins/nginx.rb] action create
    amazon-ebs: - create new file /etc/chef/ohai_plugins/nginx.rb
    amazon-ebs: - update content in file /etc/chef/ohai_plugins/nginx.rb from none to a0b829
    amazon-ebs: --- /etc/chef/ohai_plugins/nginx.rb	2013-08-26 08:03:23.903209893 +0000
    amazon-ebs: +++ /tmp/chef-rendered-template20130826-3857-1jtq9lt	2013-08-26 08:03:23.903209893 +0000
    amazon-ebs: @@ -0,0 +1,66 @@
    amazon-ebs: +#
    amazon-ebs: +# Author:: Jamie Winsor (<jamie@vialstudios.com>)
    amazon-ebs: +#
    amazon-ebs: +# Copyright 2012, Riot Games
    amazon-ebs: +#
    amazon-ebs: +# Licensed under the Apache License, Version 2.0 (the "License");
    amazon-ebs: +# you may not use this file except in compliance with the License.
    amazon-ebs: +# You may obtain a copy of the License at
    amazon-ebs: +#
    amazon-ebs: +#     http://www.apache.org/licenses/LICENSE-2.0
    amazon-ebs: +#
    amazon-ebs: +# Unless required by applicable law or agreed to in writing, software
    amazon-ebs: +# distributed under the License is distributed on an "AS IS" BASIS,
    amazon-ebs: +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    amazon-ebs: +# See the License for the specific language governing permissions and
    amazon-ebs: +# limitations under the License.
    amazon-ebs: +#
    amazon-ebs: +
    amazon-ebs: +provides "nginx"
    amazon-ebs: +provides "nginx/version"
    amazon-ebs: +provides "nginx/configure_arguments"
    amazon-ebs: +provides "nginx/prefix"
    amazon-ebs: +provides "nginx/conf_path"
    amazon-ebs: +
    amazon-ebs: +def parse_flags(flags)
    amazon-ebs: +  prefix = nil
    amazon-ebs: +  conf_path = nil
    amazon-ebs: +
    amazon-ebs: +  flags.each do |flag|
    amazon-ebs: +    case flag
    amazon-ebs: +    when /^--prefix=(.+)$/
    amazon-ebs: +      prefix = $1
    amazon-ebs: +    when /^--conf-path=(.+)$/
    amazon-ebs: +      conf_path = $1
    amazon-ebs: +    end
    amazon-ebs: +  end
    amazon-ebs: +
    amazon-ebs: +  [ prefix, conf_path ]
    amazon-ebs: +end
    amazon-ebs: +
    amazon-ebs: +nginx Mash.new unless nginx
    amazon-ebs: +nginx[:version]             = nil unless nginx[:version]
    amazon-ebs: +nginx[:configure_arguments] = Array.new unless nginx[:configure_arguments]
    amazon-ebs: +nginx[:prefix]              = nil unless nginx[:prefix]
    amazon-ebs: +nginx[:conf_path]           = nil unless nginx[:conf_path]
    amazon-ebs: +
    amazon-ebs: +status, stdout, stderr = run_command(:no_status_check => true, :cwd => "/opt/nginx-1.2.6", :command => "/usr/sbin/nginx -V")
    amazon-ebs: +
    amazon-ebs: +if status == 0
    amazon-ebs: +  stderr.split("\n").each do |line|
    amazon-ebs: +    case line
    amazon-ebs: +    when /^configure arguments:(.+)/
    amazon-ebs: +      # This could be better: I'm splitting on configure arguments which removes them and also
    amazon-ebs: +      # adds a blank string at index 0 of the array. This is why we drop index 0 and map to
    amazon-ebs: +      # add the '--' prefix back to the configure argument.
    amazon-ebs: +      nginx[:configure_arguments] = $1.split(/\s--/).drop(1).map { |ca| "--#{ca}" }
    amazon-ebs: +
    amazon-ebs: +      prefix, conf_path = parse_flags(nginx[:configure_arguments])
    amazon-ebs: +
    amazon-ebs: +      nginx[:prefix] = prefix
    amazon-ebs: +      nginx[:conf_path] = conf_path
    amazon-ebs: +    when /^nginx version: nginx\/(.+)/
    amazon-ebs: +      nginx[:version] = $1
    amazon-ebs: +    end
    amazon-ebs: +  end
    amazon-ebs: +end
    amazon-ebs: - change mode from '' to '0755'
    amazon-ebs: - change owner from '' to 'root'
    amazon-ebs: - change group from '' to 'root'
    amazon-ebs: * ohai[reload_nginx] action reload
    amazon-ebs: - re-run ohai and merge results into node attributes
    amazon-ebs: Recipe: ohai::default
    amazon-ebs: * remote_directory[/etc/chef/ohai_plugins] action nothing (skipped due to action :nothing)
    amazon-ebs: * ohai[custom_plugins] action nothing (skipped due to action :nothing)
    amazon-ebs: Recipe: yum::epel
    amazon-ebs: * yum_key[RPM-GPG-KEY-EPEL-6] action add (up to date)
    amazon-ebs: * yum_repository[epel] action add (up to date)
    amazon-ebs: * yum_repository[epel] action update[2013-08-26T08:03:24+00:00] WARN: Cloning resource attributes for yum_key[RPM-GPG-KEY-EPEL-6] from prior resource (CHEF-3694)
    amazon-ebs: [2013-08-26T08:03:24+00:00] WARN: Previous yum_key[RPM-GPG-KEY-EPEL-6]: /tmp/provision/chef-solo/cookbooks/cookbooks/yum/recipes/epel.rb:22:in `from_file'
    amazon-ebs: [2013-08-26T08:03:24+00:00] WARN: Current  yum_key[RPM-GPG-KEY-EPEL-6]: /tmp/provision/chef-solo/cookbooks/cookbooks/yum/providers/repository.rb:85:in `repo_config'
    amazon-ebs: (up to date)
    amazon-ebs: Recipe: <Dynamically Defined Resource>
    amazon-ebs: * yum_key[RPM-GPG-KEY-EPEL-6] action add (up to date)
    amazon-ebs: * execute[yum-makecache] action nothing (skipped due to action :nothing)
    amazon-ebs: * ruby_block[reload-internal-yum-cache] action nothing (skipped due to action :nothing)
    amazon-ebs: * template[/etc/yum.repos.d/epel.repo] action create
    amazon-ebs: - update content in file /etc/yum.repos.d/epel.repo from 78d374 to 20221e
    amazon-ebs: --- /etc/yum.repos.d/epel.repo	2013-03-01 07:52:14.000000000 +0000
    amazon-ebs: +++ /tmp/chef-rendered-template20130826-3857-4u8iz9	2013-08-26 08:03:24.071209953 +0000
    amazon-ebs: @@ -1,26 +1,8 @@
    amazon-ebs: +# Generated by Chef for ip-172-31-19-207.ap-northeast-1.compute.internal
    amazon-ebs: +# Local modifications will be overwritten.
    amazon-ebs: [epel]
    amazon-ebs: -name=Extra Packages for Enterprise Linux 6 - $basearch
    amazon-ebs: -#baseurl=http://download.fedoraproject.org/pub/epel/6/$basearch
    amazon-ebs: -mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=epel-6&arch=$basearch
    amazon-ebs: -failovermethod=priority
    amazon-ebs: -enabled=0
    amazon-ebs: +name=Extra Packages for Enterprise Linux
    amazon-ebs: +mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=epel-6&arch=$basearch
    amazon-ebs: gpgcheck=1
    amazon-ebs: gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6
    amazon-ebs: -
    amazon-ebs: -[epel-debuginfo]
    amazon-ebs: -name=Extra Packages for Enterprise Linux 6 - $basearch - Debug
    amazon-ebs: -#baseurl=http://download.fedoraproject.org/pub/epel/6/$basearch/debug
    amazon-ebs: -mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=epel-debug-6&arch=$basearch
    amazon-ebs: -failovermethod=priority
    amazon-ebs: -enabled=0
    amazon-ebs: -gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6
    amazon-ebs: -gpgcheck=1
    amazon-ebs: -
    amazon-ebs: -[epel-source]
    amazon-ebs: -name=Extra Packages for Enterprise Linux 6 - $basearch - Source
    amazon-ebs: -#baseurl=http://download.fedoraproject.org/pub/epel/6/SRPMS
    amazon-ebs: -mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=epel-source-6&arch=$basearch
    amazon-ebs: -failovermethod=priority
    amazon-ebs: -enabled=0
    amazon-ebs: -gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6
    amazon-ebs: -gpgcheck=1
    amazon-ebs: +enabled=1
    amazon-ebs: * execute[yum-makecache] action run
    amazon-ebs: - execute yum -q makecache
    amazon-ebs: * ruby_block[reload-internal-yum-cache] action create
    amazon-ebs: - execute the ruby block reload-internal-yum-cache
    amazon-ebs: Recipe: nginx::default
    amazon-ebs: * package[nginx] action install
    amazon-ebs: - install version 1.2.9-1.11.amzn1 of package nginx
    amazon-ebs: * service[nginx] action enable
    amazon-ebs: - enable service service[nginx]
    amazon-ebs: Recipe: nginx::commons_dir
    amazon-ebs: * directory[/etc/nginx] action create (up to date)
    amazon-ebs: * directory[/var/log/nginx] action create
    amazon-ebs: - change mode from '0700' to '0755'
    amazon-ebs: * directory[/etc/nginx/sites-available] action create
    amazon-ebs: - create new directory /etc/nginx/sites-available
    amazon-ebs: - change mode from '' to '0755'
    amazon-ebs: - change owner from '' to 'root'
    amazon-ebs: - change group from '' to 'root'
    amazon-ebs: * directory[/etc/nginx/sites-enabled] action create
    amazon-ebs: - create new directory /etc/nginx/sites-enabled
    amazon-ebs: - change mode from '' to '0755'
    amazon-ebs: - change owner from '' to 'root'
    amazon-ebs: - change group from '' to 'root'
    amazon-ebs: * directory[/etc/nginx/conf.d] action create (up to date)
    amazon-ebs: Recipe: nginx::commons_script
    amazon-ebs: * template[/usr/sbin/nxensite] action create
    amazon-ebs: - create new file /usr/sbin/nxensite
    amazon-ebs: - update content in file /usr/sbin/nxensite from none to fa46fb
    amazon-ebs: --- /usr/sbin/nxensite	2013-08-26 08:03:46.811217642 +0000
    amazon-ebs: +++ /tmp/chef-rendered-template20130826-3857-1ypsv7g	2013-08-26 08:03:46.819217644 +0000
    amazon-ebs: @@ -0,0 +1,38 @@
    amazon-ebs: +#!/bin/sh -e
    amazon-ebs: +
    amazon-ebs: +SYSCONFDIR='/etc/nginx'
    amazon-ebs: +
    amazon-ebs: +if [ -z $1 ]; then
    amazon-ebs: +        echo "Which site would you like to enable?"
    amazon-ebs: +        echo -n "Your choices are: "
    amazon-ebs: +        ls $SYSCONFDIR/sites-available/* | \
    amazon-ebs: +        sed -e "s,$SYSCONFDIR/sites-available/,,g" | xargs echo
    amazon-ebs: +        echo -n "Site name? "
    amazon-ebs: +        read SITENAME
    amazon-ebs: +else
    amazon-ebs: +        SITENAME=$1
    amazon-ebs: +fi
    amazon-ebs: +
    amazon-ebs: +if [ $SITENAME = "default" ]; then
    amazon-ebs: +        PRIORITY="000"
    amazon-ebs: +fi
    amazon-ebs: +
    amazon-ebs: +if [ -e $SYSCONFDIR/sites-enabled/$SITENAME -o \
    amazon-ebs: +     -e $SYSCONFDIR/sites-enabled/"$PRIORITY"-"$SITENAME" ]; then
    amazon-ebs: +        echo "This site is already enabled!"
    amazon-ebs: +        exit 0
    amazon-ebs: +fi
    amazon-ebs: +
    amazon-ebs: +if ! [ -e $SYSCONFDIR/sites-available/$SITENAME ]; then
    amazon-ebs: +        echo "This site does not exist!"
    amazon-ebs: +        exit 1
    amazon-ebs: +fi
    amazon-ebs: +
    amazon-ebs: +if [ $SITENAME = "default" ]; then
    amazon-ebs: +        ln -sf $SYSCONFDIR/sites-available/$SITENAME \
    amazon-ebs: +               $SYSCONFDIR/sites-enabled/"$PRIORITY"-"$SITENAME"
    amazon-ebs: +else
    amazon-ebs: +        ln -sf $SYSCONFDIR/sites-available/$SITENAME $SYSCONFDIR/sites-enabled/$SITENAME
    amazon-ebs: +fi
    amazon-ebs: +
    amazon-ebs: +echo "Site $SITENAME installed; reload nginx to enable."
    amazon-ebs: - change mode from '' to '0755'
    amazon-ebs: - change owner from '' to 'root'
    amazon-ebs: - change group from '' to 'root'
    amazon-ebs: * template[/usr/sbin/nxdissite] action create
    amazon-ebs: - create new file /usr/sbin/nxdissite
    amazon-ebs: - update content in file /usr/sbin/nxdissite from none to cc16ec
    amazon-ebs: --- /usr/sbin/nxdissite	2013-08-26 08:03:46.931217683 +0000
    amazon-ebs: +++ /tmp/chef-rendered-template20130826-3857-4g2h72	2013-08-26 08:03:46.931217683 +0000
    amazon-ebs: @@ -0,0 +1,29 @@
    amazon-ebs: +#!/bin/sh -e
    amazon-ebs: +
    amazon-ebs: +SYSCONFDIR='/etc/nginx'
    amazon-ebs: +
    amazon-ebs: +if [ -z $1 ]; then
    amazon-ebs: +        echo "Which site would you like to disable?"
    amazon-ebs: +        echo -n "Your choices are: "
    amazon-ebs: +        ls $SYSCONFDIR/sites-enabled/* | \
    amazon-ebs: +        sed -e "s,$SYSCONFDIR/sites-enabled/,,g" | xargs echo
    amazon-ebs: +        echo -n "Site name? "
    amazon-ebs: +        read SITENAME
    amazon-ebs: +else
    amazon-ebs: +        SITENAME=$1
    amazon-ebs: +fi
    amazon-ebs: +
    amazon-ebs: +if [ $SITENAME = "default" ]; then
    amazon-ebs: +        PRIORITY="000"
    amazon-ebs: +fi
    amazon-ebs: +
    amazon-ebs: +if ! [ -e $SYSCONFDIR/sites-enabled/$SITENAME -o \
    amazon-ebs: +       -e $SYSCONFDIR/sites-enabled/"$PRIORITY"-"$SITENAME" ]; then
    amazon-ebs: +        echo "This site is already disabled, or does not exist!"
    amazon-ebs: +        exit 1
    amazon-ebs: +fi
    amazon-ebs: +
    amazon-ebs: +if ! rm $SYSCONFDIR/sites-enabled/$SITENAME 2>/dev/null; then
    amazon-ebs: +        rm -f $SYSCONFDIR/sites-enabled/"$PRIORITY"-"$SITENAME"
    amazon-ebs: +fi
    amazon-ebs: +echo "Site $SITENAME disabled; reload nginx to disable."
    amazon-ebs: - change mode from '' to '0755'
    amazon-ebs: - change owner from '' to 'root'
    amazon-ebs: - change group from '' to 'root'
    amazon-ebs: Recipe: nginx::commons_conf
    amazon-ebs: * template[nginx.conf] action create
    amazon-ebs: - update content in file /etc/nginx/nginx.conf from a256fc to d19745
    amazon-ebs: --- /etc/nginx/nginx.conf	2013-05-14 18:25:23.000000000 +0000
    amazon-ebs: +++ /tmp/chef-rendered-template20130826-3857-1rwtxfz	2013-08-26 08:03:47.043217718 +0000
    amazon-ebs: @@ -1,131 +1,39 @@
    amazon-ebs: -# For more information on configuration, see:
    amazon-ebs: -#   * Official English Documentation: http://nginx.org/en/docs/
    amazon-ebs: -#   * Official Russian Documentation: http://nginx.org/ru/docs/
    amazon-ebs: -
    amazon-ebs: -user  nginx;
    amazon-ebs: +user nginx;
    amazon-ebs: worker_processes  1;
    amazon-ebs:
    amazon-ebs: error_log  /var/log/nginx/error.log;
    amazon-ebs: -#error_log  /var/log/nginx/error.log  notice;
    amazon-ebs: -#error_log  /var/log/nginx/error.log  info;
    amazon-ebs: -
    amazon-ebs: pid        /var/run/nginx.pid;
    amazon-ebs:
    amazon-ebs: -
    amazon-ebs: events {
    amazon-ebs: -    worker_connections  1024;
    amazon-ebs: +  worker_connections  1024;
    amazon-ebs: }
    amazon-ebs:
    amazon-ebs: -
    amazon-ebs: http {
    amazon-ebs: -    include       /etc/nginx/mime.types;
    amazon-ebs: -    default_type  application/octet-stream;
    amazon-ebs:
    amazon-ebs: -    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    amazon-ebs: -                      '$status $body_bytes_sent "$http_referer" '
    amazon-ebs: -                      '"$http_user_agent" "$http_x_forwarded_for"';
    amazon-ebs: -
    amazon-ebs: -    access_log  /var/log/nginx/access.log  main;
    amazon-ebs: -
    amazon-ebs: -    sendfile        on;
    amazon-ebs: -    #tcp_nopush     on;
    amazon-ebs: -
    amazon-ebs: -    #keepalive_timeout  0;
    amazon-ebs: -    keepalive_timeout  65;
    amazon-ebs: -
    amazon-ebs: -    #gzip  on;
    amazon-ebs: -
    amazon-ebs: -    # Load modular configuration files from the /etc/nginx/conf.d directory.
    amazon-ebs: -    # See http://nginx.org/en/docs/ngx_core_module.html#include
    amazon-ebs: -    # for more information.
    amazon-ebs: -    include /etc/nginx/conf.d/*.conf;
    amazon-ebs: -
    amazon-ebs: -    server {
    amazon-ebs: -        listen       80;
    amazon-ebs: -        server_name  localhost;
    amazon-ebs: -
    amazon-ebs: -        #charset koi8-r;
    amazon-ebs: -
    amazon-ebs: -        #access_log  /var/log/nginx/host.access.log  main;
    amazon-ebs: -
    amazon-ebs: -        location / {
    amazon-ebs: -            root   /usr/share/nginx/html;
    amazon-ebs: -            index  index.html index.htm;
    amazon-ebs: -        }
    amazon-ebs: -
    amazon-ebs: -        # redirect server error pages to the static page /40x.html
    amazon-ebs: -        #
    amazon-ebs: -        error_page  404              /404.html;
    amazon-ebs: -        location = /40x.html {
    amazon-ebs: -            root   /usr/share/nginx/html;
    amazon-ebs: -        }
    amazon-ebs: -
    amazon-ebs: -        # redirect server error pages to the static page /50x.html
    amazon-ebs: -        #
    amazon-ebs: -        error_page   500 502 503 504  /50x.html;
    amazon-ebs: -        location = /50x.html {
    amazon-ebs: -            root   /usr/share/nginx/html;
    amazon-ebs: -        }
    amazon-ebs: -
    amazon-ebs: -        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    amazon-ebs: -        #
    amazon-ebs: -        #location ~ \.php$ {
    amazon-ebs: -        #    proxy_pass   http://127.0.0.1;
    amazon-ebs: -        #}
    amazon-ebs: -
    amazon-ebs: -        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    amazon-ebs: -        #
    amazon-ebs: -        #location ~ \.php$ {
    amazon-ebs: -        #    root           html;
    amazon-ebs: -        #    fastcgi_pass   127.0.0.1:9000;
    amazon-ebs: -        #    fastcgi_index  index.php;
    amazon-ebs: -        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    amazon-ebs: -        #    include        fastcgi_params;
    amazon-ebs: -        #}
    amazon-ebs: -
    amazon-ebs: -        # deny access to .htaccess files, if Apache's document root
    amazon-ebs: -        # concurs with nginx's one
    amazon-ebs: -        #
    amazon-ebs: -        #location ~ /\.ht {
    amazon-ebs: -        #    deny  all;
    amazon-ebs: -        #}
    amazon-ebs: -    }
    amazon-ebs: -
    amazon-ebs: -
    amazon-ebs: -    # another virtual host using mix of IP-, name-, and port-based configuration
    amazon-ebs: -    #
    amazon-ebs: -    #server {
    amazon-ebs: -    #    listen       8000;
    amazon-ebs: -    #    listen       somename:8080;
    amazon-ebs: -    #    server_name  somename  alias  another.alias;
    amazon-ebs: -
    amazon-ebs: -    #    location / {
    amazon-ebs: -    #        root   html;
    amazon-ebs: -    #        index  index.html index.htm;
    amazon-ebs: -    #    }
    amazon-ebs: -    #}
    amazon-ebs: -
    amazon-ebs: -
    amazon-ebs: -    # HTTPS server
    amazon-ebs: -    #
    amazon-ebs: -    #server {
    amazon-ebs: -    #    listen       443;
    amazon-ebs: -    #    server_name  localhost;
    amazon-ebs: -
    amazon-ebs: -    #    ssl                  on;
    amazon-ebs: -    #    ssl_certificate      cert.pem;
    amazon-ebs: -    #    ssl_certificate_key  cert.key;
    amazon-ebs: -
    amazon-ebs: -    #    ssl_session_timeout  5m;
    amazon-ebs: -
    amazon-ebs: -    #    ssl_protocols  SSLv2 SSLv3 TLSv1;
    amazon-ebs: -    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    amazon-ebs: -    #    ssl_prefer_server_ciphers   on;
    amazon-ebs: -
    amazon-ebs: -    #    location / {
    amazon-ebs: -    #        root   html;
    amazon-ebs: -    #        index  index.html index.htm;
    amazon-ebs: -    #    }
    amazon-ebs: -    #}
    amazon-ebs: +  include       /etc/nginx/mime.types;
    amazon-ebs: +  default_type  application/octet-stream;
    amazon-ebs: +
    amazon-ebs: +  access_log	/var/log/nginx/access.log;
    amazon-ebs: +
    amazon-ebs: +  sendfile on;
    amazon-ebs: +  tcp_nopush on;
    amazon-ebs: +  tcp_nodelay on;
    amazon-ebs: +
    amazon-ebs: +  keepalive_timeout  65;
    amazon-ebs: +
    amazon-ebs: +  gzip  on;
    amazon-ebs: +  gzip_http_version 1.0;
    amazon-ebs: +  gzip_comp_level 2;
    amazon-ebs: +  gzip_proxied any;
    amazon-ebs: +  gzip_vary off;
    amazon-ebs: +  gzip_types text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript application/json;
    amazon-ebs: +  gzip_min_length  1000;
    amazon-ebs: +  gzip_disable     "MSIE [1-6]\.";
    amazon-ebs: +
    amazon-ebs: +  server_names_hash_bucket_size 64;
    amazon-ebs: +  types_hash_max_size 2048;
    amazon-ebs: +  types_hash_bucket_size 64;
    amazon-ebs:
    amazon-ebs: +  include /etc/nginx/conf.d/*.conf;
    amazon-ebs: +  include /etc/nginx/sites-enabled/*;
    amazon-ebs: }
    amazon-ebs: * template[/etc/nginx/sites-available/default] action create
    amazon-ebs: - create new file /etc/nginx/sites-available/default
    amazon-ebs: - update content in file /etc/nginx/sites-available/default from none to 113c3d
    amazon-ebs: --- /etc/nginx/sites-available/default	2013-08-26 08:03:47.415217839 +0000
    amazon-ebs: +++ /tmp/chef-rendered-template20130826-3857-nmxp26	2013-08-26 08:03:47.415217839 +0000
    amazon-ebs: @@ -0,0 +1,11 @@
    amazon-ebs: +server {
    amazon-ebs: +  listen   80;
    amazon-ebs: +  server_name  ip-XX-XX-XX-XX;
    amazon-ebs: +
    amazon-ebs: +  access_log  /var/log/nginx/localhost.access.log;
    amazon-ebs: +
    amazon-ebs: +  location / {
    amazon-ebs: +    root   /var/www/nginx-default;
    amazon-ebs: +    index  index.html index.htm;
    amazon-ebs: +  }
    amazon-ebs: +}
    amazon-ebs: - change mode from '' to '0644'
    amazon-ebs: - change owner from '' to 'root'
    amazon-ebs: - change group from '' to 'root'
    amazon-ebs: * execute[nxensite default] action run
    amazon-ebs: - execute /usr/sbin/nxensite default
    amazon-ebs: Recipe: nginx::default
    amazon-ebs: * service[nginx] action start
    amazon-ebs: - start service service[nginx]
    amazon-ebs: * service[nginx] action reload
    amazon-ebs: - reload service service[nginx]
    amazon-ebs: Chef Client finished, 20 resources updated
==> amazon-ebs: Stopping the source instance...
==> amazon-ebs: Waiting for the instance to stop...
==> amazon-ebs: Creating the AMI: packer-example 1377504007
==> amazon-ebs: AMI: ami-XXXXXXXX
==> amazon-ebs: Waiting for AMI to become ready...
==> amazon-ebs: Terminating the source AWS instance...
==> amazon-ebs: Deleting temporary security group...
==> amazon-ebs: Deleting temporary keypair...
Build 'amazon-ebs' finished.

==> Builds finished. The artifacts of successful builds are:
--> amazon-ebs: AMIs were created:

ap-northeast-1: ami-XXXXXXXX

作成されたAMIを元にEC2インスタンスを起動し、SSHで接続してみます。

$ ssh ec2-user@ec2-XX-XX-XX-XX.ap-northeast-1.compute.amazonaws.com
[ec2-user@ip-XX-XX-XX-XX ~]$ rpm -q nginx
nginx-1.2.9-1.11.amzn1.x86_64
[ec2-user@ip-XX-XX-XX-XX ~]$ rpm -q chef
chef-11.6.0-1.el6.x86_64
[ec2-user@ip-XX-XX-XX-XX ~]$

nginxchefがちゃんとインストールされていますね!!

まとめ

というわけで、Packerで簡単にChefのインストール&実行したAMIを作成できることをご紹介しました。
Packerの開発は相変わらず非常に活発で、chroot環境のEC2で並列実行するBuilderというユニークな仕組みも追加されています。こちらも試して、またブログで紹介したいです。
皆さんもPackerを活用して楽にAMIを管理しましょう!!