Packerを使用してVagrant Boxを作成してみるの巻

Date:

Share post:

久しぶりの投稿になってしまいました・・・。

以前の投稿で、Ubuntu 24.04 LTSのVagrant Boxを作成した記事を書いていましたが、今回はその関連記事です。以前作成していた時には、私は VirtualBox を Vagrant のプロバイダー(バックエンドになるプラットフォームのこと)として使用していました。

結構遅かったのですが VMware Fusion pro が無償になり、Vagrantのプロバイダーとして使用可能ということを知りまして、試用してみたところ思いのほか好感触であったことから、ローカル環境作成を VirtualBox から VMware Fusion に切り替えしています。

主要なLinuxディストリビューションのインストールから検証を行っていたところ、CentOS系(AlmaLinux, RockyLinux)はあらかじめ Vagrant Box もあるので特に問題はなかったのですが、Ubuntuは前述の投稿にも書いた通り、Vagrant Boxの提供がありません。

そのため、以下のような手順で試してみたのですが、正常に起動するBoxの作成がどうもうまくいきません。

  • VMware FusionでOVFエクスポートして ovftool で VMX に変換したのち、Box形式に圧縮

うまくいかなかったので詳細は省略しますが、ネットワークアダプタ(UbuntuのNetplan)要因なのか、設定の不備なのか特定ができませんでした。

どうしたものかと調べていたところ、AIアシスタントの Cursor さんに「Packer使うと自動作成してくれますよ!」と言われましたので、調べてみたところ、以下を行うツールだそうです。

  • Vagrantと同じ、HashiCorp社製のサーバーイメージ自動作成ツール
  • 単一のテンプレート(Packerの設定ファイル)でAWS (AMI)、Azure、VMware (VMDK/VMX)、VirtualBox (OVF) などで使用できるイメージを定義できる

特徴としては以下が挙げられるそうです。

  • 自動化: JSONファイルで定義を記述し、コマンド一つでビルド可能
  • 一貫性・安定性: イメージ構築手順をコード化し、手作業によるミスを減らし、テストを容易に
  • プロビジョニング: Chef, Puppet, Ansibleなどのツールと連携してイメージ内ソフトウェアをカスタマイズ可能

1回設定ファイルを作成しておくと、後々Box作成する時に便利ではないかと思い、今回試してみました。

というわけで、以下に手順と注意点などを書いていこうと思います。ちなみに今回ですが、以前と同じでUbuntu 24.04 LTSのISOイメージからBoxを作っていこうと思います。

1.Packerをインストール

Homebrew(パッケージマネージャ)を使用して、Packerをインストールします。

brew install packer

2.ディレクトリ構成

今回の作業ディレクトリ構成は以下のとおりです。

├── ubuntu-24.04.pkr.hcl  # メインのPacker設定ファイル
└── cidata/    # cloud-init設定(autoinstall用)
        ├── user-data    # インストール設定
        └── meta-data    # メタデータ(空ファイル)
cloud-init設定というのが出てきました。今回はクラウド上というわけではないのですが、これは何をしているかと言いますと、仮想マシンが初回に起動した時に、自動で初期設定を行うためのものです。今回何をしているかをざっと挙げますと以下のとおりです。
  • locale設定
  • ネットワーク設定
  • ストレージ設定
  • ユーザー設定
  • SSH設定
  • パッケージインストール
  • インストール後のvagrant用のsudo設定、SSH設定

user-data というファイルに記述されています。一方 meta-data ですが、本来はインスタンスIDやホスト名を記述できますが、今回は user-data に記述しています。そのため空になっています。ただし、cloud-init のNoCloudデータソースは、user-data と meta-data の両方が必要になります。どちらかが欠けるとNoCloudデータソースとして認識されず、autoinstallが起動しません。

いろいろ用語が出てくるので、以下は補足説明です。
cloud-init:クラウドインスタンス(仮想マシン)の初期設定を自動化するための業界標準ツール

データソース:cloud-init は通常、AWS、GCP、Azure などのクラウドプロバイダーが提供するメタデータサービス(例:169.254.169.254)からデータを取得します。データソースとは、このデータの取得元を定義するコンポーネント(部品)のことです。

NoCloudデータソース:ローカル環境(仮想マシンやベアメタルサーバー)ではクラウドプロバイダーが提供するメタデータサービスがありません。NoCloudデータソースは、そのような環境でcloud-initが初期設定に必要なデータを取得するための仕組みです。

どこからデータを取得してくるかにより、使用するものが変わってきます。

メインのPacker設定ファイル(ubuntu-24.04.pkr.hcl)は、Ubuntu 24.04 のISOイメージからVagrant Boxを自動生成するためのテンプレートです。大きく分けて4つのセクションで構成されています。

1)プラグイン定義

Packerの拡張機能として、2つのプラグインを使用しています。

        • vmware プラグイン: VMware Fusion上で仮想マシンを作成・操作するために必要
        • vagrant プラグイン: ビルド完了後に .box ファイルを生成するために必要

Packerはプラグインベースのアーキテクチャを採用しており、対象のプラットフォームに応じたプラグインを組み合わせて使います。

2)変数定義

テンプレートの再利用性を高めるため、変更が必要な値を変数として切り出しています。

        • ISOファイルのパス: 環境によって異なるため変数化
        • VM名: 生成されるVMの名前
        • SSH認証情報: プロビジョニング時にPackerがSSH接続するための認証情報

変数化しておくことで、同じテンプレートを別バージョンのUbuntuにも流用しやすくなります。

3)ソース定義(VMビルダー)

このセクションが設定ファイルの肝で、どのような仮想マシンを作成するかを定義しています。

⚪︎ハードウェア構成

CPU、メモリ、ディスクサイズなど、仮想マシンのスペックを指定します。今回は最低限の構成(2コア、2GB RAM、20GB ディスク)としています。

⚪︎ISOとブート設定

UbuntuのISOファイルを指定し、起動時のブートコマンドを定義します。ポイントはGRUBコマンドラインから直接カーネルを起動している点です。これにより、GRUBメニューのタイミングに依存せず、確実に自動インストール(autoinstall)を開始できます。

⚪︎cloud-init連携

autoinstallを動作させるため、NoCloudデータソース を利用しています。user-data と meta-data ファイルをISOイメージとしてマウントし、ボリュームラベルを cidata に設定することで、cloud-initがこれを認識して自動インストールを実行します。

⚪︎SSH接続設定

Packerはインストール完了後、SSHでVMに接続してプロビジョニングを行います。タイムアウトや再試行回数を十分に確保し、インストールに時間がかかっても接続が成功するようにしています。

4)ビルド定義

VMが作成された後の後処理を定義するセクションです。

⚪︎プロビジョニング(シェルスクリプト)

SSHで接続した後、Vagrant Boxとして使えるようにするための設定を行います。

          • システムアップデート: 最新のセキュリティパッチを適用
          • Vagrant SSH公開鍵の設定vagrant ssh でパスワードなしログインできるようにします
          • sudoers設定: vagrant ユーザーがパスワードなしで sudo を実行可能に
          • ネットワーク設定の汎用化: Netplanをワイルドカード設定に変更し、どの環境でもDHCPでIPを取得できるようにします
          • Machine-IDのリセット: 同じBoxから複数VMを起動した際のDHCP重複問題を防止
          • ディスクのゼロ埋め: 未使用領域をゼロで埋めることで、Boxファイルの圧縮効率を大幅に向上(これは以前の投稿でも書きましたね)

⚪︎ポストプロセッサ(Vagrant Box生成)

プロビジョニングが完了したVMを、Vagrantで利用可能な .box ファイルとしてパッケージングします。

3.実際のファイル

2.で説明したファイルの中身が以下になります。ISOファイルやチェックサムなどは適宜置き換える必要があります。

cidata/user-data
====================

#cloud-config
autoinstall:
  version: 1
  
  # ロケール設定
  locale: en_US.UTF-8
  keyboard:
    layout: us
  
  # ネットワーク(DHCPで自動取得)
  network:
    version: 2
    ethernets:
      id0:
        match:
          name: en*
        dhcp4: true
  
  # ストレージ(自動パーティション)
  storage:
    layout:
      name: lvm
  
  # ユーザー設定
  identity:
    hostname: ubuntu
    username: vagrant
    # パスワード: vagrant(SHA-512ハッシュ)
    # このパスワード(vagrant)はVagrant Boxの開発用デフォルトパスワードです。
    password: "$6$randomsalt$jguz.88OgNwt3/K5rWTBg.PCeut4KfhMQF0TCyAGmUzgcoHYnfRGTa8vU9WkmZj7uCLiMPkY77fZJdNG5xbSy."
  
  # SSH設定
  ssh:
    install-server: true
    allow-pw: true
  
  # パッケージ
  packages:
    - open-vm-tools
    - curl
    - wget
    - ca-certificates
  
  # インストール後のコマンド(最小限に)
  late-commands:
    # vagrantユーザーにsudo権限付与(これだけでSSH接続可能になる)
    - echo 'vagrant ALL=(ALL) NOPASSWD:ALL' > /target/etc/sudoers.d/vagrant
    - chmod 440 /target/etc/sudoers.d/vagrant
cidata/meta-data
====================

# 空です。
ubuntu-24.04.pkr.hcl
====================

packer {
  required_plugins {
    vmware = {
      version = ">= 1.0.0"
      source  = "github.com/hashicorp/vmware"
    }
    vagrant = {
      version = ">= 1.1.0"
      source  = "github.com/hashicorp/vagrant"
    }
  }
}

# ===================
# 変数定義
# ===================
variable "iso_path" {
  type    = string
  default = "/path/to/ubuntu-24.04.3-live-server-amd64.iso"  # ← ISOパスを変更
}

variable "vm_name" {
  type    = string
  default = "ubuntu-24.04-vagrant"
}

variable "ssh_username" {
  type    = string
  default = "vagrant"
}

variable "ssh_password" {
  type    = string
  default = "vagrant"
}

# ===================
# VMware Fusion ビルダー
# ===================
source "vmware-iso" "ubuntu" {
  # VM基本設定
  vm_name          = var.vm_name
  guest_os_type    = "ubuntu-64"
  version          = "21"           # VMware Hardware Version
  headless         = false          # GUIを表示(デバッグ用、完成後はtrueに)
  
  # ISO設定
  iso_url          = var.iso_path
  iso_checksum     = "sha256:xxxxxxxxxx"  # ← チェックサムを変更
  # ハードウェア設定
  cpus             = 2
  memory           = 2048
  disk_size        = 20480
  disk_type_id     = "0"            # Growable disk
  
  # ネットワーク設定
  network          = "nat"
  network_adapter_type = "e1000e"
  
  # 出力設定
  output_directory = "output-ubuntu-24.04"
  
  # SSH接続設定
  ssh_username     = var.ssh_username
  ssh_password     = var.ssh_password
  ssh_timeout      = "45m"
  ssh_port         = 22
  ssh_handshake_attempts = 100
  
  # シャットダウンコマンド
  shutdown_command = "echo '${var.ssh_password}' | sudo -S shutdown -P now"
  
  # cloud-init用ISO(セカンダリCD)
  cd_files         = ["./cidata/user-data", "./cidata/meta-data"]
  cd_label         = "cidata"
  
  # ブートコマンド(GRUBコマンドラインから直接ブート)
  boot_wait        = "5s"
  boot_command     = [
    "c",
    "<wait3>",
    "set gfxpayload=keep<enter>",
    "linux /casper/vmlinuz quiet autoinstall 'ds=nocloud' ---<enter>",
    "initrd /casper/initrd<enter>",
    "boot<enter>"
  ]
  
  # VMware VMX追加設定(Packerデフォルトと重複しない設定のみ)
  vmx_data = {
    "ethernet0.present"        = "TRUE"
    "ethernet0.addressType"    = "generated"
  }
}

# ===================
# ビルド定義
# ===================
build {
  name    = "ubuntu-vagrant-box"
  sources = ["source.vmware-iso.ubuntu"]
  
  # ---------------------------------------
  # プロビジョニング: Vagrant用設定
  # ---------------------------------------
  provisioner "shell" {
    execute_command = "echo '${var.ssh_password}' | sudo -S bash -c '{{ .Vars }} {{ .Path }}'"
    inline = [
      # アップデート
      "echo '>>> システムアップデート中...'",
      "apt-get update",
      "apt-get upgrade -y",
      
      # 必要なパッケージインストール
      "echo '>>> パッケージインストール中...'",
      "apt-get install -y open-vm-tools curl wget ca-certificates",
      
      # Vagrant SSH公開鍵設定
      "echo '>>> Vagrant SSH鍵設定中...'",
      "mkdir -p /home/vagrant/.ssh",
      "chmod 700 /home/vagrant/.ssh",
      "curl -fsSL https://raw.githubusercontent.com/hashicorp/vagrant/main/keys/vagrant.pub -o /home/vagrant/.ssh/authorized_keys",
      "chmod 600 /home/vagrant/.ssh/authorized_keys",
      "chown -R vagrant:vagrant /home/vagrant/.ssh",
      
      # sudoers設定(パスワードなしsudo)
      "echo '>>> sudoers設定中...'",
      "echo 'vagrant ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/vagrant",
      "chmod 440 /etc/sudoers.d/vagrant",
      
      # SSH設定
      "echo '>>> SSH設定中...'",
      "sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication yes/' /etc/ssh/sshd_config",
      "sed -i 's/^#*UseDNS.*/UseDNS no/' /etc/ssh/sshd_config",
      
      # Netplan汎用化(重要!)
      "echo '>>> ネットワーク設定汎用化中...'",
      "cat > /etc/netplan/00-vagrant.yaml << 'EOF'",
      "network:",
      "  version: 2",
      "  renderer: networkd",
      "  ethernets:",
      "    id0:",
      "      match:",
      "        name: \"en*\"",
      "      dhcp4: true",
      "    id1:",
      "      match:",
      "        name: \"eth*\"",
      "      dhcp4: true",
      "EOF",
      
      # 既存のNetplan設定を削除
      "rm -f /etc/netplan/50-cloud-init.yaml",
      "rm -f /etc/netplan/00-installer-config.yaml",
      
      # Cloud-initネットワーク設定無効化
      "mkdir -p /etc/cloud/cloud.cfg.d",
      "echo 'network: {config: disabled}' > /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg",
      
      # Machine-IDリセット(DHCP問題対策)
      "echo '>>> Machine-IDリセット中...'",
      "truncate -s 0 /etc/machine-id",
      "rm -f /var/lib/dbus/machine-id",
      "ln -sf /etc/machine-id /var/lib/dbus/machine-id",
      
      # クリーンアップ
      "echo '>>> クリーンアップ中...'",
      "apt-get autoremove -y",
      "apt-get clean",
      "rm -rf /tmp/*",
      "rm -rf /var/tmp/*",
      "rm -rf /var/cache/apt/archives/*.deb",
      
      # ログクリア
      "find /var/log -type f -exec truncate -s 0 {} \\;",
      
      # Bash履歴クリア
      "rm -f /home/vagrant/.bash_history",
      "rm -f /root/.bash_history",
      
      # swap無効化(ゼロ埋め前に必要)
      "swapoff -a",
      
      # ディスクのゼロ埋め(圧縮効率を大幅に向上)
      "echo '>>> ディスクのゼロ埋め中...(時間がかかります)'",
      "dd if=/dev/zero of=/EMPTY bs=1M 2>/dev/null || true",
      "rm -f /EMPTY",
      "sync",
      
      "echo '>>> プロビジョニング完了!'"
    ]
  }
  
  # ---------------------------------------
  # ポストプロセッサ: Vagrant Box生成
  # ---------------------------------------
  post-processor "vagrant" {
    output               = "ubuntu-24.04-vmware.box"
    keep_input_artifact  = false
  }
}

4.PackerでBoxをビルド

以下コマンドを実行することで、Vagrant Boxファイルが自動生成されます。

### 1. 作業ディレクトリに移動
cd /path/to/work/directory

### 2. プラグインをインストール
packer init ubuntu-24.04.pkr.hcl

### 3. 設定を検証
packer validate ubuntu-24.04.pkr.hcl

### 4. ビルド実行
packer build ubuntu-24.04.pkr.hcl

実行中は VMware Fusion のウィンドウが自動で立ち上がったり、コマンド入力が行われたりします。

Boxファイルが作成できたら、VMware Fusionのウィンドウは閉じて問題ありません。(Box作成時に仮想マシンはシャットダウンしているため)

ちなみに今回作成したBoxファイルですが、大体12分前後で作成されます。あとファイルサイズですが1.4GB前後です。以前の投稿と比較してみると、パッケージを入れた分少し大きくなっているのかもしれません。今回容量についてはあまりスリム化を突き詰めてはいませんので、とりあえずはよしとしておきます。

まずは作成したBoxでvagrantの起動確認を行います。

起動は問題ありませんでした。

設定を一度作成しておけば同じものを何回も作成できるので、便利だなと思いました。あと、Dockerイメージ作成の時にも使用できるらしく、ケースによっては有用だということなので、もう少し触ってみて、何か発見があればまた共有しようと思います。

Related articles

マルチポイント対応のイヤホンが便利すぎる

スマートフォンで音楽を聴きながら仕事...

ResNet50からEfficientNetV2L...

約三ヶ月ぶりの投稿です。前回の投稿(...