PackerでVagrant用のBoxを作成したときのメモ

気がついたら[Chef](http://tsuchikazu.net/chef_solo_start/)やら[Puppet](http://gihyo.jp/admin/serial/01/puppet)やら[Ansible](http://apatheia.info/blog/2013/04/06/about-ansible/)は[DevOps](http://www.atmarkit.co.jp/ait/articles/1307/02/news002.html)と呼ばれるようになったんですね。
時代のちょっと先端に行ったと思ったらまた取り残されてる感じがなんともこの業界ならではかと。

で、話は変わって前から[Vagrant](http://www.vagrantup.com/)のbaseBoxをゼロから作りたいぞ！！このヤロー！！って思っていたら
[Packer](http://www.packer.io/)というVagrantの作者が仮想イメージを作るツールを出していたので作って見た時のメモ

## 環境

* macosx10.8(ホストOS)

## 作る仮想インスタンスのOS

* CentOS6.4-x86_64_minimal

## 事前準備に必要なもの
* [homebrew](http://brew.sh/index_ja.html) ※入れていない方は何も考えずに```ruby -e "$(curl -fsSL https://raw.github.com/mxcl/homebrew/go)"```と打とう
* [virtualbox](https://www.virtualbox.org/) ※入れていない方は[そうだvirtualboxを使ってみよう](http://qiita.com/ryurock/items/31029ea9ac3fcb34abdc)からvirtualboxの入手だけを試してください

## 参考にしたサイト

* [[続報]PackerでVagrant用のBoxを作成する](http://www.ryuzee.com/contents/blog/6706)
* [OSXでpackerでCentOS6.4のVirtualBox VMを作成する](http://qiita.com/hnakamur/items/da0ed14192a18405f704)


## とりあえずPackerを試したい方はこちら

* [Packerをつかって3ステップでVagrantのBoxを作る](http://qiita.com/ryurock/items/e3635221e4717f2addfe)



## ソースコード

[ryurock/versicolor](https://github.com/ryurock/versicolor/tree/a2f83daedf9d30b6faa2c83c7536700b9dc6be29)


## Packerのインストール

OSXで試したので他のOSは本家の説明に譲ります
[INSTALL PACKER](http://www.packer.io/intro/getting-started/setup.html)

```shell
brew tap homebrew/binary
brew install packer
``` 

## Packerの実行ファイルを作成する


### 【注意】 packer1.4以前と以降で設定方法が変わりました。

各項目のtypeは

* Packer1.4以前は```virtualbox```
* Packer1.4以降は```virtualbox-iso```

になります。

適当なファイル名.jsonでもいいみたいです

```packer.json
{
  "builders": [
    {
      "type": "virtualbox-iso",
      "vm_name": "box",
      "boot_wait": "10s",
      "disk_size": 512000,
      "guest_os_type": "RedHat_64",
      "iso_checksum": "4a5fa01c81cc300f4729136e28ebe600",
      "iso_checksum_type": "md5",
      "iso_url": "http://ftp.iij.ad.jp/pub/linux/centos/6.4/isos/x86_64/CentOS-6.4-x86_64-minimal.iso",
      "ssh_username": "vagrant",
      "ssh_password": "vagrant",
      "ssh_port": 22,
      "ssh_wait_timeout": "10000s",
      "shutdown_command": "echo '/sbin/halt -h -p' > shutdown.sh; echo 'vagrant'|sudo -S sh 'shutdown.sh'",
      "guest_additions_path": "VBoxGuestAdditions_{{.Version}}.iso",
      "virtualbox_version_file": ".vbox_version",
      "vboxmanage": [
        [
          "modifyvm",
          "{{.Name}}",
          "--memory",
          "2048"
        ],
        [
          "modifyvm",
          "{{.Name}}",
          "--cpus",
          "2"
        ]
      ],
      "http_directory": "./packer/builders/",
      "boot_command": [
        "<tab> text ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/ks.cfg<enter><wait>"
      ]
    }
  ],
  "provisioners": [
    {
      "type": "shell",
      "scripts": [
        "packer/provisioners/base.sh",
        "packer/provisioners/vagrant.sh",
        "packer/provisioners/virtualbox.sh",
        "packer/provisioners/cleanup.sh"
      ],
      "override": {
        "virtualbox-iso": {
          "execute_command": "echo 'vagrant'|sudo -S sh '{{.Path}}'"
        }
      }
    }
  ],
  "post-processors": [
    {
      "type": "vagrant",
      "output": "./packer/vagrant-boxes/CentOS-6.4-x86_64-minimal.box"
    }
  ]
}
```

何が書いてあるのかわからないとおもうので説明していきます

### builders

```packer.json（一部抜粋）
  "builders": [
    {
      "type": "virtualbox-iso",
      "vm_name": "CentOS6.4-x86_minimal",
             .
             .
             .
    }
  ]
```

これは作る仮想インスタンスの設定を記載します。

| 項目名 | 説明 |
|:-----------|------------:|
| type       | 何の仮想インスタンスを作成するかを指定する項目ですAWSのインスタンスとかも指定可能。今回はvirtualboxなので 「virtualbox-iso」を記載 |
| vm_name       | デフォルトのvm名になりますVagrantでもオーバーライドできるの記載しなくても問題ない |
| boot_wait | 最初にVirtualboxが起動bootするまでの待ち時間 |
| disk_size | Virtualboxのディスク容量の指定適当に多めで |
|guest_os_type| CentOSx86系なら「RedHat_64」を指定。typeの一覧は```VBoxManage list ostypes``` でわかる|
|iso_checksum| isoのchecksum。わからない場合は```md5 作るOS.iso```と叩けばわかる|
|iso_url| isoのDL先のURL。何故かHTTPしかサポートしていなかった|
|ssh_username| sshユーザー名。vagrantと連携したいならユーザー名はvagrantにしといたほうが楽かも|
|ssh_password| sshユーザーのパスワード|
|ssh_port| 何も考えずに22でいいでしょう|
|ssh_wait_timeout| SSHの接続時間|
| shutdown_command | シャットダウンコマンド |
| guest_additions_path | Virtualboxのguest_additionsのパス |
| virtualbox_version_file | VirtualBoxのバージョン番号なんでしょう |
| vboxmanage | Virtualboxのインスタンスの設定。今回はメモリを2G、CPUCore数を2としている |
|http_directory| インストール時にローカルにWebサーバをたててkickstartなどの設定情報を持っていくための設定です。kickstartって何？って方は[kickstartでCentOS6の自動インストール](http://wg.drive.ne.jp/miura/archives/2208)をみてください|
|boot_command| boot時のkickstartを実行するときのks.cfgの場所を指定する|


### post-processors

OSを作成した後に実行することを記載する項目です

```packer.json（一部抜粋）
 "post-processors": [
    {
      "type": "vagrant",
      "output": "./packer/vagrant-boxes/CentOS-6.4-x86_64-minimal.box"
    }
  ]
```

| 項目名 | 説明 |
|:-----------|------------:|
| type | vagrantのボックス作る場合はvagrantで|
| output | vagrantのボックス作った後の.boxの吐き出し場所の指定です|


## KickStartファイルを書く

[OSXでpackerでCentOS6.4のVirtualBox VMを作成する](http://qiita.com/hnakamur/items/da0ed14192a18405f704)のまんまです。

まずはディレクトリを作ろう

```shell
mkdir -r packer/vagrant-boxes packer/builders
vim packer/builders/ks.cfg
```

```shell:packer/builders/ks.cfg
install
cdrom
lang en_US.UTF-8
keyboard us
network --bootproto=dhcp
rootpw vagrant
firewall --enabled --service=ssh
authconfig --enableshadow --passalgo=sha512
selinux --disabled
timezone Asia/Tokyo
bootloader --location=mbr

text
skipx
zerombr

clearpart --all --initlabel
autopart

auth  --useshadow  --enablemd5
firstboot --disabled
reboot

%packages --ignoremissing
@core
bzip2
kernel-devel
kernel-headers
-ipw2100-firmware
-ipw2200-firmware
-ivtv-firmware
%end

%post
/usr/bin/yum -y install sudo
/usr/sbin/groupadd -g 501 vagrant
/usr/sbin/useradd vagrant -u 501 -g vagrant -G wheel
echo "vagrant"|passwd --stdin vagrant
echo "vagrant        ALL=(ALL)       NOPASSWD: ALL" >> /etc/sudoers.d/vagrant
chmod 0440 /etc/sudoers.d/vagrant
%end
```

### provisioners

インスタンスが作成された後に実行するものです。KickStartで仮想インスタンスにプラスアルファの機能を追加する場合はprovisioners側で管理したほうがいいかと思います。provisionersのハッシュの値を入れれば任意のファイルを実行できます


```packer.json（一部抜粋）
  "provisioners": [
    {
      "type": "shell",
      "scripts": [
        "packer/provisioners/base.sh",
        "packer/provisioners/vagrant.sh",
        "packer/provisioners/virtualbox.sh",
        "packer/provisioners/cleanup.sh"
      ],
      "override": {
        "virtualbox-iso": {
          "execute_command": "echo 'vagrant'|sudo -S sh '{{.Path}}'"
        }
      }
    }
  ],
```



## ビルドの実行

```shell
cd packer.jsonが置いてあるカレントディレクトリ
packer build --only=virtualbox-iso packer.json
# 古いpackerのバージョンの方は下記のコマンドで
# packer build -only=virtualbox packer.json


virtualbox output will be in this color.

==> virtualbox: Downloading or copying Guest additions checksums
    virtualbox: Downloading or copying: http://download.virtualbox.org/virtualbox/4.2.10/SHA256SUMS
==> virtualbox: Downloading or copying Guest additions
    virtualbox: Downloading or copying: http://download.virtualbox.org/virtualbox/4.2.10/VBoxGuestAdditions_4.2.10.iso
==> virtualbox: Downloading or copying ISO
    virtualbox: Downloading or copying: http://ftp.iij.ad.jp/pub/linux/centos/6.4/isos/x86_64/CentOS-6.4-x86_64-minimal.iso
==> virtualbox: Starting HTTP server on port 8081
==> virtualbox: Creating virtual machine...
==> virtualbox: Creating hard drive...
==> virtualbox: Creating forwarded port mapping for SSH (host port 3213)
==> virtualbox: Executing custom VBoxManage commands...
    virtualbox: Executing: modifyvm CentOS6.4-x86_minimal --memory 2048
    virtualbox: Executing: modifyvm CentOS6.4-x86_minimal --cpus 2
==> virtualbox: Starting the virtual machine...
==> virtualbox: Waiting 10s for boot...
==> virtualbox: Typing the boot command...
==> virtualbox: Waiting for SSH to become available...
==> virtualbox: Connected to SSH!
==> virtualbox: Uploading VirtualBox version info (4.2.10)
==> virtualbox: Uploading VirtualBox guest additions ISO...
==> virtualbox: Gracefully halting virtual machine...
    virtualbox: 
    virtualbox:
    virtualbox: Broadcast message from vagrant@localhost.localdomain
    virtualbox: (unknown) at 0:22 ...
    virtualbox:
    virtualbox: The system is going down for power off NOW!
==> virtualbox: Preparing to export machine...
    virtualbox: Deleting forwarded port mapping for SSH (host port 3213)
==> virtualbox: Exporting virtual machine...
==> virtualbox: Unregistering and deleting virtual machine...
==> virtualbox: Running post-processor: vagrant
==> virtualbox (vagrant): Creating Vagrant box for 'virtualbox' provider
    virtualbox (vagrant): Copying: output-virtualbox/packer-disk1.vmdk
    virtualbox (vagrant): Copying: output-virtualbox/packer.ovf
    virtualbox (vagrant): Renaming the OVF to box.ovf...
    virtualbox (vagrant): Compressing box...
    virtualbox (vagrant): Compressing: Vagrantfile
    virtualbox (vagrant): Compressing: box.ovf
    virtualbox (vagrant): Compressing: metadata.json
    virtualbox (vagrant): Compressing: packer-disk1.vmdk
Build 'virtualbox' finished.

==> Builds finished. The artifacts of successful builds are:
--> virtualbox: 'virtualbox' provider box: ./packer/vagrant-boxes/CentOS-6.4-x86_64-minimal.box
```

## VagrantFileに追加

VagrantFileがない場合は作る

```shell
cd packer.jsonが置いてあるカレントディレクトリ
vagrat init
```

VagrantFileに書きましょ

```ruby:Vagrantfile
# -*- mode: ruby -*-
# vi: set ft=ruby :

BOX_NAME = "CentOS6.4-x86-minimal"

Vagrant.configure("2") do |config|
  config.vm.box = BOX_NAME

  config.vm.box_url = "./packer/vagrant-boxes/CentOS-6.4-x86_64-minimal.box"

  config.vm.network :private_network, ip: "192.168.56.101"

  config.vm.provider :virtualbox do |vb|
     vb.name = BOX_NAME
     vb.customize ["modifyvm", :id, "--memory", "2048"]
     vb.customize ["modifyvm", :id, "--cpus", "2"]
 
   end
end
```

## Vagrantで起動確認

```shell
vagrant up

Bringing machine 'default' up with 'virtualbox' provider...
[default] Box 'CentOS6.4-x86-minimal' was not found. Fetching box from specified URL for
the provider 'virtualbox'. Note that if the URL does not have
a box for this provider, you should interrupt Vagrant now and add
the box yourself. Otherwise Vagrant will attempt to download the
full box prior to discovering this error.
Downloading or copying the box...
Extracting box...e: 285M/s, Estimated time remaining: --:--:--)
Successfully added box 'CentOS6.4-x86-minimal' with provider 'virtualbox'!
[default] Importing base box 'CentOS6.4-x86-minimal'...
[default] Matching MAC address for NAT networking...
[default] Setting the name of the VM...
[default] Clearing any previously set forwarded ports...
[default] Creating shared folders metadata...
[default] Clearing any previously set network interfaces...
[default] Preparing network interfaces based on configuration...
[default] Forwarding ports...
[default] -- 22 => 2222 (adapter 1)
[default] Running any VM customizations...
[default] Booting VM...
[default] Waiting for VM to boot. This can take a few minutes.
```

これでオレオレ.boxの出来上がりです！！