Packerを使ってVirtualBoxやKVM/Xen向けの仮想マシンイメージを作成する

図1 PackerのWebサイト

 PackerにはVirtualBoxやQEMU(KVMおよびXen)などの仮想マシンイメージを作成する機能が用意されており、仮想マシン作成を自動化できる。今回は、Packerを使ってVirtualBoxおよびQEMU(KVM)用の仮想マシンにOSをインストールしてディスクイメージを作成する例を紹介する。

Packerを使って各種仮想マシン用のディスクイメージを作る

 前回記事ではPackerを使ってDocker用のイメージを作成する方法を紹介したが、今回はDockerではなく仮想化ソフトウェア向けのイメージを作成する方法を紹介していこう。

 Packerではさまざまな仮想マシンやクラウドインフラ向けのディスクイメージを作成できるが、今回はCentOS 7のインストールISOイメージを元に、VirtualBoxとQEMU(KVM)向けのディスクイメージを作成する流れを紹介する。

VirtualBox向けのディスクイメージを作成する

 まずはVirtualBox向けのディスクイメージの作成について説明しよう。PackerではVirtualBox向けのbuilderとして、「virtualbox-ovf」と「virtualbox-iso」の2つが用意されている。

 virtualbox-ovfは前回紹介したDocker向けbuilderと似たような動作を行うもので、既存のVirtualBox用の仮想マシンファイル(OVFファイル)やディスクイメージを使って仮想マシンを起動し、指定されたprovisionerでプロビジョニングを実行したのち仮想マシンをエクスポートする、というものだ。

 いっぽうのvirtualbox-isoはインストール用のISOイメージから仮想マシンを起動してインストール作業やプロビジョニング作業を実行し、その結果作成された仮想ディスクからディスクイメージを作成するものになる。具体的な作業の流れとしては、下記のようになる。

  1. 新規に仮想マシンを作成する
  2. 指定されたインストールCD/DVDのISOイメージファイルからインストーラを起動してインストールを行う
  3. プロビジョニングを実行する
  4. プロビジョニング後の環境を仮想マシンファイルとしてエクスポートする

 なお、2.のステップにおいては、Packerでは仮想マシンの起動までを行い、その後のインストール作業については関与しない。そのため手動でインストール作業を進めるか、もしくはkickstartなどの自動インストール機能を別途利用する必要がある。

 今回は、こちらのvirtualbox-iso builderを使ってVirtualBox向け仮想ディスクイメージファイルを作成することにする。なお、virtualbox-isoもしくはvirtualbox-ovf builderを利用する場合、Packerを実行するマシン上に事前にVirtualBoxがインストールされている必要がある。また、後述するheadlessインストールを行わない場合は、GUIでVirtualBoxを操作できるよう設定しておく必要もある。それぞれ事前に準備をしておこう。

VirtualBox用ディスクイメージを作成する設定を追加する

 それでは、まずはvirtualbox-iso builder用の設定を前回作成した設定ファイルに追加していこう。今回追加したのは、下記の太字で示している部分だ。

{
  "builders": [
    {
      "type": "docker",
      "image": "centos:centos7",
      "export_path": "packer-centos7-docker.tar"
    },
    {
      ↓「virtualbox-iso」builderの設定であることを宣言する
      "type": "virtualbox-iso",
      ↓使用するISOイメージのチェックサムが記載されたファイル
      "iso_checksum_url": "file:///home/hylom/packer-test/md5sum.txt",
      ↓使用するチェックサムの形式
      "iso_checksum_type": "md5",
      ↓ISOイメージのダウンロード元URL
      "iso_url": "file:///home/hylom/packer-test/CentOS-7-x86_64-NetInstall-1511.iso",
      ↓プロビジョニングに使用するユーザー名
      "ssh_username": "root",
      ↓プロビジョニング実行時に仮想マシンにログインするために使用するパスワード
      "ssh_password": "SSH_Password",
      ↓インストール作業のタイムアウト時間
      "ssh_wait_timeout": "40m",
      ↓作成する仮想マシンのディスクサイズ
      "disk_size": "8000",
      ↓作成する仮想マシンのタイプ
      "guest_os_type": "RedHat_64",
      ↓仮想マシンをシャットダウンする際に使用するコマンド
      "shutdown_command": "/sbin/shutdown -h now",
      ↓シャットダウンコマンドを実行してから完了するまでの待機時間
      "shutdown_timeout": "20s",
      ↓作成する仮想マシンの名称
      "vm_name": "packer-centos7-vbox"
    },
  ],
  "provisioners": [
    {
      "type": "chef-solo",
      "cookbook_paths": ["cookbooks"],
      "run_list": ["webserver"],
      "prevent_sudo": true
    }
  ]
}

 virtualbox-iso builderでは、インストールに使用するISOイメージを「iso_url」パラメータで指定する。ここではHTTP経由でISOイメージをダウンロードして使用するよう指定しているが、「file://」プロトコルを指定すればローカルのファイルを使用することも可能だ。また、「iso_checksum_url」および「iso_checksum_type」パラメータはそのISOイメージファイルのチェックサムが記載されているファイルとその形式を指定するもので、必須のパラメータとなっている。チェックサムはISOイメージの配布元で公開されており、たとえばCentOSの場合md5sum.txtにMD5形式のチェックサムが記載されているので、それを指定すれば良い。

 「ssh_username」および「ssh_password」はインストールの完了後にPackerがプロビジョニングに使用するアカウント名とそのログインパスワードを指定するものだ。今回はrootユーザーでプロビジョニングを実行するよう指定している。

 注意したいのが「ssh_wait_timeout」設定だ。Packerは仮想マシンを実行後、「ssh_username」で指定したアカウントを使って仮想マシンに対しログインを試みる。インストール作業中は当然ながらログインを行えないため、Packerは定期的に仮想マシンに対してログインを試行し続け、ログインに成功したら仮想マシンへのインストールが完了したと判断する仕組みになっている。このとき、ログインに成功しないまま「ssh_wait_timeout」で指定した時間が経過すると、Packerはインストール時に問題が発生したと判断して作業を中断してしまう。そのため、ここでは十分な時間を指定しておく必要がある。今回は「40m」(40分)を指定している。

 そのほか、ここで指定しているパラメータの詳細についてはPackerのドキュメントを参照してほしい。

 さて、設定ファイルの編集が終わったら、次のようにpacker buildコマンドを実行しよう。

$ ~/packer/packer build --only=virtualbox-iso centos7.json

 ここで指定している「–only=virtualbox-iso」は、使用するbuilderを選択するためのオプションだ。設定ファイル内では複数のbuilderを指定でき、このオプションが省略された場合、Packerは設定ファイル内のすべてのbuilderを順に実行してイメージを作成する。今回はVirtualBox向けのイメージのみ作成したいので、「virtualbox-iso」を指定する。

 packer buildコマンドを実行すると、図1のようにVirtualBoxが起動してインストール画面が表示される。

図1 packer buildコマンドを実行するとVirtualBoxが起動する
図1 packer buildコマンドを実行するとVirtualBoxが起動する

 今回はインストールの自動化に関する設定は行っていないので、ここではインストーラの起動画面が表示されるのみで、その後の作業には進まない。そのため続けて手動でインストーラを操作し、インストール作業を進めていく。このときrootパスワードにはPackerの設定ファイル内で「ssh_password」として指定したものを設定することに注意したい。

 手動でのインストールの完了後に仮想マシンを再起動すると、PackerがSSHで仮想マシンにログインし、プロビジョニング作業を実行する(図2)。

図2 インストール後に仮想マシンを再起動すると、プロビジョニング処理が開始される
図2 インストール後に仮想マシンを再起動すると、プロビジョニング処理が開始される

 プロビジョニング作業が正常に修了すると、イメージファイルのエクスポートが行われ、「output-virtualbox-iso」というディレクトリ内に保存される。「.vmdk」という拡張子のものがディスクイメージ、「.ovf」のものが仮想マシンの設定ファイルだ。

$ ls output-virtualbox-iso/
packer-centos7-vbox-disk1.vmdk  packer-centos7-vbox.ovf

kickstartを使ったインストール作業の自動化

 さて、Packerを使ってVirtualBox用のディスクイメージを作成することはできたが、この例ではOSのインストール作業は手動で行っており、イメージを作り直すたびに同様の作業を行わなければならない。そこで、CentOSなどRed Hat Linux系ディストリビューションで利用できる自動インストール機能「kickstart」を使ってインストール作業を自動化してみよう。

 kickstartは、インストール内容を記述した設定ファイルを指定してインストーラを起動することで自動的にインストール作業を進める機能だ。Red Hat Linux系ディストリビューションでは、OSのインストール後にkickstart用の設定ファイル(kickstartファイル)が「/root/anaconda-ks.cfg」という名前で保存される仕組みになっている。このファイルを利用することで、それと同じ環境を自動インストールできるようになる。また、このファイルを編集することで、インストール内容をカスタマイズすることも可能だ。

 今回はデフォルトのインストール設定で作成されたanaconda-ks.cfgファイルを一部修正して使用した。使用した設定ファイルは次のとおりで、修正した個所は太字で示している。

#version=RHEL7
# System authorization information
auth --enableshadow --passalgo=sha512

# Use network installation
url --url="http://ftp.jaist.ac.jp/pub/Linux/CentOS/7/os/x86_64/"
# Run the Setup Agent on first boot
#firstboot --enable
ignoredisk --only-use=sda
# Keyboard layouts
keyboard --vckeymap=jp106 --xlayouts='jp'
# System language
lang ja_JP.UTF-8

# Network information
network  --bootproto=dhcp --device=enp0s3 --ipv6=auto --activate
network  --hostname=localhost.localdomain
# Root password
rootpw --iscrypted <ハッシュ化されたパスワード>
# System timezone
timezone Asia/Tokyo --isUtc
user --groups=wheel --name=hylom --password=<ハッシュ化されたパスワード> --iscrypted --gecos="hylom"
# System bootloader configuration
bootloader --location=mbr --boot-drive=sda
autopart --type=lvm
# Partition clearing information
clearpart --none --initlabel 
# Skip EULA
eula --agreed
# auto reboot
reboot

%packages
@core

%end

 具体的な修正個所は以下の3点だ。

  • インストール後に初めて起動した際に設定画面を表示する「firstboot」を無効する(「firstboot –enable」をコメントアウト)
  • ソフトウェア利用許諾契約(EULA)についての同意画面を表示させず、自動的に同意したことにする(「eula –agreed」)
  • インストール完了後、自動的に再起動を行う(「reboot」)

 これらを指定することで、インストーラの起動後に入力を行うことなくインストール作業を進行させることが可能になる。また、今回作成したファイルはPackerの設定ファイルと同じディレクトリ内に「kickstart」というディレクトリを作成し、そこに「anaconda-ks.cfg」というファイル名で保存している。

 続いて、用意したkickstartファイルをインストーラに読み込ませるための設定を行う。こちらについては、Packerの設定ファイルに記述する。具体的に必要となる設定項目は次の2つだ。

  • HTTP経由でインストーラにkickstartファイルを渡すための「http_directory」
  • ブート時にインストーラに文字列を渡すための「boot_command」と「boot_wait」

 kickstartを使ってインストールを行うには、作成したkickstartファイルを何らかの形でインストーラに渡す必要がある。これにはいくつかの手段が利用できるが、Packerには内部的にHTTPサーバーを起動して指定したディレクトリ内のファイルを公開する機能があり、これを利用するのが簡単だ。この機能を利用するには、「http_directory」という設定項目を追加し、その値に公開するファイルが含まれるディレクトリを指定すれば良い。今回は「kickstart」というディレクトリ内にkickstartファイルを格納しているので「./kickstart/」という値を指定する。

 また、kickstartを使って自動インストールを行う場合、インストーラを起動した後にインストールオプションとしてkickstarterファイルを指定する必要がある。この入力処理を自動で行うためのオプションが「boot_command」と「boot_wait」オプションだ。これらのオプションを指定すると、仮想マシンを起動してからboot_waitオプションで指定した時間だけ待機し、続いてboot_commandオプションで指定した文字列を仮想マシンに対しキーボードイベントとして送信する、という処理が実行される。

 今回は、先に作成した設定ファイルにさらに次のような項目を追加した。

"boot_command": [
  "<tab> text ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/anaconda-ks.cfg <enter>"
],
"boot_wait": "10s",
"http_directory": "./kickstart/"

 ここで指定している「{{ .HTTPIP }}」および「{{ .HTTPPort }}」という文字列はそれぞれ「HTTPIP」および「HTTPPort」という変数を参照することを示しており、これらはPackerの起動後、HTTPサーバーのIPアドレスとポート番号に自動的に置き換えられる。

 これらの設定を追加した後に同じようにしてpacker buildコマンドを実行すると、仮想マシンの起動やインストーラの起動、インストール、プロビジョニングといった作業が全自動で行われてディスクイメージが生成される。

 なお、この場合VirtualBoxの画面がデスクトップ上に表示されてしまうが、Packerの設定ファイル内に「”headless”: “true”」という設定項目を追加することで、画面を表示せずにインストール作業を実行することも可能になる。これは「headlessインストール」と呼ばれており、リモートのマシンにSSHでログインして作業を行う場合などに便利だ。ただしこの場合エラーが発生した場合に何が起こっているのか判別しにくくなるので、利用前にインストール作業が正しく行えるかをチェックしてから使うことをおすすめする。

QEMU用のディスクイメージを作成する

 続いては、QEMU用のディスクイメージファイルを作成してみよう。QEMUはオープンソースの仮想化ソフトウェアだが、KVMやXenと組み合わせて利用する例が多い。たとえばRed Hat Enterprise LinuxやFedora、CentOSなどで採用されている仮想環境管理ツール「libvirt」では、KVMとQEMUを組み合わせて利用するようになっている。Dockerでは、「qemu」builderを利用することでKVMおよびXen用の仮想マシンイメージを作成できる。

 qemu builderではvirtualbox-iso builderと同様、インストールCD/DVDのISOイメージから仮想マシンイメージを作成できる。必要な設定項目もvirtualbox-iso builderとほぼ同じなので、virtualbox-iso builderの設定を流用することが可能だ。

 必要な設定項目について詳細はqemu buildのドキュメントを参照してほしいが、今回は次のような設定を追加した。これは先のvirtualbox-iso向け設定項目とほぼ同じで、追加/変更したのは太字の部分のみだ。

{
  "builders": [
 
 
    {
      "type": "qemu",
      "iso_checksum_url": "file:///home/hylom/packer-test/md5sum.txt",
      "iso_checksum_type": "md5",
      "iso_url": "file:///home/hylom/packer-test/CentOS-7-x86_64-NetInstall-1511.iso",
      "ssh_username": "root",
      "ssh_password": "SSH_Password",
      "ssh_wait_timeout": "40m",
      "disk_size": "8000",
      "shutdown_command": "/sbin/shutdown -h now",
      "shutdown_timeout": "20s",
      "vm_name": "packer-centos7-qemu",
      "boot_command": [
        "<tab> text ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/anaconda-ks-qemu.cfg <enter>"
      ],
      "boot_wait": "10s",
      "http_directory": "./kickstart/",
      ↓仮想化エンジンとしてKVMを使用
      "accelerator": "kvm",
      ↓使用する仮想ネットワークデバイスを指定
      "net_device": "virtio-net",
      ↓使用する仮想ディスクデバイスを指定
      "disk_interface": "virtio",
      ↓QUIを使用しない
      "headless": true,
       ↓QEMUに与える引数を指定
      "qemuargs": [
        [ "-m", "512M"]
      ]
    }
  ],
 
 

 kickstart用の設定ファイルについてはvirtualbox-iso builderで使ったもの(anaconda.cfg)とは異なるファイル(anaconda-ks-qemu.cfg)を指定している。具体的には、anaconda.cfg内でディスクデバイス関連の設定項目で指定されている「sda」という値を、すべて「vda」に置き換えている。QEMU+KVMの環境でディスクドライバにvirtioを利用する場合、仮想マシン上のOSからはディスクデバイスが「/dev/sda」ではなく「/dev/vda」として認識されるという違いがあるためだ。

 また、あらかじめqemuのインストールも必要となる。たとえばCentOS 7の場合、「qemu-system-x86.x86_64」パッケージをyumコマンドなどでインストールしておけば良い。

 設定ファイルを用意した後に次のようにpacker buildコマンドを実行すると、virtualbox-iso builderを利用した場合と同様に仮想マシンの作成やインストール、プロビジョニングが実行されて仮想マシンイメージが出力される。

$ ~/packer/packer build -only=qemu centos7.json

利用には各仮想化技術に対する一定の知識が必要

 さて、2回にわたってPackerについて紹介してきたが、Packerの設定ファイル作成などの際には対象とする仮想化ソフトウェアやコンテナ管理ツール、プロビジョニングツールなどについての知識が必要で、必ずしも「お手軽」なツールではない。ただ、一度設定ファイルを作成できてしまえば、それらを容易に使い回せるため、その後の管理作業については簡単になる。

 複数の仮想化ソフトウェアやコンテナ管理ツールを併用している場合や、プロビジョンツールを使っている場合などは活用する価値があるのではないだろうか。