HashiCorp PackerとProxmox VEの実践ガイド:標準化されたGolden Image構築パイプラインの自動化

現場のリアルな課題:サーバークラスター拡大に伴う手動VM構築の悪夢

約半年前、私たちのチームは社内サービスインフラの再構築と、Proxmox VE上でのKubernetesクラスター拡張プロジェクトを担当することになりました。当初は従来通りの慣れ親しんだ手順で行っていました。ストレージにUbuntu ServerのISOファイルをダウンロードし、Web GUIから空のVMを作成して、ウィザードの「次へ」を1ステップずつクリックしてインストールを進めます。その後、静的IPの設定、ユーザー作成、SSHキーの登録、そしてqemu-guest-agentの追加インストールを行いました。すべて完了したら、後から複製して使い回せるようにVMをTemplate(テンプレート)へと変換していました。

しかし、規模拡大のスピードが加速するにつれて問題が生じ始めました。k3sクラスターやステージング環境向けに、毎週20〜30台ものVMを新規構築する必要が出てきたのです。この時点で、3ヶ月前に作成したテンプレートには、数百件にも及ぶ重要なカーネルパッチが適用されていませんでした。

新しいVMをクローンするたびに、エンジニアはapt update && apt upgradeを実行し、Dockerをインストールし、タイムゾーンやlogrotateを設定するために毎回15〜20分もの時間を費やしていました。極めつけは、ある開発者がマシンをクローンした際にQEMU agentの起動を忘れてしまったトラブルです。PrometheusとGrafanaがホストのIPアドレスを取得できなくなり、メトリクスの収集が完全に停止してしまいました。

私自身、自宅でも本番環境に導入する前の検証用として、12台のVMとLXCコンテナを稼働させる小規模なProxmoxホームラボを運用しています。しかし、ホームラボであっても手動でのスナップショット作成やテンプレート化は極めて煩雑でした。ZFSストレージは無駄に数百GBも消費され、何よりもテンプレート内にどのパッケージがインストールされているのか誰も把握できず、手順全体がGit管理から完全に外れてしまっていたのです。

なぜ手動作成のVMテンプレートは必ず「構成ドリフト(Configuration Drift)」を引き起こすのか?

数ヶ月にわたる実際の運用の結果、手動作業によるアプローチには3つの大きなボトルネックがあることがわかりました:

  • 再現性の欠如(Lack of Reproducibility):noVNC画面上でのマウスクリック操作には、監査ログが一切残りません。以前テンプレートを作成した担当者がLVMパーティションをどのように構成したか、どのサービスを有効/無効にしたか、あるいは重要なセキュリティ設定を誤って見落としていないかを確実に把握することは不可能です。
  • 構成ドリフト(Configuration Drift):元のテンプレートは作成時点の状態で固定されてしまいます。一方で、外部のソフトウェアパッケージ、SSL証明書、カーネルパッチは日々更新され続けます。放置すればするほど、テンプレートと本番環境が求める理想状態との乖離は広がっていきます。
  • インストーラーのチェックサム検証の省略:様々なミラーサイトからサーバーへISOをダウンロードする場合、ファイルの破損や改ざんのリスクが常に潜んでいます。しかし、SSHでログインして長いコマンドを打つのが面倒なため、SHA-256の検証手順は軽視されがちです。

Proxmoxのストレージに登録する前にISOインストーラーを素早く検証するため、私はよくToolCraftのHash Generatorを利用しています。SHA-256やMD5の計算アルゴリズムが100%ブラウザ上(クライアントサイド)で実行される点が非常に便利です。ファイルが外部の中継サーバーにアップロードされることがないため、機密性の高いファイルをチェックする際も安心です。

暫定的な回避策とその現実的な限界

専用ツールへ全面的に移行する前、私たちのチームでは広く知られている2つのアプローチを試行しました:

1. VMクローン後にBashスクリプトを実行する

当初のアイデアは、テンプレートを極力軽量に保ち、クローン後にSSH経由で長大なスクリプトを実行してソフトウェアを更新するというものでした。この方法なら最新パッケージを取得できます。しかし、ノードごとのVMプロビジョニング時間が10〜15分も延びてしまいます。さらに、リポジトリのミラーでネットワーク障害が発生したり、apt lockプロセスが競合してスタックしたりすると、自動化パイプライン全体が完全に停止してしまいます。

2. Proxmox上でCloud-initを単体利用する

Proxmox VEはCloud-Init Driveを標準でスムーズにサポートしており、SSHキー、ユーザー、静的IPなどをあらかじめ設定できます。しかし、Cloud-initの役割はあくまで初回起動時(Day 1)の設定にとどまります。Dockerエンジンや独自のランタイムを内包したり、カーネルパラメータのカスタマイズ(最大オープンファイル数の拡張やsysctlのチューニングなど)を施したGolden Imageそのものを生成できるわけではありません。

決定打となる解決策:HashiCorp PackerによるGolden Image自動化

導入から6ヶ月以上が経過し、HashiCorp Packerとproxmox-isoプラグインの組み合わせがこの課題を根本から解決してくれました。VMの全パラメータはクリーンなHCL2コードで定義されます。実行すると、PackerはProxmox上に一時的なVMを自動作成し、内蔵HTTPサーバー経由でautoinstall構成ファイルを注入し、ソフトウェアをインストールした上で、わずか1コマンドでTemplateへとパッケージ化します。

ステップ1:Proxmox VE上で専用のAPIトークンを作成する

最小権限の原則(least privilege)に従い、rootアカウントを直接利用するのではなく、専用のAPIトークンを作成します:

# Packer専用の権限を持つロールを作成
pveum role add PackerRole -privs "VM.Allocate VM.Clone VM.Config.CDROM VM.Config.CPU VM.Config.Disk VM.Config.HWType VM.Config.Memory VM.Config.Network VM.Config.Options VM.Monitor VM.Audit VM.PowerMgmt Datastore.AllocateSpace Datastore.Audit"

# ユーザーを作成してトークンを発行
pveum user add packer@pve
pveum user token add packer@pve packer-token -privsep=0
pveum aclmodify / -user packer@pve -role PackerRole

ステップ2:Packer設定ファイル(HCL)の作成

プロジェクトディレクトリ内にubuntu-2204.pkr.hclファイルを作成します。このファイルでハードウェア構成、ISOソース、VNC経由で送信するブートコマンドを定義します:

packer {
  required_plugins {
    proxmox = {
      version = ">= 1.1.3"
      source  = "github.com/hashicorp/proxmox"
    }
  }
}

variable "proxmox_api_url" {
  type    = string
  default = "https://192.168.1.100:8006/api2/json"
}

variable "proxmox_api_token_id" {
  type    = string
  default = "packer@pve!packer-token"
}

variable "proxmox_api_token_secret" {
  type      = string
  sensitive = true
  default   = "YOUR_PROXMOX_API_SECRET"
}

source "proxmox-iso" "ubuntu-server" {
  proxmox_url = var.proxmox_api_url
  username     = var.proxmox_api_token_id
  token        = var.proxmox_api_token_secret
  insecure_skip_tls_verify = true

  node                 = "pve-node1"
  vm_id                = 9000
  vm_name              = "ubuntu-2204-golden-template"
  template_description = "Ubuntu 22.04 LTS Golden Image built by Packer"

  iso_file         = "local:iso/ubuntu-22.04.4-live-server-amd64.iso"
  iso_storage_pool = "local"
  unmount_iso      = true

  qemu_agent = true
  cores      = 2
  memory     = 2048
  os         = "l26"

  scsi_controller = "virtio-scsi-pci"

  disks {
    disk_size    = "20G"
    storage_pool = "local-lvm"
    type         = "scsi"
  }

  network_adapters {
    model  = "virtio"
    bridge = "vmbr0"
  }

  # Packerが一時的なWebサーバーを自動起動してuser-dataファイルをホスト
  http_directory = "http"
  boot_command = [
    "<wait>c<wait>",
    "linux /casper/vmlinuz --- autoinstall ds=nocloud-net\\;s=http://{{ .HTTPIP }}:{{ .HTTPPort }}/ <enter><wait>",
    "initrd /casper/initrd <enter><wait>",
    "boot<enter>"
  ]
  boot_wait = "5s"

  ssh_username = "sysadmin"
  ssh_password = "SuperSecurePass123!"
  ssh_timeout  = "20m"
}

注意:autoinstall設定で指定するパスワードは、平文ではなくSHA-512のcryptハッシュ文字列にすることをおすすめします。openssl passwd -6コマンドでハッシュ化する前に複雑な初期パスワードを素早く生成するために、私はよくToolCraftのPassword Generatorを使用しています。このツールはブラウザ上で直接パスワードのエントロピー(強度)を測定し、秘密情報をインターネット経由で送信しないため、新規マシン群のランダムパスワードを生成する際に重宝します。

ステップ3:Cloud-InitによるAutoinstallの設定

http/user-dataファイルを作成します。Ubuntu ServerのSubiquityインストーラーがこのファイルを読み込み、ディスクの自動パーティショニング、アカウント作成、パッケージの事前インストールを実行します:

#cloud-config
autoinstall:
  version: 1
  locale: en_US
  keyboard:
    layout: us
  identity:
    hostname: golden-image
    username: sysadmin
    password: "$6$rounds=4096$salt$hashedpasswordhere..."
  ssh:
    install-server: true
    allow-pw: true
  packages:
    - qemu-guest-agent
    - curl
    - wget
    - git
    - htop
  late-commands:
    - systemctl enable qemu-guest-agent
    - echo "sysadmin ALL=(ALL) NOPASSWD:ALL" > /target/etc/sudoers.d/sysadmin

ステップ4:自動ビルドプロセスの実行

管理端末から以下の3つのコマンドを実行するだけで、テンプレートのビルドが開始されます:

# Proxmoxプラグインをダウンロード
packer init .

# 設定ファイルの構文チェック
packer validate .

# 自動ビルドプロセスの開始
packer build ubuntu-2204.pkr.hcl

ビルドプロセスは完全に自動で進行します。まず、PackerがProxmox APIを呼び出してID 9000の一時VMを作成します。VMはISOから起動し、Packer自身が立ち上げたミニWebサーバー経由でautoinstallファイルを受け取ります。Ubuntuのインストールが完了すると、PackerはVMにSSH接続してログのクリーンアップ、machine-idのリセット、aptキャッシュの削除を行います。最後にVMを標準Templateへと変換し、シャットダウンします。

本番環境導入から6ヶ月で得られた実際の成果

Packerによる自動ビルドパイプラインは、私たちのチームにおけるProxmoxインフラ管理のあり方を根底から変革しました:

  • VMプロビジョニング時間が20分から25秒に短縮:クラスターに新しいノードを追加する際、Terraformからリンククローン(Linked Clone)形式でVM ID 9000をクローンするだけで完了します。30秒足らずでワークロードを受け入れ可能な状態になります。
  • CI/CDによる定期的な自動更新:毎週日曜日の午前2時に自動実行されるGitHub Actionsワークフローを構築しました。手作業の手間をかけることなく、Proxmox上のGolden Imageには常に最新のカーネルとセキュリティパッチが適用されます。
  • インフラの100%均一化を実現:個人の検証用ラボサーバーから社内の3つのProxmoxクラスターに至るまで、すべて同一のHCLリポジトリを共有しています。これにより、開発環境と本番環境の間で発生していた環境ドリフト(Environment Drift)がほぼ完全に解消されました。
Share: