virt-builderでUbuntuのVMイメージを作成する

# はじめに

プライマリNICでDHCPクライアントが動いて、sshでログインできて、`sudo`できるVMイメージがないか探していたのですが、`virt-builder`を使って希望通りのVMイメージを作れることがわかったので記録に残します。

ホストはUbuntu20.04LTSです。

# VMイメージ作成ツールのインストール

`virt-builder`を使います。

```
suto apt install libguestfs-tools
```

# VMイメージ作成
今回はUbuntuとDebianのイメージを作成しました。

## VMイメージ作成(Ubuntu)

ベースイメージを自動ダウンロードするので、インターネット接続環境が必要です。

```
USERNAME=ubuntu
sudo virt-builder ubuntu-20.04 \
     --format qcow2 \
     --hostname ubuntu \
     --root-password password:foobar \
     --mkdir /home/$USERNAME/.ssh \
     --copy-in $HOME/.ssh/id_rsa.pub:/home/$USERNAME/.ssh \
     --move /home/$USERNAME/.ssh/id_rsa.pub:/home/$USERNAME/.ssh/authorized_keys \
     --chmod 0700:/home/$USERNAME/.ssh \
     --edit '/etc/netplan/01-netcfg.yaml: s/enp1s0/ens3/' \
     --firstboot-command " \
     dpkg-reconfigure openssh-server; \
     useradd -m -G sudo,operator -s /bin/bash $USERNAME; \
     chage -M -1 $USERNAME; \
     chown -R $USERNAME /home/$USERNAME; \
     perl -pi -e 's/^%sudo.*$/%sudo     ALL=(ALL:ALL) NOPASSWD: ALL/' /etc/sudoers; \
     localectl set-keymap jp \
     " \
     -o ubuntu-20.04.qcow2
```

`virt-builder`のパラメータについて解説します。

### `ubuntu-20.04`
ベースイメージのディストリビューション名を指定します。`virt-builder --list`で一覧が取得できます。バージョンはたくさんありますが種類としては下記が提供されているようです。

- `centos`
- `cirros`
- `debian`
- `fedora`
- `ubuntu`
- `freebsd`
- `scientificlinux`
- `opensuse`

なお、今回指定していませんが`--arch`でアーキテクチャを指定することもできます。

### `--format qcow2`
QCOW2フォーマットでイメージを作ります。無指定の場合rawです。

### `--hostname ubuntu`
ホスト名を指定します。指定しない場合、ダウンロードした元イメージにつけられてる名前になります。

### `--root-password password:foobar`
`root`アカウントのパスワードを指定します。うまく`sudo`できるよう調整がすんだら指定は削除したほうがいいでしょう。

### `--mkdir /home/$USERNAME/.ssh`
SSHキーの置き場所を作ります。起動時にアカウントを作るのですが、先にキーを置いておきたいのでこうしています。

### `--copy-in`
ホストの公開鍵をVMイメージにコピーします。ここでは作業アカウントの公開鍵をコピーしています。

### `--move`
コピーした公開鍵を`authorized_keys`とします。これで公開鍵認証によるログインになります。コピー元のファイル名を`authorized_keys`としておくならこの操作は不要です。

### `--chmod 0700:/home/$USERNAME/.ssh`
`.ssh`のパーミッションを設定します。`700`だと10進数とみなされて変なパーミッションになります。ご注意を。

### `--edit '/etc/netplan/01-netcfg.yaml: s/enp1s0/ens3/'`
起動してみたらNICのインタフェース名が設定と違っていたので合わせます。適宜。

### `--firstboot-command`
最初の起動時にいろいろコマンドを実行します。以下解説。

- `dpkg-reconfigure openssh-server` ホスト鍵が存在しないため外部から接続できない問題を解決します
- `useradd` アカウントを作ります
- `chage` パスワード有効期限を最大にします
- `chown` 上の`--mkdir`で作るとオーナーが`root`になるので調整します
- `perl` `/etc/sudoers`を編集し、てパスワードなしで`sudo`できるようにします
- `localectl` キーマップを指定します

### `-o`
作成するVMイメージのファイル名を指定します。指定しなければ実行ディレクトリにテキトーな名前で作られます。

## VMイメージ作成(Debian)

Ubuntuイメージと同じく、インターネット接続が必要です。

```
USERNAME=debian
sudo virt-builder debian-10 \
     --format qcow2 \
     --hostname debian \
     --root-password password:hogehoge \
     --install sudo \
     --mkdir /home/$USERNAME/.ssh \
     --copy-in $HOME/.ssh/id_rsa.pub:/home/$USERNAME/.ssh \
     --move /home/$USERNAME/.ssh/id_rsa.pub:/home/$USERNAME/.ssh/authorized_keys \
     --chmod 0700:/home/$USERNAME/.ssh \
     --edit '/etc/network/interfaces: s/ens2/ens3/' \
     --firstboot-command " \
     dpkg-reconfigure openssh-server; \
     useradd -m -G sudo,operator -s /bin/bash $USERNAME; \
     chage -M -1 $USERNAME; \
     chown -R $USERNAME /home/$USERNAME; \
     perl -pi -e 's/^%sudo.*$/%sudo     ALL=(ALL:ALL) NOPASSWD: ALL/' /etc/sudoers; \
     localectl set-keymap jp \
     " \
     -o debian-10.qcow2
```

`sudo`がなかったようなので`--install sudo`を加えたのと、やはりNICの名前が一致しなかったのですがこちらは`/etc/network/interface`だったので`--edit`の内容が異なります。

# 動作確認

`virt-install`を使うなどして動作確認してみます。下記はUbuntuの例です。

## volumeの作成

上記で作成したイメージを直接指定してもいいのですが、そうするとVM上で読み書きすることでイメージの内容が書き換わりますので、イメージファイルを元にvolumeを作成します。

まずサイズ確認。

```
$ qemu-img info ubuntu-20.04.qcow2 
image: modules/hosts/images/ubuntu-20.04.qcow2
file format: qcow2
virtual size: 6 GiB (6442450944 bytes)
disk size: 1.66 GiB
cluster_size: 65536
Format specific information:
    compat: 1.1
    lazy refcounts: false
    refcount bits: 16
    corrupt: false
```

サイズを指定して、中身が空のvolumeを作ります。

```
$ virsh vol-create-as default ubuntu-vm.qcow2 6GiB --format qcow2
```

次にファイルの内容で中身を上書きします。

```
$ virsh vol-upload ubuntu-vm.qcow2 ubuntu-20.04.qcow2
```

## VM起動
下記のように`virt-install`を実行するとVMが自動起動したうえ、`virt-viewer`でコンソール画面が開きます。

```
$ virt-install \
-n ubuntu-vm \
--vcpus 1 \
--memory 2048 \
--disk vol=default/ubuntu-vm.qcow2 \
--network network=default --boot hd
```

## sshアクセス

ログインプロンプトが出ていませんが、`virt-viewer`の画面をクリックしてALT+F1を押せばログインプロンプトの画面に切り替わると思います。`root`でログインして`ip addr`でIPアドレスを確認してみましょう。

あるいは `virsh net-dhcp-leases default` で、DHCPで配ったアドレスが1わかると思います。

ホストから `ssh ubuntu@そのアドレス` でログインしてみます。

```shell-session
$ virsh net-dhcp-leases default 
 Expiry Time           MAC address         Protocol   IP address           Hostname   Client ID or DUID
------------------------------------------------------------------------------------------------------------------------------------------------
 2021-02-01 13:18:25   52:54:00:7f:66:3d   ipv4       192.168.122.147/24   ubuntu     ff:b5:5e:67:ff:00:02:00:00:ab:11:25:3b:22:27:88:44:90:d9

$ ssh ubuntu@192.168.122.147
The authenticity of host '192.168.122.147 (192.168.122.147)' can't be established.
ECDSA key fingerprint is SHA256:BXNe33zg6ip3NsbqYTeJ2iv+Z6qvvpcrxdP3Rb2+gYM.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '192.168.122.147' (ECDSA) to the list of known hosts.
Welcome to Ubuntu 20.04.1 LTS (GNU/Linux 5.4.0-65-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

ubuntu@ubuntu:~$ 

```

## おかたづけ

```
virsh destroy ubuntu-vm
virsh undefine ubuntu-dm
virsh vol-delete ubuntu-vm.qcow2 --pool default
```

# おわりに
DHCPクライアントでぶら下がりつつsshでログインできるVMを作ることができました。ユーザーアカウント周りの処理はもう少し綺麗にできるかもしれません。(`--mkdir`まわりはいまいちだと思います)

今回は`virt-builder`を使いましたが、すでに存在しているディスクイメージに対して変更を加える`virt-customize`コマンドというのもあります。状況に応じて使い分けできるといいように思います。