ブログ

ryuzeeによるブログ記事。不定期更新

Packer & Chef-SoloでAmazon EC2のAMIを簡単に作る方法

全国1000万人のPackerユーザーのみなさんこんにちはこんにちは。

Packerは、Mitchell Hashimotoさんによって開発が進められている様々な環境の仮想マシンのテンプレートを簡単に作れるツールです。例えばVagrantを使っている場合はいままではPatrick Deboisさんが作っていたVeeweeを使うのが定番でしたが、このPackerの登場で主流が移りつつあります。 またPackerでは、Amazon EC2用のAMI (Amazon Machine Image)を作成することもできます(某ドラクエ好きな著名エンジニアのIさんが「PackerはAMI作成ツールだ!」と言っていたのを聞いたような気がw)

今までは、Packerでミドルウェアやパッケージをインストールしたり、細かい設定をする場合にはShellのProvisionerを使っていたのですが、先日登場したバージョン0.3.5から、Chef-Soloに対応しましたので、今日はその使い方を説明します。

下準備

まずはPackerの最新版をインストールしてください。こちらのダウンロードページから環境にあったものをダウンロードします。 ダウンロードしたら適当な場所に配置してください。 僕は/opt/packer 以下に配置してPATHを通していますので、以降のコマンドはPATHが通っている前提となります。

Cookbookの準備

Packerから呼び出すCookbookを準備します。ここではBerkshelfを使ってCookbookを管理することにしますので、以下のような形で、今回Packerで使うCookbookをBerkshelfファイルに記述してください。 Berkshelfの使い方はこちらを参照してください。 以下の例では、Opscodeが提供するyumのCookbook、自分のローカルマシンにあるtimezoneとapache2のCookbook、そしてgithubにあげてあるmemcachedのCookbookを使うようになっています。ご自身の環境にあわせて適宜書き換えてください。

Berksfile

site :opscode

cookbook 'yum'
cookbook 'timezone', :path => '../../ryuzee-cookbooks/timezone'
cookbook 'apache2', :path => '../../ryuzee-cookbooks/apache2'
cookbook 'memcached', :git => 'git://github.com/ryuzee-cookbooks/memcached.git'

作成が終わったら、Cookbookをローカルのvendor-cookbooksで管理するように以下のコマンドを実行します。

Berks install --path=./vendor-cookbooks

Packer用のJSONファイルの準備

Packerが起動するときに利用するjsonファイルを作成します。とくに名前に決まりはありません。今回はamazonlinux.jsonという名前にしました
{
  "builders": [{
    "type": "amazon-ebs",
    "region": "ap-northeast-1",
    "source_ami": "ami-39b23d38",
    "instance_type": "m1.medium",
    "ssh_username": "ec2-user",
    "ssh_timeout": "5m",
    "ami_name": "amznlinux-{{timestamp}}"
  }],
  "provisioners": [{
    "type": "chef-solo",
    "cookbook_paths": ["./vendor-cookbooks/"],
    "run_list": ["timezone", "apache2", "memcached"],
    "json": {"memcached":{"maxcon":"512","cachesize":"512"}},
    "prevent_sudo": false,
    "skip_install": false
  }]
}

内容は前半半分は、Amazon EC2でEBS AMIを作成するので、それに関連する情報(リージョン、元となるAMI、作業の時に使うインスタンスの種類、SSHで接続する際のユーザー名とタイムアウト、完成したAMIにつける名前)です。 なお、以前のバージョンから現在時刻を取得する項目名が変わっているので、注意してください。 後半半分はProvisionerの設定です。順番に見ていきます。

  • typeの箇所はchef-soloを指定します。なおシェルを使いたい場合はshellになります。
  • cookbook_pathsは、今回適用するCookbookが置かれている場所を記述します。今回の例ではカレントディレクトリにBerkshelfを使ってvendor-cookbooksディレクトリを用意したのでそちらを指定します。なお項目名は開発ブランチの時と名前が変わっていますので、既に0.3.5以前から開発ブランチを使ってこの機能を使っていた人は変更する必要があります。
  • run_listには適用したいCookbookを列挙します。単に依存関係があるだけのCookbookについてはとくに記載する必要はありません。
  • jsonの箇所では、Cookbookを適用時にattributesを変更するために使います。たとえば上記の例では、元々memcachedのmaxconを1024、cachesizeを256としてデフォルト値設定していたのを上書きしているということです。
  • prevent_sudoは、Chef-Soloを実行する際にsudoをつけずに実行するかどうかのフラグです。元となるインスタンスにrootでログインするのでない限りはfalseとなります。
  • skip_installは、クライアント側に必要となるChef Soloを自動でインストールしないようにするフラグです。

実行

実行方法は以前と変わりません。
packer build amazonlinux.json

とすればAMIの作成が始まります。なお、ログの出力を強化するには、環境変数にPACKER_LOG=1を設定してください。

実行すると

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-8cc8f58e) to become ready...
==> amazon-ebs: Waiting for SSH to become available...
==> amazon-ebs: Connected to SSH!
    amazon-ebs: Installing Chef...
    amazon-ebs: % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
    amazon-ebs: Dload  Upload   Total   Spent    Left  Speed
    amazon-ebs: 100  6790  100  6790    0     0   7311      0 --:--:-- --:--:-- --:--:--  9005
    amazon-ebs: Downloading Chef  for el...
    amazon-ebs: Installing Chef
    amazon-ebs: warning: /tmp/tmp.G3MNcjNC/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 directory: /tmp/packer-chef-solo
    amazon-ebs: Creating directory: /tmp/packer-chef-solo/cookbooks-0
    amazon-ebs: Creating configuration file 'solo.rb'
    amazon-ebs: Creating JSON attribute file
    amazon-ebs: Executing Chef: sudo chef-solo --no-color -c /tmp/packer-chef-solo/solo.rb -j /tmp/packer-chef-solo/node.json
    amazon-ebs: Starting Chef Client, version 11.6.0
    amazon-ebs: Compiling Cookbooks...
    amazon-ebs: Converging 8 resources
    amazon-ebs: Recipe: timezone::default
    amazon-ebs: * execute[cp -p /usr/share/zoneinfo/Japan /etc/localtime] action run
    amazon-ebs: - execute cp -p /usr/share/zoneinfo/Japan /etc/localtime
    amazon-ebs: Recipe: apache2::default
    amazon-ebs: * package[httpd] action install
    amazon-ebs: - install version 2.2.25-1.0.amzn1 of package httpd
    amazon-ebs: * file[/etc/httpd/conf.d/welcome.conf] action delete
    amazon-ebs: - delete file /etc/httpd/conf.d/welcome.conf
    amazon-ebs: * file[/var/www/html/index.html] action create_if_missing
    amazon-ebs: - create new file /var/www/html/index.html
    amazon-ebs: - update content in file /var/www/html/index.html from none to b80023
    amazon-ebs: --- /var/www/html/index.html	2013-08-31 09:34:07.197018173 +0900
    amazon-ebs: +++ /tmp/.index.html20130831-1449-kk5zqc	2013-08-31 09:34:07.201018192 +0900
    amazon-ebs: @@ -0,0 +1 @@
    amazon-ebs: +It works!
    amazon-ebs: * service[httpd] action enable
    amazon-ebs: - enable service service[httpd]
    amazon-ebs: * service[httpd] action start
    amazon-ebs: - start service service[httpd]
    amazon-ebs: Recipe: memcached::default
    amazon-ebs: * package[memcached] action install
    amazon-ebs: - install version 1.4.13-1.11.amzn1 of package memcached
    amazon-ebs: * template[/etc/sysconfig/memcached] action create
    amazon-ebs: - update content in file /etc/sysconfig/memcached from 320378 to 5fb386
    amazon-ebs: --- /etc/sysconfig/memcached	2012-08-15 06:57:16.000000000 +0900
    amazon-ebs: +++ /tmp/chef-rendered-template20130831-1449-4fqyhl	2013-08-31 09:34:10.389032083 +0900
    amazon-ebs: @@ -1,5 +1,5 @@
    amazon-ebs: PORT="11211"
    amazon-ebs: USER="memcached"
    amazon-ebs: -MAXCONN="1024"
    amazon-ebs: -CACHESIZE="64"
    amazon-ebs: +MAXCONN="512"
    amazon-ebs: +CACHESIZE="512"
    amazon-ebs: OPTIONS=""
    amazon-ebs: * service[memcached] action enable
    amazon-ebs: - enable service service[memcached]
    amazon-ebs: * service[memcached] action start
    amazon-ebs: - start service service[memcached]
    amazon-ebs: * service[memcached] action restart
    amazon-ebs: - restart service service[memcached]
    amazon-ebs: Chef Client finished, 11 resources updated
==> amazon-ebs: Stopping the source instance...
==> amazon-ebs: Waiting for the instance to stop...
==> amazon-ebs: Creating the AMI: amznlinux-1377909138
==> amazon-ebs: AMI: ami-db7eecda
==> 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-db7eecda

のように表示され、AMIの作成が完了します。

まとめ

いままではせっかくCookbookがあっても、別でシェルを書くか、インスタンス起動後にCookbookを適用するしかなかったのですが、今回のChef-Soloへの対応で、既存のものをサクサク組み合わせた形で素早くベースとなる環境を作れることになります。 既にChefまたはChef Soloを使っている人にとってはかなり敷居が低いのでぜひ試してみると良いと思います。

なお、今回使ったコードは以下にアップしていますので参考にしてみてください。 https://github.com/ryuzee/sandbox-devops/tree/master/packer-ec2-chef-solo

アジャイルコーチングやトレーニングを提供しています

株式会社アトラクタでは、アジャイル開発に取り組むチーム向けのコーチングや、認定スクラムマスター研修などの各種トレーニングを提供しています。ぜひお気軽にご相談ください。

詳細はこちら