Packer+chef-soloでAWSのAMI構築を試してみた

最近、DevOpsというキーワードと共にPackerというツールの話がちらほら耳に入るようになりました。
Packerとは何ぞや?という話もあると思いますが、
すでに多くのブログで言及されているので詳しくはそちらをご参照いただくのが良いかと。
Packerでさまざまな仮想マシンのテンプレートを作成する|Ryuzee.com
Packerリリースおめでとうございます!|As a Futurist…
PackerでAmazon LinuxのAMI(Amazon Machine Image)を作成する|Developers.IO


ざっくりと説明すると
「OSの構築からVM作成まで、統一したインタフェースで自動化出来るツール」
という感じでしょうか。
なんだか便利そうですね。


実は社内でもDevOpsを推進しており、
「Packer、プロダクト環境で使えないかなー」と
調査がてら試してみたのでメモしておきます。

Packerコンポーネント概要

簡単に。

builders

VM作成のためのイメージなどを指定します。
現在は Amazon EC2 (AMI) / DigitalOcean /VirtualBox / VMware 等をサポートしているようです。

provisioners

プロビジョニングの実行。
現在は ShellScripts / FileUploads / Salt 等をサポートしているようです。
Saltは http://saltstack.com/ というクラウド用のマネジメントサービス?を実行するようです。あんまりわかってない。

post-processors

終了時の処理。AMIに固めたり、Vagrantのイメージ作ったり、どこかのURLにアップロードしたり。

PackerサンプルConfig

説明だけだとイメージが掴みづらいと思うので、簡単なサンプルを貼ってみます。

{
    // builder 。 複数指定できる
    "builders": [
        {
            "type": "vmware",
            "iso_url": "....",
            "ssh_username": "...",
            ...
        },
        {
            "type": "virtualbox",
            "iso_url": "....",
            "ssh_username": "...",
            ...
        }
    ],

    // provisoner
    "provisioners": [
        // ファイル転送
        { "type": "file", "source": "files/nginx.conf", "destination": "/tmp/nginx.conf" },
        // インライン実行
        {
            "type": "shell",
            "inline": [
                "sudo yum -y install nginx"
            ]
        },
        // シェルスクリプト読み込み/実行
        {
            "type": "shell",
            "scripts": [
                "scripts/base.sh",
            ],
        }
    ],
    // 終了後処理。vagrant用のboxを保存
    "post-processors": [
        {
            "type": "vagrant",
            "output": "output/{{ .Provider }}.box"
        }
    ]
}
Webで探す

「packer template」などでググる
サンプルテンプレートがいくつかHITするので参考にすると良いと思います。


AWSのAMIを固めるのに使ってみる

本題。
今回試したのは以下の流れ。全てpackerコマンドのみで完結します。

  1. 生AMI起動
  2. リポジトリ上にあるchefレシピをダウンロード
  3. chef-solo実行
  4. AMI作成
template.json

こんな設定ファイルを書いてみました。

{
  "builders": [{
    "type": "amazon-ebs",
    "access_key": "xxxxxxxxx",
    "secret_key": "yyyyyyyyy",
    "region": "ap-northeast-1",
    "source_ami": "ami-zzzzzzzzz",
    "instance_type": "m1.small",
    "ssh_username": "ec2-user",
    "ssh_timeout": "5m",
    "security_group_id": "sg-wwwwwww",
    "ami_name": "packer-example-{{.CreateTime}}"
  }],
 "provisioners": [
    {
      "type": "file",
      "source": "files/id_rsa",
      "destination": "/home/ec2-user/.ssh/id_rsa"
    },
    {
      "type": "file",
      "source": "files/id_rsa.pub",
      "destination": "/home/ec2-user/.ssh/id_rsa.pub"
    },
    {
      "type": "file",
      "source": "files/known_hosts",
      "destination": "/home/ec2-user/.ssh/known_hosts"
    },
    {
      "type": "shell",
      "inline": [
        "chmod 600 /home/ec2-user/.ssh/id_rsa /home/ec2-user/.ssh/id_rsa.pub /home/ec2-user/.ssh/known_hosts",
        "sudo yum -y install gcc make gcc-c++ zlib-devel openssl-devel readline-devel sqlite-devel git ruby ruby-devel rubygems",
        "sudo gem install chef --version '=11.4.0' --no-ri --no-rdoc",
        "cd /home/ec2-user && git clone git@hogehogehoge.com:chef-project.git",
        "sudo chef-solo -c /home/ec2-user/chef-project/solo.rb -j /home/ec2-user/chef-project/nodes/provisioning.json"
      ]
    }
  ]
}

config説明

builder

typeには"amazon-ebs"を指定しています。
そしてソースとなるimage-idやその他諸々のプロパティを設定します。

provisioning

gitrepoからノンパスで取得するために鍵を転送しています。*1
鍵はローカルの"files"以下のファイルを転送しています。
その後でshellをインラインで実行しています。
chef入れてリポジトリから取得してchef-soloを実行しているだけですね。

post-processors

指定していませんが、amazon-ebsの時は勝手にAMI作ってくれるようです。

packer実行

# json バリデーション
packer validate template.json
# packer 実行
packer build template.json
amazon-ebs時のPacker疑問点

もしかしたらPackerの使い方自体がよろしくないのかもしれませんが、
こんな疑問点もありました。

  • AWSがソースの場合、毎回新規にインスタンス立ち上がってしまう。起動中のインスタンスとかに実行したいかも。
  • たとえば、provisonersでchef-solo実行->serverspec実行->ALLグリーンならAMI作成、としたくなったときにどうすればいいのか?
  • 途中でエラーが出ると強制的に Terminate されてしまうので、リトライが大変。お金かかる。
  • そもそもAMI作るだけならPacker使う必要性はあるのか?

むー、どうなんだろう。

まとめ

ちょっと試してみた、レベルですが
こんなに簡単にプロビジョニングを実行しつつAMIを作成することが出来ました。
シンプルでよいですね!


Packer、provisionersにchef-solo対応するとだいぶ良さそうですね。*2
今後の動向を見守りつつ、DevOpsに励みたいと思います( ・`ω・´)

*1:予め、gitに登録されている鍵を持ったインスタンスをAMI化しておいても良いでしょう

*2:pull requestはすでにある様子