virt-builder でゲストを作って virt-resize でリサイズして virt-customize でカスタマイズ

下記の記事で cloud-init を使って KVM のゲストの IP アドレスとホスト名を自動設定しましたが、

- [KVM (libvirt) で cloud-init を使って IP アドレスとホスト名を自動設定](http://qiita.com/ngyuki/items/c274c15760429c27c721)

そもそもこれ、ベースとなるイメージからゲストをダバーっと作りたかっただけです。

`libguestfs` に含まれる `virt-customize` を使えばゲストのイメージの中を簡単にいじれるようなので試してみました。

## ホストに libguestfs をインストール

ホストに `libguestfs` をインストールします。

```sh
yum -y install libguestfs libguestfs-tools libguestfs-tools-c
```

## ベースイメージを作成

`libguestfs-tools-c` 付属する `virt-builder` を使ってベースイメージのゲストを作成します。

イメージのボリュームを作成します。なおこの例では LVM を使っていますが、raw ファイルや qcow2 でもできます。

```sh
lvcreate vg1 -n base -L 6G
```

イメージを作成します。

```sh
virt-builder centos-7.2 \
  -o /dev/vg1/base \
  --arch x86_64 \
  --root-password password:password \
  --timezone Asia/Tokyo \
  --run-command '
    set -eux
    mkdir -p /root/.ssh/pub
    chmod 700 /root/.ssh
    curl -fsSL https://github.com/ngyuki.keys > /root/.ssh/authorized_keys
    chmod 600 /root/.ssh/authorized_keys
  ' \
  --firstboot-command '
    restorecon -RFv /root/.ssh/
  '
```

`--run-command` で指定したコマンドはイメージの作成時に chroot して実行されます(`--run` でファイルも指定できる)。

`--firstboot-command` で指定したコマンドはゲストの初回起動時にだけ実行されます(`--firstboot` でファイルも指定できる)。

その他いろいろオプションはあります。詳しくは `man virt-builder`。

イメージができたら `virt-install` でインポートします。

```sh
virt-install \
  --name base \
  --disk path=/dev/vg1/base \
  --network network=default \
  --hvm --virt-type kvm \
  --vcpus 1 --ram 1024 --arch x86_64 \
  --os-type linux --os-variant rhel7 \
  --boot hd --graphics none --serial pty --console pty \
  --import --noreboot
```

起動してコンソールに接続します。

```sh
virsh start base
virsh console base
```

必要に応じてゲストの中身を修正し、終わったらシャットダウンします（`--run-command` だけで完結するなら作業は不要）。

```sh
virsh shutdown base
```

`virt-sysprep` でゲストのイメージから余計なものをいろいろ削除します（ログとか SSH ホスト鍵とか）。

```sh
virt-sysprep -d base --operations defaults,-ssh-userdir
```

実際にどんなことが行われるかは `virt-sysprep --list-operations` でそれとなく察せられると思います。
この例では `/root/.ssh` の削除だけ除外しています（デフォだと `/root/.ssh` が削除されてしまうのでせっかく配置した SSH 公開鍵も消えてしまう）。

## ゲストを作成

新しく作成するゲストのためのボリュームを作成します。

```sh
lvcreate vg1 -n sv01 -L 8G
```

ベースイメージは 6G でしたが、これから作成するゲストのイメージは 8G にしてパーティションの拡張を行います。それには `virt-resize` を使えばできるのですが、拡張するパーティションの詳細を見るために `virt-filesystems` でベースイメージのパーティションを調べます。

```sh
virt-filesystems -a /dev/vg1/base -hl
# Name       Type        VFS   Label  Size  Parent
# /dev/sda1  filesystem  ext4  -      512M  -
# /dev/sda3  filesystem  ext4  -      4.5G  -
```

拡張するのは `/dev/sda3` なので、下記のように `virt-resize` で拡張しつつコピーします。

```sh
virt-resize --expand /dev/sda3 /dev/vg1/base /dev/vg1/sv01
```

出来上がった新しいイメージのパーティションを見てみます。

```sh
virt-filesystems -a /dev/vg1/sv01 -hl
# Name       Type        VFS   Label  Size  Parent
# /dev/sda1  filesystem  ext4  -      512M  -
# /dev/sda3  filesystem  ext4  -      6.5G  -
```

ゲストをインポートします。

```sh
virt-install \
  --name sv01 \
  --disk path=/dev/vg1/sv01 \
  --network network=default \
  --hvm --virt-type kvm \
  --vcpus 1 --ram 1024 --arch x86_64 \
  --os-type linux --os-variant rhel7 \
  --boot hd --graphics none --serial pty --console pty \
  --import --noreboot
```

ゲストのホスト名を変更し、さらに初回起動時に IP アドレスが設定されるようにします。

```sh
virt-customize -d sv01 --hostname sv01 --firstboot-command '
    nmcli con modify eth0 \
      connection.autoconnect yes \
      ipv4.method manual \
      ipv4.addresses 192.168.33.21/24 \
      ipv4.gateway 192.168.33.1 \
      ipv4.dns 192.168.33.1
    nmcli con up eth0
  '
```

ゲストを開始します。

```sh
virsh start sv01
```

IP アドレスやホスト名がそれっぽく設定されていることを確認します。

```sh
ssh 192.168.33.21 uname -n
```