
Packerのv1.7からpacker initプラグインをダウンロード・インストールできるようになったので試してみました。
目次
要件
以下に注意してください。
- packer v1.7以上
- テンプレートはHCL(Hashicorp Configuration Language)で書くこと、JSONは使えない
- packer init対応プラグインであること
HCLテンプレート
Apacheをインストール・起動するAWS AMIを作成する、シンプルなテンプレートで試してみましょう。JSONだとこんな感じです。
{ "variables": { "instance_type": "t2.micro", "region": "ap-northeast-1", "host": "webserver" }, "builders": [ { "type": "amazon-ebs", "region": "{{user `region`}}", "source_ami_filter": { "filters": { "name": "amzn2-ami-hvm-*-x86_64-gp2" }, "owners": ["137112412989"], "most_recent": true }, "instance_type": "{{user `instance_type`}}", "ssh_username": "ec2-user", "ssh_timeout": "5m", "ami_name": "{{user `host`}}-{{isotime | clean_resource_name}}", "tags": { "Base_AMI_ID": "{{ .SourceAMI }}", "Base_AMI_NAME": "{{ .SourceAMIName }}" } } ], "provisioners": [ { "type": "shell", "inline": [ "sudo yum update -y", "sudo amazon-linux-extras install -y epel", "sudo yum install -y @development jq git", "sudo yum install httpd -y", "echo 'version 1' | sudo tee /var/www/html/index.html", "sudo systemctl enable httpd" ] } ] }
HCLで書くとこうなります。Terraformっぽく複数のファイルに分けてみました。ファイル名は*.pkr.hclとするのが良いようです。
variables.pkr.hcl
変数の定義を行います。まんまTerraformと同じです。
variable "instance_type" {
default = "t2.micro"
}
variable "region" {
default = "ap-northeast-1"
}
variable "host" {
default = "webserver"
}
plugins.pkr.hcl
プラグインの設定です。
packer {
required_plugins {
amazon = {
version = ">= 0.0.1"
source = "github.com/hashicorp/amazon"
}
}
}
sources.pkr.hcl
これまでのprovisionersにあたるものです。これまでsource_ami_filterで指定していたのがdataを使って参照していますね。ぐっとTerraformっぽくなりました。
あと、テンプレのように書いていたclean_resource_nameですがHCLでは対応していないようです。
data "amazon-ami" "amazon_linux2" {
filters = {
name = "amzn2-ami-hvm-*-x86_64-gp2"
}
most_recent = true
owners = ["137112412989"]
region = "ap-northeast-1"
}
source "amazon-ebs" "webserver" {
region = var.region
source_ami = data.amazon-ami.amazon_linux2.id
instance_type = var.instance_type
ssh_username = "ec2-user"
ssh_timeout = "5m"
ami_name = "${var.host}-{{ timestamp }}"
tags = {
Base_AMI_ID = "{{ .SourceAMI }}"
Base_AMI_NAME = "{{ .SourceAMIName }}"
}
}
build.pkr.hcl
これまでのbuildersにあたるものです。sourcesのところでsources.pkr.hclの定義を呼んでいます。
build {
sources = [
"source.amazon-ebs.webserver"
]
provisioner "shell" {
inline = [
"sudo yum update -y",
"sudo amazon-linux-extras install -y epel",
"sudo yum install -y @development jq git",
"sudo yum install httpd -y",
"echo 'version 1' | sudo tee /var/www/html/index.html",
"sudo systemctl enable httpd"
]
}
}
最終的にこんな感じで一つのディレクトリ内においておきます。
$ ls
build.pkr.hcl plugins.pkr.hcl sources.pkr.hcl variables.pkr.hcl variables.pkrvars.hcl
ではプラグインをインストールしましょう。packer initでプラグインを記載したhclファイル(plugins.pkr.hcl)か、hclファイルのあるディレクトリを指定します。ここではカレントディレクトリを指定しました。
$ packer init . Installed plugin github.com/hashicorp/amazon v0.0.1 in "/XXX/XXX/.packer.d/plugins/github.com/hashicorp/amazon/packer-plugin-amazon_v0.0.1_x5.0_darwin_amd64"
プラグインは~/.packer.d/plugins配下にダウンロードされます。
~/.packer.d/plugins/
└── github.com
└── hashicorp
└── amazon
├── packer-plugin-amazon_v0.0.1_x5.0_darwin_amd64
└── packer-plugin-amazon_v0.0.1_x5.0_darwin_amd64_SHA256SUM
packer validateも使えます(v1.7リリース時は使えなかったみたいですがv1.7.2では使えました)
$ packer validate . Error: Unknown source type amaozn-ebs on line 0: (source code not available) known builders: [vsphere-clone hyperone proxmox vmware-iso digitalocean virtualbox-ovf amazon-instance vagrant amazon-ebssurrogate openstack googlecompute jdcloud hyperv-iso docker hyperv-vmcx parallels-pvm profitbricks proxmox-iso virtualbox-iso cloudstack lxc vsphere-iso lxd amazon-ebsvolume amazon-ebs hcloud ncloud azure-chroot proxmox-clone scaleway ucloud-uhost linode triton file oneandone alicloud-ecs parallels-iso qemu amazon-chroot osc-chroot azure-arm null oracle-oci tencentcloud-cvm azure-dtl osc-bsusurrogate vmware-vmx osc-bsuvolume oracle-classic osc-bsu yandex virtualbox-vm]
ではビルドしてみましょう。
$ packer build .
amazon-ebs.webserver: output will be in this color.
==> amazon-ebs.webserver: Prevalidating any provided VPC information
==> amazon-ebs.webserver: Prevalidating AMI Name: webserver-1620491713
amazon-ebs.webserver: Found Image ID: ami-0ca38c7440de1749a
==> amazon-ebs.webserver: Creating temporary keypair: packer_XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
==> amazon-ebs.webserver: Creating temporary security group for this instance: packer_XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
==> amazon-ebs.webserver: Authorizing access to port 22 from [0.0.0.0/0] in the temporary security groups...
==> amazon-ebs.webserver: Launching a source AWS instance...
==> amazon-ebs.webserver: Adding tags to source instance
amazon-ebs.webserver: Adding tag: "Name": "Packer Builder"
amazon-ebs.webserver: Instance ID: i-XXXXXXXXXXXXXXXX
==> amazon-ebs.webserver: Waiting for instance (i-XXXXXXXXXXXXXXXX) to become ready...
==> amazon-ebs.webserver: Using ssh communicator to connect: 54.250.137.121
==> amazon-ebs.webserver: Waiting for SSH to become available...
==> amazon-ebs.webserver: Connected to SSH!
==> amazon-ebs.webserver: Provisioning with shell script: /var/folders/c8/XXXXXXXXXXXXXXXXXXXXXXXX/T/packer-shellXXXXXXXXX
(snip)
==> amazon-ebs.webserver: Stopping the source instance...
amazon-ebs.webserver: Stopping instance
==> amazon-ebs.webserver: Waiting for the instance to stop...
==> amazon-ebs.webserver: Creating AMI webserver-XXXXXXXXXX from instance i-XXXXXXXXXXXXXXXX
amazon-ebs.webserver: AMI: ami-XXXXXXXXXXXXXXXX
==> amazon-ebs.webserver: Waiting for AMI to become ready...
==> amazon-ebs.webserver: Adding tags to AMI (ami-XXXXXXXXXXXXXXXX)...
==> amazon-ebs.webserver: Tagging snapshot: snap-XXXXXXXXXXXXXXXX
==> amazon-ebs.webserver: Creating AMI tags
amazon-ebs.webserver: Adding tag: "Base_AMI_ID": "ami-0ca38c7440de1749a"
amazon-ebs.webserver: Adding tag: "Base_AMI_NAME": "amzn2-ami-hvm-2.0.20210427.0-x86_64-gp2"
==> amazon-ebs.webserver: Creating snapshot tags
==> amazon-ebs.webserver: Terminating the source AWS instance...
==> amazon-ebs.webserver: Cleaning up any extra volumes...
==> amazon-ebs.webserver: No volumes to clean up, skipping
==> amazon-ebs.webserver: Deleting temporary security group...
==> amazon-ebs.webserver: Deleting temporary keypair...
Build 'amazon-ebs.webserver' finished after 4 minutes 12 seconds.
==> Wait completed after 4 minutes 12 seconds
==> Builds finished. The artifacts of successful builds are:
--> amazon-ebs.webserver: AMIs were created:
ap-northeast-1: ami-XXXXXXXXXXXXXXXX
できました。
プラグインを使ってみる
AMIの作成自体もプラグインで行ったわけですが、他のプラグインも使ってみましょう。
以下で紹介されているAMIの世代管理を行ってくれるプラグイン"amazon-ami-management"を使ってみます。
plugins.pkr.hclを修正します。
packer {
required_plugins {
amazon = {
version = ">= 0.0.1"
source = "github.com/hashicorp/amazon"
}
amazon-ami-management = {
version = ">= 1.0.0"
source = "github.com/wata727/amazon-ami-management"
}
}
}
プラグインをインストールします。
$ packer init . Installed plugin github.com/wata727/amazon-ami-management v1.1.2 in "/XXX/XXX/.packer.d/plugins/github.com/wata727/amazon-ami-management/packer-plugin-amazon-ami-management_v1.1.2_x5.0_darwin_amd64"
AMIのタグでAmazon_AMI_Management_Identifierを付与します。"amazon-ami-management"プラグインはこのタグから世代数を確認するようです。sources.pkr.jsonを修正します。
(snip)
tags = {
Base_AMI_ID = "{{ .SourceAMI }}"
Base_AMI_NAME = "{{ .SourceAMIName }}"
Amazon_AMI_Management_Identifier = var.host
}
(snip)
プラグインの設定はpost-processorsセクションで設定します。JSONの場合は独立したセクションでしたが、HCLの場合はbuildの中になります。build.pkr.hclを以下のように修正します。
build {
sources = [
"source.amazon-ebs.webserver"
]
provisioner "shell" {
inline = [
"sudo yum update -y",
"sudo amazon-linux-extras install -y epel",
"sudo yum install -y @development jq git",
"sudo yum install httpd -y",
"echo 'version 1' | sudo tee /var/www/html/index.html",
"sudo systemctl enable httpd"
]
}
# 以下を追加
post-processor "amazon-ami-management" {
regions = [var.region]
identifier = var.host
keep_releases = 3
}
}
あと、identifierで指定した文字列が
何度かビルドしてみると、AMIが3世代だけ残っていることが確認できると思います。
変数のオーバーライド
-varや-var-fileを使った変数のオーバーライドはこれまでと同じです。
$ packer build -var host=webserver2 .
$ packer build -var-file=variables.pkrvars.file .
ファイル名は*.pkrvars.hclにするのがよいようです。中身はこんな感じです。
host = "webserver2"
環境ごとに変数を分けて複数の環境に対応するようなケースは、これまでと同じやり方でいけそうです。
既存のJSONテンプレートからHCLテンプレートに変換する
packer hc2_upgradeを使うと、既存のJSONテンプレートをHCLに変換してくれます。
$ packer hcl2_upgrade packer.json Successfully created packer.json.pkr.hcl
中身を見てみるとこんな感じです。
variable "host" {
type = string
default = "webserver"
}
variable "instance_type" {
type = string
default = "t2.micro"
}
variable "region" {
type = string
default = "ap-northeast-1"
}
data "amazon-ami" "autogenerated_1" {
filters = {
name = "amzn2-ami-hvm-*-x86_64-gp2"
}
most_recent = true
owners = ["137112412989"]
region = "${var.region}"
}
# 1 error occurred upgrading the following block:
# unhandled "clean_resource_name" call:
# there is no way to automatically upgrade the "clean_resource_name" call.
# Please manually upgrade to use custom validation rules, `replace(string, substring, replacement)` or `regex_replace(string, substring, replacement)`
# Visit https://packer.io/docs/templates/hcl_templates/variables#custom-validation-rules , https://www.packer.io/docs/templates/hcl_templates/functions/string/replace or https://www.packer.io/docs/templates/hcl_templates/functions/string/regex_replace for more infos.
source "amazon-ebs" "autogenerated_1" {
ami_name = "${var.host}-{{ clean_resource_name `${timestamp()}` }}"
instance_type = "${var.instance_type}"
region = "${var.region}"
source_ami = "${data.amazon-ami.autogenerated_1.id}"
ssh_timeout = "5m"
ssh_username = "ec2-user"
tags = {
Base_AMI_ID = "{{ .SourceAMI }}"
Base_AMI_NAME = "{{ .SourceAMIName }}"
}
}
build {
sources = ["source.amazon-ebs.autogenerated_1"]
provisioner "shell" {
inline = ["sudo yum update -y", "sudo amazon-linux-extras install -y epel", "sudo yum install -y @development jq git", "sudo yum install httpd -y", "echo 'version 1' | sudo tee /var/www/html/index.html", "sudo systemctl enable httpd"]
}
}
上でも記載したとおり、clean_resource_nameは使えないので修正が必要、ということで、コメントとして記載されています。
多少の修正は必要になるかもしれませんが、イチから書き直さなくていいので便利ですね。
まとめ
Packerについて調べると、ほとんどがJSONの情報で、HCLでの情報はあまり見当たらないのが辛いところですが、色々メリットもあります。
- JSONの使いにくさ(ケツカンマでコケる、コメント入れれない、そもそも見にくい)に悩まされることもなくなる
- プラグインが手軽に使える
- 既存のJSONからの変換もできる
- Terraformを日常的に使っていれば、同じ書き方でいける
徐々にシフトしていけばいいのではないかと思います。