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を日常的に使っていれば、同じ書き方でいける
徐々にシフトしていけばいいのではないかと思います。