virt-builder で Ubuntu 18.04 を入れようとしてハマった件

とある事情で Ubuntu 18.04 のクリーンで直ぐにぶち壊せる環境が欲しかったので virt-builder で入れようとしたらすごくハマった件。

virt-builder でゲストを作って virt-resize でリサイズして virt-customize でカスタマイズ - Qiita でやってたのをもっと簡素化して Ubuntu 18.04 でやりました。CentOS 7 とか 8 なら同じ手順でサクッと出来たんですけど・・

環境

  • ホスト CentOS 8.2.2004
  • ゲスト Ubuntu 18.04
  • qemu-kvm 2.12.0
  • libvirt 4.5.0
  • libguestfs-tools 1.38.4

コンソールに何も表示されない

virt-builder でイメージを作ってから virt-install でインポートします。

virt-builder ubuntu-18.04 \
  --output /var/lib/libvirt/images/ubuntu-18.04.img \
  --arch x86_64 \
  --hostname ubuntu-18.04 \
  --root-password password:password \
  --timezone Asia/Tokyo

virt-install \
  --name ubuntu-18.04 \
  --hvm \
  --virt-type kvm \
  --ram 4096 \
  --vcpus 4 \
  --arch x86_64 \
  --os-type linux \
  --os-variant ubuntu18.04 \
  --boot hd \
  --disk path=/var/lib/libvirt/images/ubuntu-18.04.img \
  --network network=default \
  --graphics none \
  --serial pty \
  --console pty \
  --import

がしかし virt-install の後のコンソールになにも表示されず、うんともすんとも言わなくなりました。

シリアルコンソールが有効になっていないだけ? と思いつつ --graphics vnc,port=5901,listen=127.0.0.1 にして VNC で繋いでみたところ、普通にログインプロンプトが表示されていました。

ログインして cat /proc/cmdline してみたところ次のとおりです。console=ttyS0 がなくシリアルコンソールが利用可能になっていません。

BOOT_IMAGE=/boot/vmlinuz-4.15.0-20-generic root=UUID=8a5c65a8-9852-4c2a-9789-627cb736abe5 ro quiet splash vt.handoff=1

/etc/default/grubGRUB_CMDLINE_LINUX=console=ttyS0,115200 を追記して update-grub してからリブートすれば virsh console が利用可能になったので、これを virt-builder に仕込みます。

IPアドレスが付与されない

virt-builder ubuntu-18.04 \
  --output /var/lib/libvirt/images/ubuntu-18.04.img \
  --arch x86_64 \
  --hostname ubuntu-18.04 \
  --root-password password:password \
  --timezone Asia/Tokyo \
  --append-line '/etc/default/grub:GRUB_CMDLINE_LINUX="console=ttyS0,115200"' \
  --run-command 'update-grub'

これで virt-install するとコンソールにもプロンプトが表示されてログインできました。

がしかし ip addr してみたところIPアドレスが付与されていません。

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: enp1s0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 52:54:00:6e:c8:5e brd ff:ff:ff:ff:ff:ff

cat /etc/netplan/01-netcfg.yaml してみたところ次の通りでした。設定のデバイス名と実際のデバイス名に齟齬があることが原因です。

network:
  version: 2
  renderer: networkd
  ethernets:
    ens2:
      dhcp4: yes

次の Issue も見つかりました。

この Issue にもある通り net.ifnames=0 biosdevname=0 を追加してデバイス名を eth0 に固定してしまえば良いと思うので virt-builder に仕込みます。

SSHホスト鍵が存在しない

virt-builder ubuntu-18.04 \
  --output /var/lib/libvirt/images/ubuntu-18.04.img \
  --arch x86_64 \
  --hostname ubuntu-18.04 \
  --root-password password:password \
  --timezone Asia/Tokyo \
  --append-line '/etc/default/grub:GRUB_CMDLINE_LINUX="console=ttyS0,115200 net.ifnames=0 biosdevname=0"' \
  --run-command 'update-grub' \
  --write '/etc/netplan/01-netcfg.yaml:
network:
  version: 2
  renderer: networkd
  ethernets:
    eth0:
      dhcp4: yes
'

これで virt-install するとDHCPでIPアドレスが付与されるようになりました。

がしかしSSHでログインしようとすると Connection reset とか返されて接続出来ません。

コンソールから /var/log/auth.log を見てみると次の通り。ホスト鍵が生成されていないことが原因でした。

error: Could not load host key: /etc/ssh/ssh_host_rsa_key
error: Could not load host key: /etc/ssh/ssh_host_ecdsa_key
error: Could not load host key: /etc/ssh/ssh_host_ed25519_key
fatal: No supported key exchange algorithms [preauth]

ホスト鍵が無ければ sshd の開始時に自動で作成されるものだと思っていたんですが、ディストリビューションに依るものなのでしょうか。CentOS 8 の場合は sshd.service に先立って開始する sshd-keygen.target に含まれる sshd-keygen@rsa.service sshd-keygen@ecdsa.service sshd-keygen@ed25519.service によってホスト鍵がなければ作成されるようになっています。

virt-builder --notes ubuntu-18.04 してみたところ、次のように --firstboot-command に仕込むように記載がありました。

  --firstboot-command "dpkg-reconfigure openssh-server"

これを virt-builder に仕込みます。

SSHでrootログインが出来ない

virt-builder ubuntu-18.04 \
  --output /var/lib/libvirt/images/ubuntu-18.04.img \
  --arch x86_64 \
  --hostname ubuntu-18.04 \
  --root-password password:password \
  --timezone Asia/Tokyo \
  --append-line '/etc/default/grub:GRUB_CMDLINE_LINUX="console=ttyS0,115200 net.ifnames=0 biosdevname=0"' \
  --run-command 'update-grub' \
  --firstboot-command 'dpkg-reconfigure openssh-server' \
  --write '/etc/netplan/01-netcfg.yaml:
network:
  version: 2
  renderer: networkd
  ethernets:
    eth0:
      dhcp4: yes
'

これでゲストの初回起動時にSSHのホスト鍵が作成されます。

がしかし SSH でログインしようとしてみたところ、パスワード入力のプロンプトは表示されるものの正しいパスワードを入力しても Permission denied, please try again. とか返されてログインできません。

sshd がデフォだと root でパスワード認証ではログインできないためでした。ちょっとした確認のために直ぐぶっ壊せる環境をホスト内で閉じたネットワークの中に作りたかっただけなので、root でパスワードログインできるように virt-builder/etc/ssh/sshd_config に追記します。

SSHホスト鍵が存在しない、ふたたび

virt-builder ubuntu-18.04 \
  --output /var/lib/libvirt/images/ubuntu-18.04.img \
  --arch x86_64 \
  --hostname ubuntu-18.04 \
  --root-password password:password \
  --timezone Asia/Tokyo \
  --append-line '/etc/default/grub:GRUB_CMDLINE_LINUX="console=ttyS0,115200 net.ifnames=0 biosdevname=0"' \
  --append-line '/etc/ssh/sshd_config:PermitRootLogin yes' \
  --run-command 'update-grub' \
  --firstboot-command 'dpkg-reconfigure openssh-server' \
  --write '/etc/netplan/01-netcfg.yaml:
network:
  version: 2
  renderer: networkd
  ethernets:
    eth0:
      dhcp4: yes
'

これで PermitRootLogin yes になるので root でログインできるはずです。

がしかしSSHでログインしようとするとまた Connection reset とか返されて接続できなくなりました。 どうやら dpkg-reconfigure openssh-server が何かしらの原因で失敗してホスト鍵が作成されなかったようです。

コンソールからログインして dpkg-reconfigure openssh-server してみたところ「/etc/ssh/sshd_config が変更されてるみたいなんやけどどないする?」みたいな TUI のプロンプトが表示されました。たぶんこれが原因でコケたのでしょう。

--frontend noninteractive を付ければプロンプトは表示されなくなるようなので、これを virt-builder に仕込みます。

最終形

virt-builder ubuntu-18.04 \
  --output /var/lib/libvirt/images/ubuntu-18.04.img \
  --arch x86_64 \
  --hostname ubuntu-18.04 \
  --root-password password:password \
  --timezone Asia/Tokyo \
  --append-line '/etc/default/grub:GRUB_CMDLINE_LINUX="console=ttyS0,115200 net.ifnames=0 biosdevname=0"' \
  --append-line '/etc/ssh/sshd_config:PermitRootLogin yes' \
  --run-command 'update-grub' \
  --firstboot-command 'dpkg-reconfigure --frontend noninteractive openssh-server' \
  --write '/etc/netplan/01-netcfg.yaml:
network:
  version: 2
  renderer: networkd
  ethernets:
    eth0:
      dhcp4: yes
'

virt-install \
  --name ubuntu-18.04 \
  --hvm \
  --virt-type kvm \
  --ram 4096 \
  --vcpus 4 \
  --arch x86_64 \
  --os-type linux \
  --os-variant ubuntu18.04 \
  --boot hd \
  --disk path=/var/lib/libvirt/images/ubuntu-18.04.img \
  --network network=default \
  --graphics none \
  --serial pty \
  --console pty \
  --import