Packerを使ってVagrant Boxを作ってみた

永遠の中二病です、ごきげんよう。学生時代の趣味はWindowsの再インストールでした。

環境構築って面倒ですよね。単純作業の割には微妙な手順ミスで後からハマったりして、もっと自動化、効率化できないかなと昔から思っていました。Windowsにも自動インストールの仕組みは以前からありましたが、そのための設定がまた大変だったものです。そんなわけで、今回はUNIX界隈に場所を移して、仮想環境を楽に構築してみようというお話です。

環境構築今昔話

さて、UNIX界隈で仮想環境の構築と言われてどんな手順を思い浮かべるでしょうか?

  1. 仮想マシンを立てる
  2. OSのイメージをダウンロード
  3. OSインストール
  4. ミドルウェアインストール
  5. 設定諸々

ざっと挙げても沢山ありますね。これを手作業でやっていては大変です。もちろんこうした作業を自動化する仕組みは色々あって、KickstartのようなOSインストールの自動化であったり、Puppetのようなサーバの集中設定管理のようなものは以前から提供されていました。

また最近だと、昨年はVagrantChefのようなツールが大いに話題になりました。これらは仮想マシンの操作やプロビジョニング(ソフトウェアの整備やシステム環境設定など、稼働するための準備全般)という部分をプログラマブルに行えるようにするためのものです。上記の手順だと4〜5に相当する部分+αですね。

  1. 仮想マシンを立てる
  2. OSのイメージをダウンロード
  3. OSインストール
  4. ミドルウェアインストール … OK!
  5. 設定諸々 … OK!

はい、あとは1〜3まで自動化できれば、ワンストップで仮想環境が作れそうです。

ところが、1〜3に相当する仮想マシンイメージの作成に関することは、Vagrant/Chefと比較するとほとんど話題に上がっていません。というのも、予め用意されたイメージファイルが各所で配布されているので、大抵はそれを利用しているからなのですね。個人用途などではそれでも十分かと思いますが、業務利用となると素性の明らかな…つまり意図された手順に沿ってインストールされた仮想マシンを使いたいもの。

そこで今回は、Vagrantから利用することを想定した仮想マシンイメージを実際に作る事例を紹介しようと思います。なお、仮想化ソフトウェアにはVirtualBoxを利用し、ホストはOS X、ゲストはCentOS 6.5を想定しています。他のOSや仮想化ソフトウェアを利用される場合は一部を読み替えていただければと思います。

環境構築の概要

前置きが長くなりましたが、今回の環境構築のゴールは仮想マシンCentOSをインストールして、Vagrantから利用できるようになることです。これを踏まえ、想定環境は次の通りとしました。各ツールのバージョンは執筆当時の最新版です。

ホストOS
OS X 10.9.x (Mavericks)
ゲストOS
CentOS 6.5 (64bit)
その他ツール
VirtualBox 4.3.6
Vagrant 1.4.3
Packer 0.5.1

また今回仮想マシンを作成するにあたっては、Packerというツールを使用します。同じような機能を持つツールとしてVeeweeというものもあるのですが、PackerはVirtualBoxVMWareに加えてAmazon EC2やDigitalOceanのようなクラウドサービスについても一貫性のあるインタフェースで作成できるため、汎用性を考慮してこちらを選びました。

必要なソフトウェアのインストール

Packer公式サイトのダウンロードページに各プラットフォーム向けのパッケージがありますので、こちらをダウンロード、インストールします。homebrewのようにパッケージ管理システム上に存在する場合もありますので、そちらからインストールしても構わないでしょう。

また、VirtualBoxVagrantもインストールが必要になります。これらは公式サイトからパッケージでダウンロード、インストールします。Vagrantはパッケージ管理システム上にも存在しますが、執筆時点ではバージョンが古いのでパッケージからインストールします。

設定ファイルの作成

Packerを設定するにあたって、今回は次の3つのファイルを作成します。

  • Packer自体の設定ファイル
  • OSインストール後のプロビジョニング用シェルスクリプト
  • OS自動インストール用の設定ファイル
  • Vagrantの設定ファイル

Packer自体の設定ファイル

まずPacker自体の設定ファイルですが、これはJSON形式で記述します。作業ディレクトリは任意ですが、その配下にBoxが作成されることを考慮しておくと良いでしょう。ファイル名も任意ですが、ここでは便宜上「packer.json」とします。

{
    "builders": [
        {
            "type": "virtualbox-iso",
            "guest_os_type": "RedHat_64",
            "iso_url": "http://ftp.iij.ad.jp/pub/linux/centos/6.5/isos/x86_64/CentOS-6.5-x86_64-minimal.iso",
            "iso_checksum_type": "md5",
            "iso_checksum": "0d9dc37b5dd4befa1c440d2174e88a87",
            "ssh_username": "vagrant",
            "ssh_password": "vagrant",
            "ssh_wait_timeout": "3000s",
            "vm_name": "box",
            "http_directory": "./",
            "boot_wait": "10s",
            "boot_command":[
                "",
                "linux ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/ks.cfg ",
                ""
            ]
        }
    ],
    "provisioners": [
        {
            "type": "shell",
            "script": "provisioners.sh"
        }
    ],
    "post-processors": [
        {
            "type": "vagrant",
            "output": "centos-6.5-x86_64.box"
        }
    ]
}

この中で説明が必要な項目について触れていきます。

  • buildersのtypeは過去のバージョンでは「virtualbox」でしたが、最新版では「virtualbox-iso」となります。
  • buildersのssh_usernameとssh_passwordは仮想マシンにログインする時に使います。
  • buildersのboot_waitは、ブート時に待つ時間で、環境によるかもしれませんが短すぎるとコマンドの入力に失敗します。
  • buildersのboot_commandは、ブート時にPakerがOSインストーラを操作するためのコマンド群です。
  • provisionersは、OSインストール後のプロビジョニングについて記述します。今回はシェルスクリプトとして「provisioners.sh」を呼び出すようにしていますが、ChefやPuppetも使おうと思えば使えます。
  • post-processorsは、インストール終了後の出力情報です。ここではVagrant用に「centos-6.4-x86_64.box」というファイル名で保存します。

OSインストール後のプロビジョニング用シェルスクリプト

次に、provisionersの項目で外に出したプロビジョニング用スクリプトです。こちらも作業ディレクトリディレクトリにprovisionersで指定したファイル(今回はprovisioners.sh)を設置します。

#!/bin/bash

sudo sed -i "s/^.*requiretty/#Defaults requiretty/" /etc/sudoers
sudo sed -i "s/#UseDNS yes/UseDNS no/" /etc/ssh/sshd_config
sudo sed -i "s/SELINUX=enforcing/SELINUX=disabled/" /etc/selinux/config

sudo sh -c 'echo "[epel]" >> /etc/yum.repos.d/epel.repo'
sudo sh -c 'echo "name=epel" >> /etc/yum.repos.d/epel.repo'
sudo sh -c 'echo "baseurl=http://download.fedoraproject.org/pub/epel/6/\$basearch" >> /etc/yum.repos.d/epel.repo'
sudo sh -c 'echo "enabled=0" >> /etc/yum.repos.d/epel.repo'
sudo sh -c 'echo "gpgcheck=0" >> /etc/yum.repos.d/epel.repo'

sudo yum -y install gcc make automake autoconf libtool gcc-c++ kernel-headers-`uname -r` kernel-devel-`uname -r` zlib-devel openssl-devel readline-devel sqlite-devel perl wget nfs-utils bind-utils
sudo yum -y --enablerepo=epel install dkms

mkdir -pm 700 /home/vagrant/.ssh
wget --no-check-certificate 'https://raw.github.com/mitchellh/vagrant/master/keys/vagrant.pub' -O /home/vagrant/.ssh/authorized_keys
chmod 0600 /home/vagrant/.ssh/authorized_keys
chown -R vagrant /home/vagrant/.ssh

cd /tmp
sudo mount -o loop /home/vagrant/VBoxGuestAdditions.iso /mnt
sudo sh /mnt/VBoxLinuxAdditions.run
sudo umount /mnt
sudo /etc/init.d/vboxadd setup

ここで行っているのは、主にVirtualBoxGuestAdditionsをインストールするための設定と、Vagrantを利用してSSHログインするための設定です。ただのシェルスクリプトですので、読めば理解いただけるかと思います。なお、yumでインストールしているパッケージはGuestAdditionsに必要な最低限のものとなっています。

OS自動インストール用の設定ファイル

次に、OS自動インストール用の設定ファイルを用意します。Linuxの場合はKickstartという自動インストールの仕組みがありますので、その設定ファイルを作成します。こちらは作業ディレクトリに「ks.kfg」として設置します。

install
cdrom
lang en_US.UTF-8
keyboard us
network --bootproto=dhcp
rootpw --iscrypted $1$bru//p3Y$AIC48J2Me8qwiR5JW/xIs/
firewall --enabled --service=ssh
authconfig --enableshadow --passalgo=sha512
selinux --disabled
timezone UTC
bootloader --location=mbr

text
skipx
zerombr

clearpart --all --initlabel
autopart

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

%packages --nobase
@core
%end

%post
/usr/bin/yum -y install sudo
/usr/sbin/groupadd vagrant
/usr/sbin/useradd vagrant -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

こちらについては、Vagrantを利用して「vagrant/vagrant」でログインできるように、またパスワード無しでsudoできるようにしています。rootのパスワードもひとまず「vagrant」としていますので、適宜変更してください。

Vagrantの設定ファイル

最後にVagrantの設定ファイルですが、こちらはvagrantコマンドでスケルトンを生成できますので、利用してみましょう。作業ディレクトリ上で次のコマンドを発行してください。

$ vagrant init centos-6.5-x86_64

これで作業ディレクトリ上に「Vagrantfile」というファイルが生成されますので、次の箇所だけ編集します。

# 仮想マシンにマウントするディレクトリを指定
  # config.vm.synced_folder "../data", "/vagrant_data"
  config.vm.synced_folder "./", "/vagrant_data"

 

# コメントアウトを解除
  config.vm.network :public_network

なお、この設定ではネットワークインタフェースが複数ある場合に選択を求められることになりますので、環境に応じて次のように指定しておくと自動選択されます。

  #en1: Wi-Fi (AirPort) の部分は選択したいインタフェースを指定
  config.vm.network :public_network, :bridge => "en1: Wi-Fi (AirPort)"

イメージ作成

さて、これでイメージ作成の準備は整いました。作業ディレクトリ上で次のコマンドを発行してください。

$ packer build packer.json

設定に問題が無ければ、あとは放置しておくだけで仮想マシンイメージの作成が完了します。完了したら、おもむろに

$ vagrant box add centos-6.5-x86_64 centos-6.5-x86_64.box
$ vagrant up

と打ち込んでみましょう。特にエラー無く起動すれば完成です!「vagrant ssh」で接続するなり、壊すなり、お好きなようにご利用ください。

補足:vagrant upでエラーが発生する場合

下記のようなエラーが発生する場合があるようです。

Failed to mount folders in Linux guest. This is usually beacuse
the "vboxsf" file system is not available. Please verify that
the guest additions are properly installed in the guest and
can work properly. The command attempted was:

mount -t vboxsf -o uid=`id -u vagrant`,gid=`getent group vagrant | cut -d: -f3` /vagrant /vagrant
mount -t vboxsf -o uid=`id -u vagrant`,gid=`id -g vagrant` /vagrant /vagrant

この場合、共有フォルダが正しくマウントされていませんが、仮想環境には入れますので、

$ sudo /etc/init.d/vboxadd setup

とすることで再度正常にGuestAdditionsがインストールされます。その後、ローカルから

$ vagrant halt
$ vagrant up

で正常化します。

あとがき

最後が実に呆気なかったのですが、それだけ自動化の威力が大きいということでご勘弁を…。 VagrantとChefでOSインストール後の環境をプログラマブルに制御し、更に前段階の仮想マシンイメージ作成をPackerで自動化することで、再利用性、一貫性のある環境構築をゼロから行えるようになりました。この仕組みを使えば、多人数の業務プロジェクトなどでも標準化された開発環境を容易に実現できるようになります。またPackerを利用すれば、クラウドサーバの構築についても同じインタフェースが利用できますので、本番環境の構築にも手を広げられる可能性が見えてくるのではないでしょうか。今回紹介した内容はPackerの中でもほんの一部ですので、ぜひ思い思いの使い方をしていただければと思います。

インフラ環境もいよいよ本格的に、職人技から自動化の時代になってきた感がありますね。楽をしても良い所は、どんどん楽をしたいものです。