💭

Pakcerで異なるsourceのビルドを並列処理する時、buildブロックを複数指定する

2022/03/15に公開

環境

  • Packer v1.7.9

経緯

  • 1つのテンプレート・1つのbuildブロックで複数のsourceを実行したかったのだが、変数を使用しているのでできなかった
    • (なぜ)buildを並列処理してビルド時間を短縮したかった
    • packer実行時に変数appを引数から取得する
    • provisioningブロックでAnsibleを実行するとき、appを渡す
      • appの値がそれぞれのsourceで違うため、同一のbuildブロックを使用できない

結果

手順

ディレクトリ構成

$ tree mock
mock
├── packer.sh
├── packer
│   └── foo.pkr.hcl # 1つのテンプレート
└── provisioning
    ├── doc
    ├── group_vars
        ├── fuga.yml
    │   └── foo.yml
    ├── roles
    │   // 省略
    ├── fuga.yml 
    └── foo.yml
  • packer buildするとき
$ pwd
mock
$ sh packer.sh foo dev
  • 実行するスクリプト
packer.sh
APP=$1
ENV=$2
# 変数ファイル
(echo app=\"${APP}\"; echo env=\"${ENV}\") > packer/${APP}.pkrvars.hcl
# 変数ファイルを使ってビルド
packer validate -var-file="packer/${app}.pkrvars.hcl" ${app}.pkr.hcl
packer build -var-file="packer/${app}.pkrvars.hcl" packer/${app}.pkr.hcl

実現したかったこと

foo.pkr.hcl

source "amazon-ebs" "foo" {
  ami_description               = "foo ami"
  ami_name                      = "${var.image_name}-foo"
// 省略
}

source "amazon-ebs" "fuga" {
  ami_description               = "fuga ami"
  ami_name                      = "${var.image_name}-fuga"
// 省略
}

build {
  sources = [ 
    "source.amazon-ebs.foo",
    "source.amazon-ebs.fuga" // sourceを複数指定する
  ]
 

  provisioner "ansible" {
    extra_arguments = ["-vv", "--extra-vars", "app=${var.app} env=${var.env}"] // ここで変数`app`の値がそれぞれのsourceで異なるので実行できない
    playbook_file   = "provisioning/${var.app}.yml" // playbookの中身も違ったりする
    user            = "ec2-user"
  }

  post-processor "manifest" {
    output     = "manifest.json"
    strip_path = true
  }
}

修正後

foo.prk.hcl
source "amazon-ebs" "foo" {
  ami_description               = "foo ami"
  ami_name                      = "${var.image_name}-foo"
// 省略
}

source "amazon-ebs" "huga" {
  ami_description               = "huga ami"
  ami_name                      = "${var.image_name}-fuga"
// 省略
}

build {
  sources = [ 
    "source.amazon-ebs.foo"
  ]
 

  provisioner "ansible" {
    extra_arguments = ["-vv", "--extra-vars", "app=${var.app} env=${var.env}"] 
    playbook_file   = "provisioning/${var.app}.yml"
    user            = "ec2-user"
  }

  post-processor "manifest" {
    output     = "manifest.json"
    strip_path = true
  }
}

build {
  sources = [ 
    "source.amazon-ebs.fuga"
  ]

  provisioner "ansible" {
    extra_arguments = ["-vv", "--extra-vars", "app=fuga env=${var.env}"] // 変数を使わず直接指定
    playbook_file   = "provisioning/fuga.yml" // playbook名も直接指定
    user            = "ec2-user"
  }

  post-processor "manifest" {
    output     = "manifest_fuga.json" // manifestファイルは出しわけ
    strip_path = true
  }
}

  • 実行結果
    • 実行結果が出力される
    • 並行して処理されていることがわかる
    • 1つずつ処理していた時と比べ、処理時間短縮できた(およそ1/2ぐらい)
packer.sh
# 省略
amazon-ebs.foo: prevalidationg AMI Name: test-foo
amazon-ebs.fuga: prevalidationg AMI Name: test-fuga
# 省略

Discussion