HashiCorp Packer が HCP (HashiCorp Cloud Platform) で利用可能になりました
HCP (HashiCorp Cloud Platform) ってなに?
HashiCorp のプロダクトが SaaS モデルで利用可能なクラウドサービスです。
- Terraform Cloud
- HCP Vault
- HCP Consul
というラインナップがこれまで提供されていましたが、先日新たに HCP Packer が正式に GA (General Availability) として仲間に加わりました。
利用するためには HCP アカウントの作成が必要です。
HashiCorp プロダクトといえば OSS をまず想像しますが、近年はクラウドサービスにも力を入れており、今後も新たなプロダクトが追加されていく予定です。
Packer おさらい
Packer は HashiCorp の中でもかなり初期から存在する OSS プロダクトで (最初のリリースは2013年5月)、事前に定義された設定ファイルから "ゴールデンイメージ" を作成し、さらにそれを複数のプラットフォームへ簡単に展開することが可能です。
Amazon EC2 (AMI), Azure VM, GCP (GCE VM) などの主要なクラウドベンダーはもちろん、その他にも VMware や Docker など、様々な種類のイメージ作成に対応しています。
豊富な plugin も用意されており、例えば Ansible と組み合わせることにり、任意のアプリケーションのインストールや設定を行った上でイメージ化する、という一連の動作を簡単にコード化して自動化できます。
HCP Packer
現時点で HCP Packer が提供する唯一の機能は、HCP Packer Registry とよばれる、マシンイメージの metadata をクラウド上で管理するためのレジストリです。
*現時点では、HCP Packer == HCP Packer Registry だと思っても大丈夫です (いずれ HCP Packer ファミリーとして別の機能が提供されるまでは)。
重要なのは、HCP Packer Registry はあくまでもマシンイメージの metadata 保管場所であり、マシンイメージそのものが push される場所ではない、ということです。HCP Packer Registry は、既存の OSS Packer と組み合わせて使うことでそのメリットが最大限に発揮される、いわば extention のようなツールといえます。
HCP Packer Registry の何が嬉しいのか
ここまでの説明だけでは、単なる metadata レジストリの何が嬉しいのか、という感想に落ち着きます。
これにはまず HCP Packer Registry が解決しようとした問題を理解する必要があります。
特に大規模な環境での Packer 利用において、作成されたマシンイメージを "ちゃんと" 管理することの難しさが浮き彫りになってきました。イメージを簡単に作成し展開できるようになった一方で、実際には、
- どのマシンイメージが最新なのか
- そのマシンイメージはどの時点での Git commit に紐付いているのか
- IaC ツールに対してのイメージ ID (e.g., AMI ID) の更新作業
など、マシンイメージの提供者、マシンイメージの利用者、両者にとって管理コストが問題になるケースが多く聞かれました。
これを解決するため、Packer での build 時に HCP Packer Registry に対してイメージと紐づく metadata を同時に登録し、各イメージに対して任意の属性情報を持たせることで管理性を高め、外部ツールから目的のイメージ ID を簡単に取得するインターフェイスを提供する、というアイデアが生まれ、HCP Packer Registry が誕生しました。
Iterations と Channels
HCP Packer Registry の重要な概念として、Iterations
と Channels
があります。
Iterations
は、Packer での build 毎にインクリメントされ、それぞれの iteration にそのビルドによって作成されたマシンイメージの情報が追加されます。例えば下記の画像の例では、3つの iteration が存在する (3回ビルドが行われた) ことが分かります。
各 iteration をクリックすると、そのビルドの詳細が確認できます。
下記の画像の例では、AWS EC2 (AMI) および GCP (GCE VM) に対してそれぞれマシンイメージの作成が行われたことが分かります。
Channels
は、特定の channel に対して現在有効な iteration を1つアサインすることができるオブジェクトです。これにより、外部のツールは iteration のバージョンを気にすることなく、目的の channel 名さえ知っていれば、常に有効なマシンイメージの情報を取得できるようになります。
先ほどの interation 一覧の画面をもう一度見てみます。
この画面では、development
, staging
channel は iteration version 2
を利用、production
channel は iteration version 1
を利用、という設定が行われていることが分かります。
この状態で、例えば staging でマシンイメージが問題ないことが確認されたら、iteration version 2
を production
channel にもプロモートする、といった操作が簡単に行なえます。
Packer templates の書き方
HCP Packer Registry を使うには、build
block 内で hcp_packer_registry
を宣言します。下記は build block のみ抜粋しています。全体を含むサンプルはこちら
bucket_labels
はバケットレベルでの任意の label (bucket -> iteration という階層構造)、build_labels
は各ビルドに対する任意の label です。
build {
hcp_packer_registry {
bucket_name = "learn-packer-ubuntu"
description = <<EOT
Some nice description about the image being published to HCP Packer Registry.
EOT
bucket_labels = {
"owner" = "platform-team"
"os" = "Ubuntu",
"ubuntu-version" = "Focal 20.04",
}
build_labels = {
"build-time" = timestamp()
"build-source" = basename(path.cwd)
"git-commit-hash" = "${local.truncated_sha}"
"git-commit-author" = "${local.author}"
"foo" = "bar"
}
}
sources = [
"source.amazon-ebs.basic-example-west"
]
}
なお、全ての Builder plugin が HCP Packer Registry に対応している訳ではありません。利用する際には、対象の plugin ページに HCP Packer Ready
のマークが表示されているかどうかを確認してみてください。
例えば下記の Docker plugin では HCP Packer Ready
のマーク表示によって HCP Packer Registry に対応していることが分かります。
Terraform 連携
実際に HCP Packer Registry を Terraform の任意のワークフローから利用する際には、HashiCorp hcp
terraform provider の Data Source を利用します。
- https://registry.terraform.io/providers/hashicorp/hcp/latest/docs/data-sources/packer_image
- https://registry.terraform.io/providers/hashicorp/hcp/latest/docs/data-sources/packer_iteration
# This assumes HCP_CLIENT_ID and HCP_CLIENT_SECRET env variables are set
provider "hcp" { }
data "hcp_packer_iteration" "ubuntu" {
bucket_name = "learn-packer-ubuntu"
channel = "development"
}
data "hcp_packer_image" "ubuntu_us_west_1" {
bucket_name = "learn-packer-ubuntu"
cloud_provider = "aws"
iteration_id = data.hcp_packer_iteration.ubuntu.ulid
region = "us-west-1"
}
output "ubuntu_iteration" {
value = data.hcp_packer_iteration.ubuntu
}
output "ubuntu_us_west_1" {
value = data.hcp_packer_image.ubuntu_us_west_1
}
hcp_packer_iteration
data source 内で、対象のバケット名、そして最も重要な channel 名を指定します。今回の例では、development
channel を指定しています。つまり、development
channel に現在アサインされている iteration のビルドを利用することになります。
hcp_packer_image
では、上記の hcp_packer_iteration
data source から取得した情報を元に iteration_id
を設定します。さらに cloud_provider
, region
を設定することにより、その iteration に含まれる目的のマシンイメージを指定します。
これを実行すると、下記のような出力が得られます (一部省略)。
$ terraform plan
Changes to Outputs:
+ ubuntu_iteration = {
+ author_id = "HCP-Packer"
+ bucket_name = "learn-packer-ubuntu"
+ channel = "development"
...
}
+ ubuntu_us_west_1 = {
+ bucket_name = "learn-packer-ubuntu"
+ build_id = "01FYEXDSAXGJASSS9C2J0M61ZJ"
+ cloud_image_id = "ami-0b3c20f2fd2b1e282" // ← ここ
+ cloud_provider = "aws"
+ component_type = "amazon-ebs.basic-example-west"
+ created_at = "2022-03-18T16:23:00.701Z"
+ id = "01FYEXM8F2416Y3E44GK9TABZ2"
+ iteration_id = "01FYEXDRTZNVF4PVXHSYN6A752"
+ labels = {
+ "build-source" = "learn-hcp-packer-get-started"
+ "build-time" = "2022-03-18T16:22:57Z"
+ "git-commit-author" = "Shohei Maeda <xxxx>"
+ "git-commit-hash" = "e7a54117"
}
+ organization_id = "xxxx"
+ packer_run_uuid = "219ea822-334e-df64-541d-95705ebb536f"
+ project_id = "xxxx"
+ region = "us-west-1"
+ timeouts = null
}
hcp_packer_image
Data Source の出力に含まれる cloud_image_id
に、目的の AMI ID が含まれていることが分かります。この値を Terraform 内から参照することで、動的に任意の channel から対象のイメージ ID を取得することができ、Terraform 側で AMI ID を静的に管理する必要がなくなります。
必要となるのはあくまでもターゲットとなる channel
名であり、この channel にどの iteration がアサインされているかを利用者は意識する必要がありません。
セキュリティ・コンプライアンス対策としての iteration revocation 機能
HCP Packer Registry では iteration によって各ビルドを管理していることは説明しました。そしてこの iteration は 必要に応じて revoke (取り消し) することもできます。revoke された iteration は、ユーザーによって完全に削除されない限り再度 restore することも可能です。
例えば作成したマシンイメージにセキュリティ上の問題が見つかり、このイメージの利用を中止したい場合は Revoke immediately
によって即座に任意の iteration を revoke するができます。また、組織でのコンプライアンスを目的として、作成された iteration に対して、スケジュールされた未来日の revocation date を設定することもできます。これにより、作成したイメージに対して EOL (end of life) を設定するといった運用も可能になります。
この revoke された iteration がまだ任意の channel にアサインされている場合、その channel の利用者はマシンイメージの情報を得る事ができなくなります。試しに、先ほどの Terraform が参照していた developer
channel に現在アサインされている iteration を revoke し、再度実行してみます。
$ terraform plan
Changes to Outputs:
+ ubuntu_iteration = {
+ author_id = "HCP-Packer"
+ bucket_name = "learn-packer-ubuntu"
+ channel = "development"
...
}
+ ubuntu_us_west_1 = {
+ bucket_name = "learn-packer-ubuntu"
+ build_id = "01FYEXDSAXGJASSS9C2J0M61ZJ"
+ cloud_image_id = "error_revoked" // ← ここ
+ cloud_provider = "aws"
+ component_type = "amazon-ebs.basic-example-west"
+ created_at = "2022-03-18T16:23:00.701Z"
+ id = "01FYEXM8F2416Y3E44GK9TABZ2"
+ iteration_id = "01FYEXDRTZNVF4PVXHSYN6A752"
+ labels = {
+ "build-source" = "learn-hcp-packer-get-started"
+ "build-time" = "2022-03-18T16:22:57Z"
+ "git-commit-author" = "Shohei Maeda <xxxx>"
+ "git-commit-hash" = "e7a54117"
}
+ organization_id = "xxxx"
+ packer_run_uuid = "219ea822-334e-df64-541d-95705ebb536f"
+ project_id = "xxxx"
+ region = "us-west-1"
+ timeouts = null
}
分かりにくいですが、cloud_image_id
の値が error_revoked
となっています。
このように、revoke された後はイメージ ID は返されません。
この特性を条件分岐に使うことで、エラー時にはリソースの作成をスキップすることもできるでしょう。
resource "aws_instance" "app_server" {
count = data.hcp_packer_image.ubuntu_us_west_1.cloud_image_id == "error_revoked" ? 0 : 1
ami = data.hcp_packer_image.ubuntu_us_west_1.cloud_image_id
instance_type = "t2.micro"
tags = {
Name = "Learn-HCP-Packer"
}
}
Terraform Cloud Run Tasks との連携
Terraform Cloud の Business プランを利用している場合、HCP Packer が提供している Terraform Cloud Run Tasks 用の Task を利用することができます。
これにより、Terraform apply 時に HCP Packer が提供する Run Tasks のポリシーを強制することができます。例えば上記で説明した、イメージが既に revoke されている場合、plan と apply の間のステージで明確なエラーメッセージと共に実行を失敗させたり (このステージで Run Tasks が実行される)、HCP Packer "Plus" tier を利用している場合には、さらに Terraform の定義されたリソース内 (現時点でサポートされている対象リソースは一部のみ) でハードコードされたイメージ ID の検出を試み、見つかった場合には失敗させる、警告を出す、といった事も可能になります。
利用料金
詳細は下記をご覧ください。Standard Free
という無料のプランも用意されており、このプランでは最大で10個のイメージ、250 requests/month (API) まで利用可能です。
その他リソース
Discussion