Packer実行エラー時にインスタンスをTerminateさせない機能がリリースされました

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

2016/10/21に、Packerの新しいバージョン 0.11.0 がリリースされました。

このリリース内に、個人的に非常に注目していた新機能が含まれています。今日はそのご紹介です。

新機能?

Packerはマシンイメージ作成を効率化するためのHashicorp社製のツールです。AWS EC2に限った話で言うと、

  • EC2インスタンスを起動する
  • 指定した方法でプロビジョニングを行う
  • プロビジョニングが完了したらAMIを作成する

という工程を自動化し、AMIの作成を非常に楽にすることができます。私も普段から非常にお世話になっているツールです。

便利なツールなのですがPackerでAMIを作る時に面倒な点がひとつありました。Packerの実行過程でエラーが発生したときには、強制的にすべてのリソースがTerminateされてしまう点です。この不満点を解消する -on-errorオプションというものが追加されました。

-on-errorオプションでは、Packer実行時にエラーが発生した時にPackerがどう振る舞うかを指定できます。現時点では3種類の指定が可能です。

  • -on-error=cleanup : 作成されたリソースをすべて破棄する(これまでのPackerと同じ挙動)
  • -on-error=abort : 作成されたリソースを一切破棄せずPackerを終了する
  • -on-error=ask : エラー発生時、どうするかをプロンプトから選択する、(cleanup,abort,retryから選択する)

これが実装されたことで、プロビジョニングでエラーが発生した時のトラブルシューティングが容易になりました。早速試してみましょう。

インストール

公式サイトからお使いのプラットフォームに合った最新版のzipをダウンロードし、展開したファイルをPATH配下に置いてください。筆者はMac OS Xで以下の手順を実行しました。

$ wget https://releases.hashicorp.com/packer/0.11.0/packer_0.11.0_darwin_amd64.zip
$ unzip packer_0.11.0_darwin_amd64.zip
Archive:  packer_0.11.0_darwin_amd64.zip
  inflating: packer
$ mv packer ~/bin/packer
$ packer version
Packer v0.11.0

$

今回は以下のPackerテンプレートを利用します。 packer.jsonとして適当なディレクトリに保存してください。

{
  "variables": {
    "ami_id"   : "ami-1a15c77b",
    "ami_name" : "PackerSample"
  },
  "builders": [
    {
      "type": "amazon-ebs",
      "communicator": "ssh",
      "ssh_pty" : "true",
      "region": "ap-northeast-1",
      "source_ami": "{{user `ami_id`}}",
      "instance_type": "t2.nano",
      "availability_zone" : "ap-northeast-1a",
      "ssh_username": "ec2-user",
      "ssh_timeout": "5m",
      "ami_name": "{{user `ami_name`}}_{{isotime | clean_ami_name}}"
    }
  ],
  "provisioners": [
    {
      "type": "shell",
      "inline": [
        "exit 1"
      ]
    }
  ]
}

provisioners のところで exit 1 と指定しているので、このPackerテンプレートは必ず実行に失敗します。その時の挙動を見てみましょう。

-on-error=cleanup

まずは -on-error=cleanup から。

$ packer build -on-error=cleanup packer.json
amazon-ebs output will be in this color.

==> amazon-ebs: Prevalidating AMI Name...
<...snip...>
==> amazon-ebs: Provisioning with shell script: /var/folders/wf/h6dvbxsx57gd4_xln0375j3h0000gq/T/packer-shell674948147
==> amazon-ebs: Terminating the source AWS instance...
==> amazon-ebs: Cleaning up any extra volumes...
==> amazon-ebs: No volumes to clean up, skipping
==> amazon-ebs: Deleting temporary security group...
Build 'amazon-ebs' errored: Script exited with non-zero exit status: 1

==> Some builds didn't complete successfully and had errors:
--> amazon-ebs: Script exited with non-zero exit status: 1

==> Builds finished but no artifacts were created.

今までと同様、作成したリソースがすべて消されています。

-on-error=ask

次に -on-error=ask を試します。

$ packer build -on-error=ask packer.json
amazon-ebs output will be in this color.

==> amazon-ebs: Prevalidating AMI Name...
<...snip...>
==> amazon-ebs: Step "StepProvision" failed
==> amazon-ebs:  Clean up and exit, [a] abort without cleanup, or [r] retry step (build may fail even if retry succeeds)? a
Build 'amazon-ebs' errored: unexpected EOF

==> Some builds didn't complete successfully and had errors:
--> amazon-ebs: unexpected EOF

エラーが発生した時に、どうするかを聞かれました。今回はa(=abort)を選んだので、作成されたリソースがそのまま残っています。

-on-error=abortの動きは上の例と一緒なので割愛します。

活用方法

さて、上でプロビジョニング失敗時のデバッグに役立つと書きました。ただ、Packerで利用されるSSH秘密鍵はPackerによって動的に生成されるため、そのままではSSHログインできません。なので、仕方なくPackerテンプレートにSSH秘密鍵を指定します。 *1 packer.json を下のように修正します。ハイライトされているところが変更点です。

{
  "variables": {
    "ami_id"   : "ami-1a15c77b",
    "ami_name" : "PackerSample"
  },
  "builders": [
    {
      "type": "amazon-ebs",
      "communicator": "ssh",
      "ssh_pty" : "true",
      "region": "ap-northeast-1",
      "source_ami": "{{user `ami_id`}}",
      "ssh_keypair_name" : "<AWSのキーペア名>",
      "ssh_private_key_file" : "<AWSキーペアに対応した秘密鍵のファイルパス>",
      "instance_type": "t2.nano",
      "availability_zone" : "ap-northeast-1a",
      "ssh_username": "ec2-user",
      "ssh_timeout": "5m",
      "ami_name": "{{user `ami_name`}}_{{isotime | clean_ami_name}}"
    }
  ],
  "provisioners": [
    {
      "type": "shell",
      "inline": [
        "exit 1"
      ]
    }
  ]
}

このテンプレートを -on-error=ask オプションを付与してbuildします。 エラーが出てプロンプトが表示されている時に、別のターミナルからSSHでログインすることが可能です。その時に指定する秘密鍵は packer.json で指定したものになります.

$ ssh -i <指定したキーペア> ec2-user@xx.xxx.xxx.xxx
Warning: Permanently added 'xx.xxx.xxx.xxx' (RSA) to the list of known hosts.
Last login: Wed Oct 26 06:41:38 2016

       __|  __|_  )
       _|  (     /   Amazon Linux AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-ami/2016.09-release-notes/
3 package(s) needed for security, out of 10 available
Run "sudo yum update" to apply all updates.
[ec2-user@ip-172-31-1-140 ~]$

まとめ

Packerを使いはじめて3年くらい経ちますが、Packerと一緒に利用しているAnsibleのエラーが出てイメージ作成が失敗してしまい、そのトラブルシューティングに苦心することが何度もありました。

今回リリースされた素晴らしい機能により、その手間を格段に減らすことができるようになるのではないでしょうか。是非活用しましょう!

脚注

  1. 汎用性が下がるためあまりやりたくない手段ではありますが...