PackerをCIツールに組み込むためのTipsあれこれ

2013.10.27

ども、大瀧です。
みなさんPacker使ってますか?Packerは、本ブログでも以下のエントリーでご紹介している通りAMI(Amazon EC2のイメージ)などの仮想マシンイメージを自動作成するツールです。

Packerのコンセプトとして、コードベースで管理でき、一連の処理がコマンドラインで完結すると謳われており、GitやJenkinsなどとの組み合わせを意識しています。

ただ、実際に触ってみるとそのままでは上手く行かないところもあったので、備忘録としてブログに残しておきます。

アクセスキーの外出し

AMIを作成するamazon-ebs Builderを利用する場合、AWS APIにアクセスするためのアクセスキー、シークレットキーを指定する必要があります。しかし、以下のようにテンプレートファイルにベタ書きすると、Gitでコードを管理する際に環境ごとの差異を吸収できませんし、GitHubなどの公開リポジトリにpushするときに取り除くのも面倒です。

Packerテンプレートの例

{
  "builders": [{
    "type": "amazon-ebs",
    "access_key": "AKIAXXXXXXXXXXXXXXXX",
    "secret_key": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "region": "ap-northeast-1",
(以下略)

そこで、アクセスキー、シークレットキーを外出ししてみます。Packerテンプレートで可変の値を扱うためには、User Variablesを利用します。User Variablesvariablesセクションで変数名と初期値を定義し、{{user `変数名`}}で参照します。書き直すと、以下のようになります。

{
  "variables": {
    "aws_access_key": "",
    "aws_secret_key": ""
  },
  "builders": [{
    "type": "amazon-ebs",
    "access_key": "{{user `aws_access_key`}}",
    "secret_key": "{{user `aws_secret_key`}}",
    "region": "ap-northeast-1",
(以下略)

あとは、packerコマンドの実行時に-varオプションで値をセットします。

$ packer build ¥
  -var 'aws_access_key=AKIAXXXXXXXXXXXXXXXX' ¥
  -var 'aws_secret_key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' ¥
  centos_cloud-init.json

-var '変数名=値'という形式で、複数指定できます。

出力の絞り込み

Packerを実行すると、その作業過程が標準出力に出力されます。以下のような感じです。

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

==> amazon-ebs: Creating temporary keypair: packer 526a9b2f-9acb-0442-f0c5-341eaa209b8e
==> 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...
(中略)
Build 'amazon-ebs' finished.

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

ap-northeast-1: ami-XXXXXXXX
$

人間が見る分には見やすくて良いのですが、JenkinsなどのCIツールで処理結果を抽出するにはちょっと厳しい感じです。

そこで、Packerには出力オプションとして-machine-readableオプションが用意されています。以下のような出力になります。

$ packer build -machine-readable centos_cloud-init.json
1382712518,,ui,say,amazon-ebs output will be in this color.
1382712518,,ui,say,
1382712518,,ui,say,==> amazon-ebs: Creating temporary keypair: packer 526a84c6-9acb-0442-f0c5-341eaa209b8e
1382712519,,ui,say,==> amazon-ebs: Creating temporary security group for this instance...
1382712520,,ui,say,==> amazon-ebs: Authorizing SSH access on the temporary security group...
1382712520,,ui,say,==> amazon-ebs: Launching a source AWS instance...
1382712521,,ui,say,==> amazon-ebs: Waiting for instance (i-XXXXXXXX) to become ready...
(中略)
1382712917,,ui,say,Build 'amazon-ebs' finished.
1382712917,,ui,say,\n==> Builds finished. The artifacts of successful builds are:
1382712917,amazon-ebs,artifact-count,1
1382712917,amazon-ebs,artifact,0,builder-id,mitchellh.amazonebs
1382712917,amazon-ebs,artifact,0,id,ap-northeast-1:ami-XXXXXXXX
1382712917,amazon-ebs,artifact,0,string,AMIs were created:\n\nap-northeast-1: ami-XXXXXXXX
1382712917,amazon-ebs,artifact,0,files-count,0
1382712917,amazon-ebs,artifact,0,end
1382712917,,ui,say,--> amazon-ebs: AMIs were created:\n\nap-northeast-1: ami-XXXXXXXX
$

タイムスタンプのほか、出力の種類などの項目がカンマ区切りで出力されました。これであれば、UNIX/Linuxで使える文字列解析のテキストユーティリティコマンドで解析できそうです。

今回は、出力からAMI IDを抽出してみます。

$ packer build -machine-readable centos_cloud-init.json ¥
| awk -F , '$3 ~ /^artifact$/ && $5 ~ /^id$/ { print $6 };' ¥
| cut -d : -f 2
ami-XXXXXXXX
$

最後の行が作成されたAMI IDです。awkコマンドとcutコマンドの組み合わせで出せました!awkだけでもなんとかなりそうな気もします。

-machine-readableオプションの出力の詳細は、公式ドキュメントを参照ください。

まとめ

Gitでのコード管理やJenkinsなどのCIツール向けに、アクセスキーの外出しとAMI IDの抽出を行いました。両方を行うコマンドラインは以下になります。

$ packer build ¥
  -var 'aws_access_key=AKIAXXXXXXXXXXXXXXXX' ¥
  -var 'aws_secret_key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' ¥
  -machine-readable ¥
  XXXX.json ¥
  | awk -F , '$3 ~ /^artifact$/ && $5 ~ /^id$/ { print $6 };' | cut -d : -f 2
ami-XXXXXXXX
$

これをEC2の作成時にAMI IDを渡すようJenkinsのジョブにかませてやると、Packerテンプレートの自動テストの道も見えてきますよね。頑張って作り込んで、PackerをCIツールでテストしましょう!