サーバープロビジョニングのアプローチ:Bake(事前構築)vs. Fry(即時構成)
AWS、Azure、またはオンプレミスのハイパーバイザー上で仮想マシンを起動する際、プラットフォームチームは通常、ジャストインタイムプロビジョニング(“Fry”)と事前構築済みイメージ(“Bake”)という2つのワークフローのいずれかを選択します。
“Fry”モデルでは、Ubuntu 22.04 LTSやAmazon Linux 2023などの標準的なバニラOSイメージから起動を開始します。ブート時にcloud-init、Ansible、Chefなどのツールが順次実行されます。
これらのツールはパッケージのインストール、アプリケーションバイナリの取得、監視エージェントの設定、セキュリティベースラインの適用などを担います。このモデルはイメージストレージの消費を最小限に抑えられる反面、インスタンスの起動処理が脆弱なボトルネックになります。aptミラーの一時的なタイムアウトや上流のGitHubレート制限が1つ発生しただけで、金曜日のトラフィック急増時にAuto Scalingの処理が完全に失敗してしまいます。
HashiCorp Packerを用いた“Bake”モデルは、この問題を解決します。すべてのOSパッチ、カーネル調整、ランタイム、ログ収集エージェントを、デプロイ前に不変(イミュータブル)なスナップショットとして直接焼き込みます。Auto Scaling Group(ASG)が新たに20台のインスタンスを要求した場合でも、すべての依存関係がすでにディスク上に配置されているため、各VMは45秒未満で起動します。
Packerでゴールデンイメージを構築するメリットとデメリット
VMイメージをビルド成果物として扱うアプローチには、事前に考慮すべき特有のトレードオフが存在します。
メリット
- 高速で予測可能なオートスケーリング:ランタイムを事前に組み込んでおくことで、これまで15〜20分かかっていた起動時のブートストラップ処理を35〜50秒に短縮できます。
- 構成ドリフトの完全排除:本番環境のマシンに対するアドホックなSSHログインによる変更を防ぎます。エージェントの更新が必要な場合は、新しいイメージバージョンをリリースします。
- 統一されたマルチクラウドテンプレート:Packer HCL2を使用することで、単一の共有設定ファイルから1回のCI実行でAWS AMI、Azure Managed Image、GCPディスクイメージを出力できます。
- シフトレフトセキュリティ:ワークロードが本番環境に到達する前に、TrivyやOpenSCAPなどの脆弱性スキャナーを使用してビルドパイプライン内でイメージスナップショットを検査できます。
デメリット・トレードオフ
- イメージストレージの肥大化:不要になったEBSスナップショットを5つのAWSリージョンに放置すると、GB月あたり0.05ドルのコストが急速に蓄積します。不要なAMIの登録を解除する自動ライフサイクルポリシーの実装が不可欠です。
- パイプラインのオーバーヘッド:インスタンスの起動はほぼ瞬時に完了しますが、ビルダーVMの起動、プロビジョナーの実行、スナップショットの書き出し、リソースのクリーンアップなど、事前のCIビルドに8〜15分程度の時間を要します。
推奨構成:Packer HCL2 & CI/CDアーキテクチャ
非推奨となったJSONテンプレートは避け、Packerの最新構文であるHCL2で統一してください。リポジトリはモジュール化されたビルダーと疎結合なBashプロビジョナーで構成します。
packer-golden-images/
├── .github/
│ └── workflows/
│ └── build-ami.yml
├── config/
│ ├── common-variables.pkrvars.hcl
│ └── security-baseline.sh
├── scripts/
│ └── install-telemetry.sh
└── templates/
└── ubuntu-base.pkr.hcl
CI/CD検証パイプラインの構築には、バイナリチェックサムの検証、マニフェストの変換、ビルド用VPCサブネットのサイジングなど、開発者による反復作業が伴います。こうした迅速な運用の確認作業には、ToolCraftを頻繁に利用しています。すべてのユーティリティがブラウザ内のクライアントサイドで完結して動作するため、プライベートネットワーク設定や秘密鍵がリモートサーバーに送信されることはありません。
サードパーティのバイナリをテンプレートへcurlで取得する前に、ベンダーのリリース文字列をHash GeneratorにペーストしてSHA-256ハッシュを即座に確認しています。従来のJSON形式のPacker設定を最新のHCLブロックに移行する際も、YAML ↔ JSON Converterを利用することで構文のクリーンアップを迅速化できます。同様に、企業のCIDRブロックと重複しないビルド用サブネットの設計も、Subnet Calculatorを使えば簡単に行えます。
ステップ・バイ・ステップ実装ガイド
以下は、AWS上でUbuntu 22.04 LTS AMIをビルドし、GitHub Actionsと連携させるエンドツーエンドの構成例です。
1. Packerテンプレートの定義 (`ubuntu-base.pkr.hcl`)
このテンプレートではAWSプラグインのバージョンを固定し、Canonicalの公式AMIレジストリを検索した上で、スナップショット作成前にインスタンス固有の状態を削除します。
packer {
required_plugins {
amazon = {
version = ">= 1.2.8"
source = "github.com/hashicorp/amazon"
}
}
}
variable "aws_region" {
type = string
default = "us-east-1"
}
variable "environment" {
type = string
default = "production"
}
data "amazon-ami" "ubuntu_lts" {
filters = {
name = "ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"
root-device-type = "ebs"
virtualization-type = "hvm"
}
most_recent = true
owners = ["099720109477"] # Canonical公式アカウントID
}
source "amazon-ebs" "base_linux" {
ami_name = "golden-linux-${var.environment}-{{timestamp}}"
instance_type = "t3.micro"
region = var.aws_region
source_ami = data.amazon-ami.ubuntu_lts.id
ssh_username = "ubuntu"
tags = {
Name = "Golden-Linux-Image"
Environment = var.environment
BuiltBy = "Packer-CI"
}
}
build {
name = "hardened-ubuntu"
sources = ["source.amazon-ebs.base_linux"]
# 1. OSパッケージの更新と主要セキュリティユーティリティのインストール
provisioner "shell" {
inline = [
"export DEBIAN_FRONTEND=noninteractive",
"sudo apt-get update -y",
"sudo apt-get upgrade -y",
"sudo apt-get install -y fail2ban curl jq unattended-upgrades ufw"
]
}
# 2. テレメトリおよびデーモン堅牢化スクリプトの実行
provisioner "shell" {
script = "./scripts/install-telemetry.sh"
}
# 3. ビルド成果物のクリーンアップと複製ホスト間の競合を防ぐmachine-idの初期化
provisioner "shell" {
inline = [
"sudo truncate -s 0 /etc/machine-id",
"sudo rm -f /var/lib/dbus/machine-id",
"sudo apt-get clean",
"sudo rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*"
]
}
}
2. システム堅牢化およびテレメトリスクリプトの追加
このスクリプトをscripts/install-telemetry.shとして保存します。Prometheus Node Exporter v1.7.0を導入し、SSHのルートログインおよびパスワード認証を無効化します。
#!/usr/bin/env bash
set -euo pipefail
echo "Prometheus Node Exporterをインストール中..."
NODE_EXPORTER_VERSION="1.7.0"
curl -fsSL "https://github.com/prometheus/node_exporter/releases/download/v${NODE_EXPORTER_VERSION}/node_exporter-${NODE_EXPORTER_VERSION}.linux-amd64.tar.gz" \
-o /tmp/node_exporter.tar.gz
tar -xzf /tmp/node_exporter.tar.gz -C /tmp/
sudo mv "/tmp/node_exporter-${NODE_EXPORTER_VERSION}.linux-amd64/node_exporter" /usr/local/bin/
rm -rf /tmp/node_exporter*
sudo useradd --system --no-create-home --shell /bin/false node_exporter 2>/dev/null || true
echo "SSHデーモンを堅牢化中..."
sudo mkdir -p /etc/ssh/sshd_config.d
cat <<'EOF' | sudo tee /etc/ssh/sshd_config.d/99-golden-hardening.conf
PermitRootLogin no
PasswordAuthentication no
X11Forwarding no
MaxAuthTries 3
EOF
sudo chmod 600 /etc/ssh/sshd_config.d/99-golden-hardening.conf
echo "堅牢化が完了しました。"
3. GitHub Actionsによるビルド自動化
mainブランチへのプッシュをトリガーにするか、毎週の定期実行(cron)を設定して最新のOSセキュリティパッチを自動適用します。
name: Golden AMIのビルド
on:
push:
branches:
- main
paths:
- 'templates/**'
- 'scripts/**'
schedule:
- cron: '0 3 * * 0' # 毎週日曜日の03:00 UTCに定期実行
workflow_dispatch:
jobs:
packer-build:
name: Packerの検証とビルドを実行
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- name: ソースコードのチェックアウト
uses: actions/checkout@v4
- name: HashiCorp Packerのセットアップ
uses: hashicorp/setup-packer@main
with:
version: "1.10.0"
- name: AWS認証情報の設定 (OIDC)
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/packer-build-role
aws-region: us-east-1
- name: Packerプラグインの初期化
run: packer init templates/ubuntu-base.pkr.hcl
- name: 構文チェックの実行
run: packer validate templates/ubuntu-base.pkr.hcl
- name: AMIのビルド
run: packer build -color=false templates/ubuntu-base.pkr.hcl
4. TerraformまたはOpenTofuでゴールデンイメージを利用する
AWSプロバイダーのデータフィルターを活用し、IaC設定から最新の検証済みイメージを参照します。
data "aws_ami" "latest_golden_image" {
most_recent = true
owners = ["self"]
filter {
name = "name"
values = ["golden-linux-production-*"]
}
filter {
name = "tag:BuiltBy"
values = ["Packer-CI"]
}
}
ベースイメージを自動化することで、VMプロビジョニングは予測不能なボトルネックから、約40秒で完了する安定したルーチンへと生まれ変わります。週次のイメージ再ビルドとCIでの自動脆弱性テストを組み合わせることで、稼働中のワークロードに影響を与えることなく、クラウド環境全体に常に最新のパッチを適用し続けることが可能になります。

