hidemium's blog

日々学んだことをアウトプットする。

PackerでWindows Server 2012 R2のVMwareイメージをビルドする

この記事は NIFTY Cloud Advent Calendar 2015の 20 日目です。
ESXi上で動作するOSイメージを自動ビルドするのにPackerが使われています。
LinuxのOSイメージをPackerでビルドする事例はありますが、Windowsについてはまだまだ少ないと感じており、今回は、WindowsのOSイメージをPackerでビルドする方法を紹介します。

構成

※Workstation上に、UbuntuとESXiを稼働させています。

インストール

Packerのインストール

まず、Packerのインストールを行います。

$ wget https://dl.bintray.com/mitchellh/packer/packer_0.8.6_linux_amd64.zip
$ mkdir /usr/local/packer
$ unzip -d /usr/local/packer packer_0.8.6_linux_amd64.zip
$ echo 'export PATH="${PATH}:/usr/local/packer"' | sudo tee -a /etc/profile.d/packer.sh; source /etc/profile.d/packer.sh
$ packer --version
0.8.6

Packer Template

Packerを使ってビルドするには、Packer用のテンプレートファイル(json形式)を作成する必要があります。GitHub上にいくつかプロジェクトがあり、設定ファイル一式を取得することができます。

ただし、上記の設定ファイルだけだと一部動作しないところもあり、環境に合わせて変更を行います。今回の環境に合わせて修正を行った設定ファイルを使います。

$ git clone https://github.com/hideakihal/packer-windows-esxi.git
$ cd packer-windows-esxi

ISOイメージの配置

packer-windows-esxi/iso配下にWindows Server 2012 R2のOSイメージを配置します。
また、合わせてwindows_2012_r2.jsonのvariablesにISOファイルのファイル名とハッシュ値を入力します。

$ vi windows_2012_r2.json
  "variables": {
    "iso_url": "./iso/9600.17050.WINBLUE_REFRESH.140317-1640_X64FRE_SERVER_EVAL_EN-US-IR3_SSS_X64FREE_EN-US_DV9.ISO",
    "iso_checksum_type": "md5",
    "iso_checksum": "5B5E08C490AD16B59B1D9FAB0DEF883A",
   :

ESXi のファイアウォールの設定

ESXiのFirewall設定を開き、VM serial port connected over network にチェックを入れ、OKを選択します。

ESXi の GuestIPHack の有効化

VMware Tools が起動していない仮想マシンの IP を取得するため、 GuestIPHack を有効にします。
ESXi に SSH でログインして、下記のコマンドを実行します。

esxcli system settings advanced set -o /Net/GuestIPHack -i 1

ビルド方法

上記の準備ができたところで、以下のコマンドを実行し、ビルドを行います。コマンドに PACKER_LOG=1 PACKER_LOG_PATH=build.log を追加すると、詳細なログを出力することができるのでデバッグに便利です。

PACKER_LOG=1 PACKER_LOG_PATH=build.log \
packer build \
-var 'remote_host=<ESXi の IP アドレス>' \
-var 'remote_datastore=<データストア名>' \
windows_2012_r2.json

Packer Templateの解説

ビルドの流れ

今回作成した設定ファイルは、以下の流れでビルドを行っています。

  1. buildersによるOSリソースの設定
  2. 応答ファイル(Autounattend.xml)によるOSインストール
    1. 言語設定(SetupUILanguage等)
    2. インストールエディション選択(ImageInstall>OSImage>InstallFrom)
    3. ディスク構成(DiskConfiguration)
    4. コンピュータ名(ComputerName)
    5. アカウント設定(UserAccounts)
    6. 初期設定スクリプト(FirstLogonCommands)
      1. 初期設定(init.bat)
      2. Windows Update(win-updates.ps1)
      3. WinRM有効化(winrm.bat)
  3. WinRMにてログインし、provisionersで設定した事後スクリプトを実行
    1. VMware Toolsインストール(vm-guest-tools.bat)
    2. RDP有効化(enable-rdp.bat)

Windows Updateについて

Windows Updateを行っていますが、応答ファイルを以下のように修正することで無効にすることもできます。

$ vi Autounattend.xml
<!-- WITHOUT WINDOWS UPDATES -->
<SynchronousCommand wcm:action="add">
    <CommandLine>cmd.exe /c a:\winrm.bat</CommandLine>
    <Description>Fire-up winrm!</Description>
    <Order>99</Order>
</SynchronousCommand>
<!-- WITH WINDOWS UPDATES
<SynchronousCommand wcm:action="add">
    <CommandLine>cmd.exe /c C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File a:\win-updates.ps1 -DoneScript a:\winrm.bat</CommandLine>
    <Description>Run Windows Updates</Description>
    <Order>99</Order>
    <RequiresUserInput>true</RequiresUserInput>
</SynchronousCommand>
-->

参考までにビルド時間は、Windows Updateがある場合は3時間30分、Windows Updateがない場合は15分かかりました。そのため、デバッグ中はWindows Updateはオフにしたほうが良いかと思います。
また、応答ファイルをデバッグする場合は、Windows ADKをインストールし、Windows システム イメージ マネージャーを利用すると便利です。

Windowsのprovisionerについて

Windowsイメージをビルドする際に利用できる provisioner は、PowerShell(powershell) と Windows Shell(windows-shell) しかありません。
OpenSSHをインストールして、Shell provisioner(shell) を試してましたが動作しませんでした。(動かす方法があるかもしれませんが。)
powershellpowershellスクリプトを実行でき、windows-shellはcmdによるコマンドを実行できます。
今回は以下のように、VMware ToolsのインストールとRDP有効化のために利用しています。他の設定を行いたい場合は、ここにスクリプトを追加するかたちになります。

$ vi windows_2012_r2.json
  "provisioners": [
    {
      "type": "windows-shell",
      "scripts": [
        "scripts/vm-guest-tools.bat",
        "scripts/enable-rdp.bat"
      ]
    }
  ],

ただし、powershellwindows-shellを利用するためには、WinRMによる接続を行う必要があり、テンプレートファイルにWinRM接続の設定を定義しておく必要があります。

$ vi windows_2012_r2.json
      "communicator": "winrm",
      "winrm_username": "packer",
      "winrm_password": "packer",
      "winrm_timeout": "6h",

おわりに

今回、PackerによるWindowsのOSイメージをビルドを行いましたが、GitHub上にいくつかプロジェクトをそのまま利用するだけでは難しく、はまりどころが多いように感じました。実用化に向けては、環境に合わせてテンプレートファイルを修正し、provisionerをカスタマイズしていく方向になるかと思います。
今回の記事がみなさんのお役に立てられればと思います。