Automating Ubuntu 20.04 installs with Packer
Ubuntu 20.04 — which was released few days ago (23rd April) — brings with it a
new installer, replacing the previous Debian installer with
subiquity
. This means that any of the previous approaches for
automated/unattended installs no longer work and need to be replaced.
No one seemed to have documented doing this successfully yet with Packer, so I set out to figure it out. But first, here’s a working unattended configuration:
ubuntu-2004.json
:
{
"builders": [
{
"name": "ubuntu-2004",
"type": "vmware-iso",
"guest_os_type": "ubuntu-64",
"headless": false,
"iso_url": "http://releases.ubuntu.com/20.04/ubuntu-20.04-live-server-amd64.iso",
"iso_checksum": "caf3fd69c77c439f162e2ba6040e9c320c4ff0d69aad1340a514319a9264df9f",
"iso_checksum_type": "sha256",
"ssh_username": "ubuntu",
"ssh_password": "ubuntu",
"ssh_handshake_attempts": "20",
"http_directory": "http",
"memory": 1024,
"boot_wait": "5s",
"boot_command": [
"<enter><enter><f6><esc><wait> ",
"autoinstall ds=nocloud-net;s=http://{{ .HTTPIP }}:{{ .HTTPPort }}/",
"<enter>"
]
}
],
"provisioners": [
{
"type": "shell",
"inline": ["ls /"]
}
]
}
user-data
:
#cloud-config
autoinstall:
version: 1
identity:
hostname: ubuntu-server
password: '$6$wdAcoXrU039hKYPd$508Qvbe7ObUnxoj15DRCkzC3qO7edjH0VV7BPNRDYK4QR8ofJaEEF2heacn0QgD.f8pO8SNp83XNdWG6tocBM1'
username: ubuntu
network:
network:
version: 2
ethernets:
ens33:
dhcp4: true
dhcp-identifier: mac
ssh:
install-server: true
late-commands:
- sed -i 's/^#*\(send dhcp-client-identifier\).*$/\1 = hardware;/' /target/etc/dhcp/dhclient.conf
- 'sed -i "s/dhcp4: true/&\n dhcp-identifier: mac/" /target/etc/netplan/00-installer-config.yaml'
We also need the presence of the file meta-data
: touch meta-data
in the
directory available to the Packer HTTP server. The password is ubuntu
. Whilst
this uses the VMware builder, the relevant configuration options exist
among the other builders, too.
I’ve also created an example Github repo with the working configuration in.
The new unattended installation is well documented and I started from the Quick Start guide.
There were four things that need solving on top of the basic configuration:
- Ensure that there’s enough memory to run the installer with. 512MB caused a kernel panic, 1GB works fine,
- Install an SSH server,
- Allow the SSH handshake to fail for longer, because the installer has it’s own SSH server which will cause “Waiting for SSH…” to connect to the wrong thing and the build to fail,
- Ensure that we have a persistent IP address after the installation is completed.
The typical way to do this is to restore the DHCP identifier used back to the MAC address of the device, rather than the device identifier which is now common. This is the same problem as I’ve seen previously with Debian Buster (10), and I’ve reused the late command here to set the DHCP client to do that. We also seem to need to do this with netplan too, to reliably get the same IP back that Packer is expecting.
Interestingly, subiquity does not seem to support dhcp-identifier
and
so we need to do this ourselves after the installation is completed. We need to
quote the sed
line, as otherwise we fall into a trap when loading
cloud-init
configuration, as it seems to think it’s YAML.
This took quite a bit of time to get working right. To solve issues along the way, I:
- Used Alt + F2 to get a working console when the installer failed or got stuck,
- Read the output of
/var/log/installer/subiquity-debug.log
to get the network configuration correct, - …and
/var/log/syslog
to debug the YAML parsing issues around thelate-commands
.