The exact steps you took are a bit hard to follow. Therefore, I've outlined the steps below that I use to create a new ISO configured with autoinstall.
Some observations first:
- Your
grub.cfg file does not match mine exactly, but I was successful with yours
- Your
install-sources.yaml file does not match. But I don't see a problem here. I just kept mine simple.
- Your
user-data file is slightly different than mine. I have timezone: Asia/Kolkata indented within another user-data directive. But testing shows it works both ways. Also, you're running a late-command to install cloud-init, but if you're un-squashing the Desktop squashfs and installing cloud-init within the chroot, then you don't need to run this late command during autoinstall; it's redundant.
Some notes:
- We're downloading both the Server and Desktop ISO's for Ubuntu 22.04.5
- The full Server ISO is extracted
- Only the
/casper/ directory is extracted from the Desktop ISO
- The Desktop
filesystem.squashfs is un-squashed, chrooted, modified, re-squashed, and copied to the extracted server ISO
- Necessary files are created for autoinstall in the extracted server directory
grub.cfg and install-sources.yaml are modified within the extracted server directory
- The extracted server directory is re-packed into a new ISO
- This process adds the squashfs filesystem from the Ubuntu Desktop ISO to the Server ISO instead of installing the
ubuntu-desktop package into the Server installation. With this technique, Subiquity from the Server ISO is used for installation.
Within a working directory, make the following directories:
$ mkdir server-iso-extracted desktop-iso-extracted tmp
Download ISO files:
wget https://nl3.releases.ubuntu.com/releases/releases/releases/releases/22.04/ubuntu-22.04.5-live-server-amd64.iso
wget https://nl3.releases.ubuntu.com/releases/releases/releases/releases/22.04/ubuntu-22.04.5-desktop-amd64.iso
Current working directory structure:
$ tree -L 1
.
├── desktop-iso-extracted
├── server-iso-extracted
├── tmp
├── ubuntu-22.04.5-desktop-amd64.iso
└── ubuntu-22.04.5-live-server-amd64.iso
Unpack the ISO's. For the Desktop ISO, you only need the /casper/ directory.
xorriso -osirrox on -indev ubuntu-22.04.5-live-server-amd64.iso -extract / ./server-iso-extracted/
xorriso -osirrox on -indev ubuntu-22.04.5-desktop-amd64.iso -extract /casper/ ./desktop-iso-extracted/
Copy Desktop filesystem.squashfs to tmp directory:
cp desktop-iso-extracted/filesystem.squashfs ./tmp/
Unsquash desktop-iso-extracted/casper/filesystem.squashfs from Desktop ISO:
sudo unsquashfs -n -d tmp/squashfs-root tmp/filesystem.squashfs
Create chroot:
sudo mount --bind /etc/resolv.conf tmp/squashfs-root/etc/resolv.conf
sudo mount -t proc none tmp/squashfs-root/proc
sudo mount -t sysfs none tmp/squashfs-root/sys
sudo mount -t devpts none tmp/squashfs-root/dev/pts
sudo chroot tmp/squashfs-root/
Modify Desktop filesystem. Upgrade and install cloud-init:
apt update
apt install cloud-init
# install any other applications as well
Exit chroot:
exit
sudo umount tmp/squashfs-root/proc
sudo umount tmp/squashfs-root/sys
sudo umount tmp/squashfs-root/dev/pts
sudo umount tmp/squashfs-root/etc/resolv.conf
Create a new modified squashfs:
sudo mksquashfs tmp/squashfs-root/ tmp/modified_filesystem.squashfs -comp xz
Copy modified squashfs to server-iso-extracted/casper/filesystem.squashfs:
sudo cp tmp/modified_filesystem.squashfs server-iso-extracted/casper/filesystem.squashfs
Create a server-iso-extracted/nocloud directory:
mkdir server-iso-extracted/nocloud
Create a meta-data file:
touch server-iso-extracted/nocloud/meta-data
Create a server-iso-extracted/nocloud/user-data file with the following contents:
#cloud-config
autoinstall:
version: 1
# The following credentials will create a default user. username: ubuntu - password: ubuntu
identity:
hostname: ubuntu-desktop
password: $6$5lpwCLsKLEzMkSJc$keOAhA6aO/5RocGThmhVA7LSNuW911Rx5HHXFEa75oGK20cEdAAgn14H5f5nGeq6QgcSyLPrWcg1.JvjXbhrN/
realname: Ubuntu user
username: ubuntu
user-data:
timezone: America/Los_Angeles
# Let NetworkManager manage all devices on this system
network:
version: 2
renderer: NetworkManager
refresh-installer:
update: no
keyboard:
layout: us
toggle: null
variant: ''
locale: en_US.UTF-8
# cloud-init is not installed by default in the Desktop ISO. Therefore, it either needs to be installed within the ISO or installed with the following lines:
# late-commands:
# - curtin in-target --target=/target -- apt install -y cloud-init
Give write permissions to server-iso-extracted/boot/grub/grub.cfg:
chmod +w server-iso-extracted/boot/grub/grub.cfg
Modify server-iso-extracted/boot/grub/grub.cfg as follows:
set timeout=30
loadfont unicode
set menu_color_normal=white/black
set menu_color_highlight=black/light-gray
menuentry "Try or Install Ubuntu Server" {
set gfxpayload=keep
linux /casper/vmlinuz autoinstall ds=nocloud;s=/cdrom/nocloud/ ---
initrd /casper/initrd
}
menuentry "Ubuntu Server with the HWE kernel" {
set gfxpayload=keep
linux /casper/hwe-vmlinuz ---
initrd /casper/hwe-initrd
}
grub_platform
if [ "$grub_platform" = "efi" ]; then
menuentry 'Boot from next volume' {
exit 1
}
menuentry 'UEFI Firmware Settings' {
fwsetup
}
else
menuentry 'Test memory' {
linux16 /boot/memtest86+.bin
}
fi
Give write permissions to server-iso-extracted/casper/install-sources.yaml:
chmod +w server-iso-extracted/casper/install-sources.yaml
Update server-iso-extracted/casper/install-sources.yaml as follows:
- description:
en: This version installs a Desktop environment
where humans are not expected to log in.
id: desktop
locale_support: none
name:
en: Ubuntu Desktop
path: filesystem.squashfs
size: 568651776
type: fsimage
variant: server
default: true
Reconstruct checksums:
cd server-iso-extracted
chmod +w md5sum.txt
find ./dists ./.disk ./pool ./casper ./boot -type f -print0 | xargs -0 md5sum > md5sum.txt
cd ..
Make new ISO file:
Create a script in your working directory called makeiso.sh with the following contents:
#!/bin/bash
#Parameters found with 'xorriso -indev ubuntu-22.04.3-live-server-amd64.iso -report_el_torito as_mkisofs'
xorriso joliet on -as mkisofs \
-V 'Ubuntu 22.04 Autoinstaller' \
--modification-date="2024111907040900" \
--grub2-mbr --interval:local_fs:0s-15s:zero_mbrpt,zero_gpt:'ubuntu-22.04.5-live-server-amd64.iso' \
--protective-msdos-label \
-partition_cyl_align off \
-partition_offset 16 \
--mbr-force-bootable \
-append_partition 2 28732ac11ff8d211ba4b00a0c93ec93b --interval:local_fs:4162948d-4173019d::'ubuntu-22.04.5-live-server-amd64.iso' \
-appended_part_as_gpt \
-iso_mbr_part_type a2a0d0ebe5b9334487c068b6b72699c7 \
-c '/boot.catalog' \
-b '/boot/grub/i386-pc/eltorito.img' \
-no-emul-boot \
-boot-load-size 4 \
-boot-info-table \
--grub2-boot-info \
-eltorito-alt-boot \
-e '--interval:appended_partition_2_start_1040737s_size_10072d:all::' \
-no-emul-boot \
-boot-load-size 10072 \
-o ubuntu-22.04.5-autoinstall-amd64.iso \
server-iso-extracted
Then run the script with source makeiso.sh to make the new ISO.
When I'm all done, the working directory structure looks like this:
$ tree -L 3
.
├── desktop-iso-extracted
│ ├── filesystem.manifest
│ ├── filesystem.manifest-minimal-remove
│ ├── filesystem.manifest-remove
│ ├── filesystem.size
│ ├── filesystem.squashfs
│ ├── filesystem.squashfs.gpg
│ ├── initrd
│ └── vmlinuz
├── makeiso.sh
├── server-iso-extracted
│ ├── boot
│ │ ├── grub
│ │ └── memtest86+.bin
│ ├── boot.catalog
│ ├── casper
│ │ ├── filesystem.manifest
│ │ ├── filesystem.size
│ │ ├── filesystem.squashfs
│ │ ├── hwe-initrd
│ │ ├── hwe-vmlinuz
│ │ ├── initrd
│ │ ├── install-sources.yaml
│ │ ├── ubuntu-server-minimal.manifest
│ │ ├── ubuntu-server-minimal.size
│ │ ├── ubuntu-server-minimal.squashfs
│ │ ├── ubuntu-server-minimal.squashfs.gpg
│ │ ├── ubuntu-server-minimal.ubuntu-server.installer.generic-hwe.manifest
│ │ ├── ubuntu-server-minimal.ubuntu-server.installer.generic-hwe.size
│ │ ├── ubuntu-server-minimal.ubuntu-server.installer.generic-hwe.squashfs
│ │ ├── ubuntu-server-minimal.ubuntu-server.installer.generic-hwe.squashfs.gpg
│ │ ├── ubuntu-server-minimal.ubuntu-server.installer.generic.manifest
│ │ ├── ubuntu-server-minimal.ubuntu-server.installer.generic.size
│ │ ├── ubuntu-server-minimal.ubuntu-server.installer.generic.squashfs
│ │ ├── ubuntu-server-minimal.ubuntu-server.installer.generic.squashfs.gpg
│ │ ├── ubuntu-server-minimal.ubuntu-server.installer.manifest
│ │ ├── ubuntu-server-minimal.ubuntu-server.installer.size
│ │ ├── ubuntu-server-minimal.ubuntu-server.installer.squashfs
│ │ ├── ubuntu-server-minimal.ubuntu-server.installer.squashfs.gpg
│ │ ├── ubuntu-server-minimal.ubuntu-server.manifest
│ │ ├── ubuntu-server-minimal.ubuntu-server.size
│ │ ├── ubuntu-server-minimal.ubuntu-server.squashfs
│ │ ├── ubuntu-server-minimal.ubuntu-server.squashfs.gpg
│ │ └── vmlinuz
│ ├── dists
│ │ ├── jammy
│ │ ├── stable -> jammy
│ │ └── unstable -> jammy
│ ├── EFI
│ │ └── boot
│ ├── install
│ ├── md5sum.txt
│ ├── nocloud
│ │ ├── meta-data
│ │ └── user-data
│ ├── pool
│ │ ├── main
│ │ └── restricted
│ └── ubuntu -> .
├── tmp
│ ├── filesystem.squashfs
│ ├── modified_filesystem.squashfs
│ └── squashfs-root
│ ├── bin -> usr/bin
│ ├── boot
│ ├── dev
│ ├── etc
│ ├── home
│ ├── lib -> usr/lib
│ ├── lib32 -> usr/lib32
│ ├── lib64 -> usr/lib64
│ ├── libx32 -> usr/libx32
│ ├── media
│ ├── mnt
│ ├── opt
│ ├── proc
│ ├── root
│ ├── run
│ ├── sbin -> usr/sbin
│ ├── snap
│ ├── srv
│ ├── sys
│ ├── tmp
│ ├── usr
│ └── var
├── ubuntu-22.04.5-autoinstall-amd64.iso
├── ubuntu-22.04.5-desktop-amd64.iso
└── ubuntu-22.04.5-live-server-amd64.iso
From here, the ISO can be used to install. With autoinstall configured, you won't be prompted during the installation process.
Update:
Regarding the install-sources.yaml file, you can have multiple entries. By default, autoinstall will select the entry that has the default: true key/value.
Looking at the Subiquity source code repository, documentation for Autoinstall configuration reference manual defines a top-level source key. Under source, two more keys can be defined, search-drivers and id. By default, search-drivers is true and id is blank, which means that autoinstall will search the install-sources.yaml file for an entry with a default: true key/value and will then choose this as the source to install. Alternatively, you can define id in your autoinstall config, which tells autoinstall to search install-sources.yaml for an entry with a matching id. It will then install that source.
source
- type: mapping, see below
- default: see below
- can be interactive: true
search_drivers
- type: boolean
- default:
true (mostly, see below)
Whether the installer searches for available third-party drivers. When
set to false, it disables the drivers :ref:screen and section<ai-drivers>.
The default is true for most installations, and false when a
"core boot" or "enhanced secure boot" method is selected (where
third-party drivers cannot be currently installed).
id
- type: string
- default: the default value as listed in install-sources
Identifier of the source to install (e.g., ubuntu-server-minimal).
The correct ID to use is specific to a given installation ISO. As this
ID may change over time, the canonical place to look for this
information is the installation ISO itself, in the
casper/install-sources.yaml file where the value to use is the
id.
Source examples:
autoinstall:
# default behaviour
source:
search_drivers: true
id: <the installation source marked as default in install-sources.yaml>
autoinstall:
on the Ubuntu Server ISO, install with the minimal source
source:
id: ubuntu-server-minimal
autoinstall:
on the Ubuntu Desktop ISO, install with the standard source
source:
id: ubuntu-desktop
As for defining the size of the squashfs in install-sources.yaml, the Subiquity source code states that it's used in determining the amount of space needed when formatting the disk. So yes, the more accurate this is the better.
# Factors for suggested minimum install size:
# 1) Source minimum - The minimum reported as part of source selection. This
# is absolute bare minimum information to get bits on the disk and doesn’t
# factor in filesystem overhead. Obtained from the size value of the
# chosen source as found at /casper/install-sources.yaml.
# 2) Room for boot - we employ a scaling system to help select the recommended
# size of a dedicated /boot and/or efi system partition (see above). If
# /boot is not actually a separate partition, this space needs to be
# accounted for as part of the planned rootfs size.
# 3) room for esp - similar to boot. Included in all calculations, even if
# we're not UEFI boot.
# 4) Room to grow - while meaningful work can sometimes be possible on a full
# disk, it’s not the sort of thing to suggest in a guided install.
# Suggest for room to grow max(2GiB, 50% of source minimum).
def calculate_suggested_install_min(source_min: int, part_align: int = MiB) -> int:
room_for_boot = bootfs_scale.minimum
room_for_esp = uefi_scale.minimum
room_to_grow = max(2 * GiB, math.ceil(0.5 * source_min))
total = source_min + room_for_boot + room_for_esp + room_to_grow
return align_up(total, part_align)