コンテンツにスキップ

テンプレート

はじめに

本サイトにつきまして、【IT技術の知見】はじめに - 俺の技術ノート をご認識のほど宜しくお願いいたします。


01. セットアップ

インストール

▼ apt リポジトリから

$ curl -L https://apt.releases.hashicorp.com/gpg | sudo apt-key add -
$ sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main"
$ sudo apt-get update && sudo apt-get install packer


GitHub Actions 上で実行する場合

.github/workflows/packer.yml に配置し、手動実行またはタグの push で AMI を作成する。Repository variables に AWS_ACCOUNT_ID を登録し、AWS 側には sts.amazonaws.com を audience とする GitHub OIDC プロバイダーと github-actions-packer IAM ロールを用意する。ロールの信頼ポリシーで対象リポジトリ・ブランチ・タグを制限し、AMI 作成に必要な権限を付与する。

name: Build AMI

on:
  workflow_dispatch:
  push:
    tags: ["**"]

permissions:
  contents: read
  # AWSのIAMロールを引き受けるためのOIDCトークンを取得する。
  id-token: write

env:
  AWS_REGION: ap-northeast-1

jobs:
  build-ami:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: recursive
          fetch-depth: 0
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::${{ vars.AWS_ACCOUNT_ID }}:role/github-actions-packer
          aws-region: ${{ env.AWS_REGION }}
          role-duration-seconds: 1800
          retry-max-attempts: 6
      - uses: hashicorp/setup-packer@v3
        with:
          version: "1.14.0"
      - name: Resolve source AMI
        run: |
          aws sts get-caller-identity
          SOURCE_IMAGE_ID=$(aws ssm get-parameter \
            --name /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-x86_64 \
            --query 'Parameter.Value' --output text)
          echo "source ami-id: $SOURCE_IMAGE_ID"
          # Packerの実行ステップにAMI IDを渡す。
          echo "SOURCE_IMAGE_ID=$SOURCE_IMAGE_ID" >> "$GITHUB_ENV"
      - name: Build AMI
        run: |
          packer init template.pkr.hcl
          packer build template.pkr.hcl
      - name: Inspect built AMI and tag annotation
        env:
          COMMIT_TAG: ${{ github.ref_type == 'tag' && github.ref_name || '' }}
        run: |
          AMI_NAME="foo-$(date "+%Y-%m-%d")"
          AMI_ID=$(aws ec2 describe-images --region "$AWS_REGION" --owners self --filters "Name=name,Values=${AMI_NAME}" --query 'Images[*][ImageId]' --output text)
          SOURCE_IMAGE_NAME=$(git tag -l $COMMIT_TAG -n | awk '{print $2}' | jq -r .image_name)
          echo "$SOURCE_IMAGE_NAME"

template.pkr.hcl は env("SOURCE_IMAGE_ID") で取得した AMI ID を参照する想定である。テンプレートが異なる変数名を使う場合は、それに合わせて渡し方を変更する。


02. build

sources

実行する source を設定する。

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


provisioner

build {

  provisioner "shell-local" {

  }
}
build {

  provisioner "shell" {

  }
}
build {

  provisioner "ansible" {

  }
}


03. provisioner

provisioner とは

サーバー/コンテナのプロビジョナーを設定する。


ansible の場合

▼ playbook_file

build {

  provisioner "ansible" {
    playbook_file = "playbook.yml"
  }
}

▼ user

build {

  provisioner "ansible" {
    user = "ec2-user"
  }
}


shell-local の場合

▼ shell-local

Ansible は、コントロールノード (ansible デプロイサーバー) と管理対象ノード (ansible デプロイ先サーバー) から構成される。

shell-local では、コントロールノードで実行するコマンドを設定する。

▼ inline

build {

  provisioner "shell-local" {
    command = "ansible-galaxy install -f -r requirements.yml -p roles"
  }
}


shell の場合

▼ shell とは

Ansible は、コントロールノード (ansible デプロイサーバー) と管理対象ノード (ansible デプロイ先サーバー) から構成される。

shell では、管理対象ノードで実行するコマンドを設定する。

▼ inline

build {

  provisioner "shell" {
    inline = ["echo Hello World"]
  }
}


04. packer

packer とは


required_plugins

packer {

  required_plugins {
    amazon = {
      source  = "github.com/hashicorp/amazon"
      version = "~> 1"
    }
    ansible = {
      source  = "github.com/hashicorp/ansible"
      version = "~> 1"
    }
  }
}


05. source

source とは

作成するマシンイメージやコンテナイメージの内容を設定する。


amazon-ebs の場合

▼ ami_name

AWS AMI の名前を設定する。

source "amazon-ebs" "foo" {
  "ami_name" = "bar-ami"
}

▼ ami_users

source "amazon-ebs" "foo" {
  "ami_users" = "<AWSアカウントID>"
}

▼ ena_support

source "amazon-ebs" "foo" {
  "ena_support" = true
}

▼ encrypt_boot

source "amazon-ebs" "foo" {
  "encrypt_boot" = false
}

▼ force_deregister

同じ名前のマシンイメージが存在する場合に、既存のマシンイメージを登録解除してからこれを作成するか否かを設定する。

Packer の作成するマシンイメージの名前は、ランダム値をつけない限り、常に同じである。

マシンイメージの名前の重複を許可しないプロバイダー (例:AWS) では、1 個の名前のマシンイメージを 1 回しか作成できないことになってしまう。

そういった場合に使用する。

source "amazon-ebs" "foo" {
  "force_deregister" = true
}

▼ instance_type

source "amazon-ebs" "foo" {
  "instance_type" = "t2.micro"
}

▼ launch_block_device_mappings

EC2 に紐付けるルートデバイスボリュームを設定する。

source "amazon-ebs" "foo" {
  "launch_block_device_mappings" = [
    {
      # ルートボリューム
      "device_name": "/dev/xvda",
      "volume_type": "gp2",
      # AWS AMIの作成後に、元となったEC2のボリュームを削除する
      "delete_on_termination": "true",
      "volume_size": "300",
    },
  ]
}

▼ region

AWS AMI を作成するリージョンを設定する。

source "amazon-ebs" "foo" {
  "region" = "ap-northeast-1"
}

▼ snapshot_users

source "amazon-ebs" "foo" {
  "snapshot_users" = "<AWSアカウントID>"
}

▼ source_ami

AWS AMI の基とする AWS AMI (例:Amazon Linux 2 AMI) を設定する。

source "amazon-ebs" "foo" {
  "source_ami" = "ami-0b7546e839d7ace12"
}

▼ ssh_username

EC2 への SSH 公開鍵認証時に使用するユーザー名を設定する。

source "amazon-ebs" "foo" {
  "ssh_username" = "ec2-user"
}

▼ temporary_key_pair_type

暗号化キーの種類を設定する。

source "amazon-ebs" "foo" {
  "temporary_key_pair_type" = "rsa"
}


06. variable

variable とは

ファイル内で使用する変数を設定する。

variable "region" {
  type    = string
  default = "ap-northeast-1"
}

source "amazon-ebs" "foo" {
  "region" = "${var.region}"
}


07. 関数

関数を使用できるブロック

Packer では、variables ブロックには定数を設定する必要があるため、関数は variables ブロックで使用できない。

variables ブロックの値を一度 locals ブロックで加工する必要がある。