ちょっと話題の記事

PackerでAmazon LinuxのAMI(Amazon Machine Image)を作成する

2013.07.16

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

みなさーん、7/12(金)のVagrant meetupは楽しかったですかー? 話題のVagrantの開発者 Mitchell Hashimoto さんを迎えてのアツいVagrantトークに、TLは沸き上がっていましたね。かくいう大瀧は、WHITE ASH初の自主企画ライブのために、Vagrant meetupは泣く泣く欠席でした。いいライブだったから悔しくなんてないです。ホントです。

さて、そんな (どんな?w) Mitchell Hashimotoさんを中心に最近開発が進められているPackerというツールがあります。今年の3月に開発が始まり現在はまだバージョン0.1.5ですが、斬新なコンセプトや面白そうな機能がたくさんあって面白いと思い、今回は概要と入門をご紹介したいと思います!

Packerのできることと目指すもの

スクリーンショット 2013-07-14 14.58.11

Packerは、Packer Webサイトのトップ画像にもあるように、一つの設定ファイルから複数の環境に同時にマシンイメージを作成することができます。例えば、クラウドの本番環境(AWS EC2など)とローカルの開発環境(VirtualBoxなど)を、同一のファイルで同時にイメージを作成するという感じです。

ただ、複数環境ではなくAWS EC2/AMIを管理するケースでも、AMIを自動作成し、その構成内容をコード(設定ファイル)で管理できるというEC2/AMIの新しい管理手法として非常に有用だと思います。これまで、AMIは他人が作ったものはもとより、開発者が自分で作ったものであっても、作成したあとからAMIの内容を正確に把握することが難しいブラックボックスになりがちだったのではないでしょうか。Packerを使用すれば、設定ファイル(後述のTemplate)をGitなどのVCSで管理することで、AMIの構成をコードで管理することが可能になります。PackerによるAMIの作成は、自動で簡単に行うことができるので特定のAMIへの依存が少なくなるというメリットもあります。

Packerの目指すものは、公式Webページのイントロダクションに見ることができます。

Packer brings pre-baked images into the modern age, unlocking untapped potential and opening new opportunities.

"Packerは、事前に構成済み(pre-baked)マシンイメージを次世代に進化させ、未開発の可能性と新しい機会をもたらします。"とあり、AMIなどのイメージ管理を進化させる可能性を持つツールということが理解していただけると思います。

Packerの概要

Packerは、以下の図のイメージのように、TemplateBuilderProvisionerという3つのコンポーネントで動作します。

packer01

Template Packerの設定ファイルを指します。シンプルな単一のJSONファイルです。以下のBuilderProvisionerの他、Packerの設定は全てTemplateに記述します。
Builder マシンイメージを作成するための作業用マシンの作成や、イメージのエクスポートを行います。AWSのほか、クラウドサービスのDigitalOcean、仮想化ソフトウェアのVirtualBox、VMware Fusionをサポートします。
Provisioner マシンイメージのゲストOSへの変更内容を指定します。現在はシェルの実行やファイルコピーなどの基本的なものがサポートされます。

個人的には、ProvisionerがPackerが流行るかどうかを左右する重要なコンポーネントだと思っています。 シェルだけではなく、最近流行りのProvisioning Frameworkがさくっと実行できるとCool!!な気がしてきませんか?

AMIを作ってみる

Packerの最初の一歩としては、公式WebページのGETTING STARTEDが簡潔な英語でとてもわかりやすいので、そちらも参照ください。 ここでは、Amazon LinuxでAMIを作成するまでの手順とちょっとハマったところをご紹介します。今回はBuilderをAWS、Provisionerをシェルコマンドとして「yumでパッケージを最新にし、nginxパッケージをインストールした」AMIを作成してみます。概念図を以下に示します。

packer02

  1. Amazon Linux AMIからEC2インスタンスを作成
  2. ProvisionerをEC2インスタンスに適用
  3. EC2インスタンスからAMIを作成

設定は、全てこのあとのTemplateに記述するだけです。EC2周りの補足としては、インスタンスで使用するセキュリティグループ、SSHキーペアは今回専用のものがPackerによってそれぞれ自動で作成、削除されます *1

準備するもの

  • AWSのAPIアクセスキー、シークレットキー
  • 元となるAMIのAMI ID

1. Packerのインストール

Packerは、公式Webページからバイナリをダウンロードします。ちなみに、ソースはGoで記述されています。イマドキな感じですね。任意のディレクトリ/フォルダに展開し、PATHを通すだけでOKです。今回は、~/.packerに配置しました。

$ mkdir ~/.packer
$ cd ~/.packer
$ wget https://dl.bintray.com/mitchellh/packer/0.1.5_darwin_amd64.zip
$ unzip 0.1.5_darwin_amd64.zip
$ rm 0.1.5_darwin_amd64.zip
$ ls
packer*                        packer-builder-digitalocean*   packer-builder-vmware*         packer-command-validate*       packer-provisioner-file*
packer-builder-amazon-ebs*     packer-builder-virtualbox*     packer-command-build*          packer-post-processor-vagrant* packer-provisioner-shell*
$ vim ~/.bash_profile
 : 
export PATH=$PATH:$HOME/.packer
$ packer -v
Packer v0.1.5
$ packer
usage: packer [--version] [--help] <command> [<args>]

Available commands are:
    build        build image(s) from template
    validate     check that a template is valid

2. Templateの作成

Templateは、packerコマンドを実行する任意のフォルダ/ディレクトリにJSON形式のテキストファイルで作成します。JSONのルート階層にbuildersキーおよびprovisionersキーとしてBuilderProvisionerを定義する非常にシンプルな構成です。Templateの書き方の詳細は、公式Webページのドキュメントを参照ください。

例 : sample.json

{
  "builders": [{
    "type": "amazon-ebs",
    "access_key": "XXXXXXXXXXXXXXXX",
    "secret_key": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "region": "ap-northeast-1",
    "source_ami": "ami-XXXXXXXX",
    "instance_type": "t1.micro",
    "ssh_username": "ec2-user",
    "ssh_timeout": "5m",
    "ami_name": "packer-example {{.CreateTime}}"
  }],
 "provisioners": [{
    "type": "shell",
    "inline": [
      "sudo yum -y update",
      "sudo yum -y install nginx"
    ]
  }]
}

Builderの記述

EBSベースのEC2を使用する場合は、typeキーにamazon-ebsを指定します。ami_nameキーは、作成されるAMI名です。{{.CreateTime}}はGoのテンプレートの変数参照らしく、AMIの作成日時が(なぜか)UNIXタイムスタンプで入ります。

ゲストOSをAmazon Linux、インスタンスタイプをt1.microにする場合、インスタンス作成後にSSHでゲストOSに接続できるようになるまで時間がかかるため、ssh_timeoutキーでタイムアウトの時間を調整する必要があります。デフォルト(ssh_timeoutキーの記述なし)の1m(1分)では、エラーになりました。

Provisionerの記述

シェルコマンド、シェルスクリプトを使用する場合は、typeキーにshellを指定します。さらにinlineキー(実行したいコマンドのリスト)もしくはscript/scriptsキー(シェルスクリプトのファイル名)を指定すると、コマンドおよびスクリプトを実行してくれます。

3. packerコマンドの実行

これだけで準備OKです。packer validateTemplateの書式チェック、packer buildでイメージ作成を実行します。

$ packer validate sample.json
Template validated successfully.
$ packer build sample.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 to become ready...
==> amazon-ebs: Waiting for SSH to become available...
==> amazon-ebs: Connected via SSH!
==> amazon-ebs: Provisioning with shell script: /var/folders/yp/pzfkk6s92f9_yxrnzckv238c0000gn/T/packer-shell590149046
amazon-ebs: Loaded plugins: priorities, security,
amazon-ebs: : update-motd, upgrade-
amazon-ebs: : helper
amazon-ebs: Setting up Update Process
amazon-ebs: Resolving Dependencies
amazon-ebs: --> Running transaction check
amazon-ebs: ---> Package aws-apitools-ec2.noarch 0:1.6.8.0-1.0.amzn1 will be an update
 (中略)
amazon-ebs: Updated:
amazon-ebs: aws-apitools-ec2.noarch 0:1.6.8.0-1.0.amzn1
 (中略)
amazon-ebs: Complete!
amazon-ebs: Loaded plugins: priorities, security,
amazon-ebs: : update-motd, upgrade-
amazon-ebs: : helper
amazon-ebs: Setting up Install Process
amazon-ebs: Resolving Dependencies
amazon-ebs: --> Running transaction check
amazon-ebs: ---> Package nginx.x86_64 1:1.2.9-1.11.amzn1 will be installed
amazon-ebs: --> Processing Dependency: GeoIP for package: 1:nginx-1.2.9-1.11.amzn1.x86_64
 (中略)
amazon-ebs: Installed:
amazon-ebs: nginx.x86_64 1:1.2.9-1.11.amzn1
amazon-ebs:
amazon-ebs: Dependency Installed:
amazon-ebs: GeoIP.x86_64 0:1.4.8-1.5.amzn1
 (中略)
amazon-ebs: Complete!
==> amazon-ebs: Stopping the source instance...
==> amazon-ebs: Waiting for the instance to stop...
==> amazon-ebs: Creating the AMI: packer-example 1373798894
==> 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: Error cleaning up security group. Please delete the group manually: sg-XXXXXXXX
==> 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
$

4. AMIの確認

packer buildの実行結果の最後に、作成されたAMIのIDが表示されます。Management Consoleで確認してみましょう。

packer_ss03

できてますね!

近日中にChef Soloに対応!(するかも)

概要のところで「ProvisionerでProvisioning Frameworkが使えたらいいね」みたいな話をしましたが 、Provisioner for Chef Soloという Pull Request が数日前に発行されたようで、近日中に公式ビルドでも使えるようになるんじゃないかなぁ〜と勝手に期待しています。できるようになったら、あらためてブログで書くつもりです。

まとめ

AMI作成を自動化し、構成をコードで管理できるPackerをご紹介しました。AMIの管理手法を根底から覆す、もの凄いポテンシャル、可能性を持つツールだと思っています。みなさんもPackerの動向を、要チェックや!!(古い)

脚注

  1. 今回試したときには、セキュリティグループの削除がエラーになり手動で消す必要がありました。Default VPC構成などが影響したのかもしれません。