Skip to content

Instantly share code, notes, and snippets.

@wpbrown
Created June 15, 2020 22:42
Show Gist options
  • Save wpbrown/b688a934339cb4228c3faf5b527fbe5b to your computer and use it in GitHub Desktop.
Save wpbrown/b688a934339cb4228c3faf5b527fbe5b to your computer and use it in GitHub Desktop.
ubuntu autoinstall with btrfs subvolumes
#cloud-config
autoinstall:
version: 1
identity:
hostname: btrbox
password: "$6$exDY1mhS4KUYCE/2$zmn9ToZwTKLhCw.b4/b.ZRTIZM30JZ4QrOQ2aOXJ8yk96xpcCof0kxKwuX1kqLG/ygbJ1f8wxED22bTL4F46P0"
username: ubuntu
storage:
config:
### drive
- id: disk0
type: disk
ptable: gpt
grub_device: true
preserve: false
wipe: superblock
### partitions
- id: efi_partition
type: partition
size: 512MB
device: disk0
flag: boot
grub_device: true
preserve: false
- id: swap_partition
type: partition
size: 8GB
device: disk0
flag: swap
preserve: false
- id: root_partition
type: partition
size: -1
device: disk0
preserve: false
### format and mount efi partition
- id: efi_format
type: format
fstype: fat32
volume: efi_partition
preserve: false
- id: efi_mount
type: mount
path: /boot/efi
device: efi_format
### format and mount swap partition
- id: swap_format
type: format
fstype: swap
volume: swap_partition
preserve: false
- id: swap_mount
path: none
type: mount
device: swap_format
### format and mount root partition
- id: root_format
type: format
fstype: btrfs
volume: root_partition
preserve: false
- id: root_mount
type: mount
path: /
device: root_format
late-commands:
- |
set -ex
EFI_DEV=$(awk '$2 == "/target/boot/efi" { print $1 }' /proc/mounts)
ROOT_DEV=$(awk '$2 ~ "^/target$" { print $1 }' /proc/mounts)
ROOT_UUID=$(blkid -o value $ROOT_DEV | head -n 1)
awk '$2 ~ "^/target/" { print $2 }' /proc/mounts | xargs umount
btrfs subvolume snapshot /target /target/rootfs
mkdir /mnt/rootfs
mount -o subvol=rootfs $ROOT_DEV /mnt/rootfs
mount $EFI_DEV /mnt/rootfs/boot/efi
mount -o bind /dev /mnt/rootfs/dev
mount -o bind /sys /mnt/rootfs/sys
mount -o bind /proc /mnt/rootfs/proc
sed -i "/$ROOT_UUID/s/defaults/defaults,noatime,subvol=rootfs/" /mnt/rootfs/etc/fstab
chroot /mnt/rootfs update-grub
chroot /mnt/rootfs grub-install --efi-directory=/boot/efi
find /target -mindepth 1 -maxdepth 1 -not -name rootfs -exec rm -rf '{}' \;
btrfs subvolume create /target/home
echo "/dev/disk/by-uuid/$ROOT_UUID /home btrfs defaults,noatime,subvol=home 0 0" >> /mnt/rootfs/etc/fstab
@bashadude
Copy link

bashadude commented Mar 10, 2023

Hi @wpbrown

I have trailed this code for ubuntu 22.04.2 jammy. I got this error can you please suggest me what next?

image

In crash file content is below
First 50 lines
image
last 100 lines
image

Thanks in advance @wpbrown

@IguanaBob
Copy link

IguanaBob commented Aug 13, 2024

Hi @wpbrown

I have trailed this code for ubuntu 22.04.2 jammy. I got this error can you please suggest me what next?

IMAGE

I faced this in writing my autoinstall for a laptop. After /var/log is moved to a subvolume and removed from /target/ the final step of copying install logs fails. You can fix this by adding this to the end of your autoinstall late commands:

umount /target/ && mkdir -p /target/var/log/ && mount -o subvol=@var_log $ROOT_DEV /target/var/log/ #needed for install logs

You may need to modify depending on if your have /var/log, /var, or both as subvolumes.

I went a little overboard with mine. Here is what I am currently testing on server 24.04.

#cloud-config
autoinstall:
  version: 1

  refresh-installer:
    update: true

  source:
    id: ubuntu-server-minimal
    search_drivers: true

  drivers:
    install: true

  oem:
    install: true

  kernel:
    flavor: hwe

  updates: all

  locale: en_US.UTF-8
  keyboard:
    layout: us
  timezone: America/Chicago

  identity:
    realname: REDACTED
    username: REDACTED
    password:  REDACTED
    hostname: REDACTED

  ssh:
    install-server: true
    allow-pw: true
    authorized-keys: []

  packages:
    - pv
    - git
    - pigz
    - vim
    - btop
    - btrbk
    - btrfs-compsize

  storage:
    config:
      - id: disk0
        type: disk
        ptable: gpt
        wipe: superblock-recursive
        match:
          size: largest

      - id: efi
        type: partition
        size: 1G
        device: disk0
        flag: boot
        wipe: superblock
        grub_device: true

      - id: boot
        type: partition
        size: 2G
        device: disk0
        wipe: superblock

      - id: pvpart
        type: partition
        device: disk0
        size: -1
        wipe: superblock

      - id: pvpart-crypt
        type: dm_crypt
        volume: pvpart
        key: "REDACTED"

      - id: vg0
        type: lvm_volgroup
        name: vg0
        devices:
          - pvpart-crypt

      - id: swap_lv
        type: lvm_partition
        name: swap_lv
        volgroup: vg0
        size: 6G

      - id: root_lv
        type: lvm_partition
        name: root_lv
        volgroup: vg0
        size: -1

      - id: efipart_fs
        type: format
        volume: efi
        fstype: fat32

      - id: bootpart_fs
        type: format
        volume: boot
        fstype: ext4

      - id: root_lv_fs
        type: format
        volume: root_lv
        fstype: btrfs

      - id: swap-fs
        type: format
        volume: swap_lv
        fstype: swap

      - id: efi-mount
        type: mount
        path: /boot/efi
        device: efipart_fs
        options: noatime,nodiratime

      - id: boot-mount
        type: mount
        path: /boot
        device: bootpart_fs
        options: noatime,nodiratime

      - id: swap-mount
        type: mount
        path: none
        device: swap-fs

      - id: root-mount
        type: mount
        path: /
        device: root_lv_fs
        options: compress-force=zstd:15,ssd,noatime,nodiratime  #compress maximum during install, will be set sanely in fstab

  late-commands:
  - |
    set -ex
    
    ### BTRFS Subvolumes
    #BOOT_DEV=$(awk '$2 == "/target/boot" { print $1 }' /proc/mounts)
    BOOT_DEV=/dev/sda2
    #EFI_DEV=$(awk '$2 == "/target/boot/efi" { print $1 }' /proc/mounts)
    EFI_DEV=/dev/sda1
    #ROOT_DEV=$(awk '$2 ~ "^/target$" { print $1 }' /proc/mounts)
    ROOT_DEV=/dev/mapper/vg0-root_lv
    ROOT_UUID=$(blkid -o value $ROOT_DEV | head -n 1)
    #awk '$2 ~ "^/target/" { print $2 }' /proc/mounts | xargs umount || sleep 5 && awk '$2 ~ "^/target/" { print $2 }' /proc/mounts
    sleep 10 || (exit 0)
    umount /target/boot/efi || ( sleep 5 && umount /target/boot/efi || sleep 5 && ( umount -l /target/boot/efi || exit 0 ))
    umount /target/boot || ( sleep 5 && umount /target/boot || sleep 5 && ( umount -l /target/boot || exit 0 ))
    umount /target/cdrom || ( sleep 5 && umount /target/cdrom || sleep 5 && ( umount -l /target/cdrom || exit 0 ))
    btrfs subvolume snapshot /target /target/@   #OS
    mkdir /mnt/rootfs
    mount -o subvol=@ $ROOT_DEV /mnt/rootfs
    mount $BOOT_DEV /mnt/rootfs/boot
    mount $EFI_DEV /mnt/rootfs/boot/efi
    mount -o bind /dev  /mnt/rootfs/dev
    mount -o bind /sys  /mnt/rootfs/sys
    mount -o bind /proc /mnt/rootfs/proc
    sed -i "/$ROOT_UUID/s/compress=zstd:15/subvol=@,compress=zstd:3/" /mnt/rootfs/etc/fstab
    chroot /mnt/rootfs update-grub
    chroot /mnt/rootfs grub-install --efi-directory=/boot/efi
    find /target -mindepth 1 -maxdepth 1 -not -name '@' -exec rm -rf '{}' \;
    btrfs subvolume create /target/@home   #data
    btrfs subvolume create /target/@opt   #data
    btrfs subvolume create /target/@var_opt   #data
    btrfs subvolume create /target/@srv   #data
    btrfs subvolume create /target/@var   #data, nocow?
    btrfs subvolume create /target/@var_spool   #data
    btrfs subvolume create /target/@var_mail   #data
    btrfs subvolume create /target/@var_cache   #cache, do no backup, nocow
    btrfs subvolume create /target/@var_log   #logs, backup?, nocow?
    btrfs subvolume create /target/@var_snap   #data
    btrfs subvolume create /target/@usr_local   #data
    
    ### NoDataCow
    chattr +C /target/@var_cache

    ### Subvolumes 
    mv /mnt/rootfs/home/* /target/@home/ || (exit 0)
    mount -o subvol=@home $ROOT_DEV /mnt/rootfs/home || (exit 0)
    mv /mnt/rootfs/var/cache/* /target/@var_cache/ || (exit 0)
    mv /mnt/rootfs/var/opt/* /target/@var_opt/ || (exit 0)
    mv /mnt/rootfs/var/spool/* /target/@var_spool/ || (exit 0)
    mv /mnt/rootfs/var/mail/* /target/@var_mail/ || (exit 0)
    mv /mnt/rootfs/var/log/* /target/@var_log/ || (exit 0)
    mv /mnt/rootfs/var/snap/* /target/@var_snap/ || (exit 0)
    mv /mnt/rootfs/var/* /target/@var/ || (exit 0)
    mount -o subvol=@var $ROOT_DEV /mnt/rootfs/var/ || (exit 0)
    mount -o subvol=@var_cache $ROOT_DEV /mnt/rootfs/var/cache || (exit 0)
    mount -o subvol=@var_spool $ROOT_DEV /mnt/rootfs/var/spool || (exit 0)
    mount -o subvol=@var_log $ROOT_DEV /mnt/rootfs/var/log || (exit 0)
    mount -o subvol=@var_mail $ROOT_DEV /mnt/rootfs/var/mail || (exit 0)
    mount -o subvol=@var_opt $ROOT_DEV /mnt/rootfs/var/opt || (exit 0)
    mount -o subvol=@var_snap $ROOT_DEV /mnt/rootfs/var/snap || (exit 0)

    echo "/dev/disk/by-uuid/$ROOT_UUID /home btrfs noatime,nodiratime,subvol=@home 0 0" >> /mnt/rootfs/etc/fstab
    echo "/dev/disk/by-uuid/$ROOT_UUID /var btrfs noatime,nodiratime,subvol=@var 0 0" >> /mnt/rootfs/etc/fstab
    echo "/dev/disk/by-uuid/$ROOT_UUID /var/opt btrfs noatime,nodiratime,subvol=@var_opt 0 0" >> /mnt/rootfs/etc/fstab
    echo "/dev/disk/by-uuid/$ROOT_UUID /var/spool btrfs noatime,nodiratime,subvol=@var_spool 0 0" >> /mnt/rootfs/etc/fstab
    echo "/dev/disk/by-uuid/$ROOT_UUID /var/mail btrfs noatime,nodiratime,subvol=@var_mail 0 0" >> /mnt/rootfs/etc/fstab
    echo "/dev/disk/by-uuid/$ROOT_UUID /var/cache btrfs noatime,nodiratime,subvol=@var_cache 0 0" >> /mnt/rootfs/etc/fstab
    echo "/dev/disk/by-uuid/$ROOT_UUID /var/mail btrfs noatime,nodiratime,subvol=@var_mail 0 0" >> /mnt/rootfs/etc/fstab
    echo "/dev/disk/by-uuid/$ROOT_UUID /var/snap btrfs noatime,nodiratime,subvol=@var_snap 0 0" >> /mnt/rootfs/etc/fstab
    echo "/dev/disk/by-uuid/$ROOT_UUID /opt btrfs noatime,nodiratime,subvol=@opt 0 0" >> /mnt/rootfs/etc/fstab
    echo "/dev/disk/by-uuid/$ROOT_UUID /srv btrfs noatime,nodiratime,subvol=@srv 0 0" >> /mnt/rootfs/etc/fstab
    echo "/dev/disk/by-uuid/$ROOT_UUID /usr/local btrfs noatime,nodiratime,subvol=@usr_local 0 0" >> /mnt/rootfs/etc/fstab
    
    ### Tweaks
    ln -s ../../bin/pigz /mnt/rootfs/usr/local/bin/gzip || (exit 0)
    
    ### journald limits
    echo "SystemMaxUse=1G" >> /mnt/rootfs/systemd/journald.conf || (exit 0)
    echo "RuntimeMaxUse=200M" >> /mnt/rootfs/systemd/journald.conf || (exit 0)
    
    ### Aliases
    echo "alias cp='cp --reflink=auto'" >> /mnt/rootfs/root/.bash_aliases || (exit 0)
    echo "alias cp='cp --reflink=auto'" >> /mnt/rootfs/etc/skel/.bash_aliases || (exit 0)
    echo "alias cp='cp --reflink=auto'" >> /mnt/rootfs/home/jon/.bash_aliases || (exit 0)
    chroot /mnt/rootfs chown USERNAME: /home/USERNAME/.bash_aliases || (exit 0)
    
    ### Disable unwanted services
    ln -s /dev/null /mnt/rootfs/etc/systemd/system/ModemManager || (exit 0)
    ln -s /dev/null /mnt/rootfs/etc/systemd/system/systemd-networkd-wait-online.service || (exit 0)
    
    ### Remove cloud-init
    touch /mnt/rootfs/etc/cloud/cloud-init.disabled || (exit 0)
    chroot /mnt/rootfs apt purge cloud-init || (exit 0)
    rm -rf /mnt/rootfs/etc/cloud /mnt/rootfs/var/lib/cloud || (exit 0)
    
    ### Disable ubuntu-advantage & ESM nags
    ln -s /dev/null /mnt/rootfs/etc/systemd/system/ua-messaging.timer || (exit 0)
    ln -s /dev/null /mnt/rootfs/etc/systemd/system/ua-messaging.service || (exit 0)
    ln -s /dev/null /mnt/rootfs/etc/systemd/system/ua-timer.timer || (exit 0)
    rm -f /mnt/rootfs/etc/apt/apt.conf.d/20apt-esm-hook.conf || (exit 0)
    truncate -s 0 /mnt/rootfs/etc/ubuntu-advantage/help_data.yaml || (exit 0)
    truncate -s 0 /mnt/rootfs/etc/update-motd.d/50-motd-news || (exit 0)
    truncate -s 0 /mnt/rootfs/etc/update-motd.d/88-esm-announce || (exit 0)
    truncate -s 0 /mnt/rootfs/etc/update-motd.d/91-contract-ua-esm-status || (exit 0)
    ln -s /dev/null /mnt/rootfs/etc/systemd/system/esm-cache.service || (exit 0)
    ln -s /dev/null /mnt/rootfs/etc/systemd/system/reboot-cmds.service || (exit 0)
    ln -s /dev/null /mnt/rootfs/etc/systemd/system/apt-news.service || (exit 0)
    touch /mnt/rootfs/root/.hushlogin || (exit 0)
    touch /mnt/rootfs/etc/skel/.hushlogin || (exit 0)
    touch /mnt/rootfs/home/jon/.hushlogin || (exit 0)
    chroot /mnt/rootfs chown jon: /home/jon/.hushlogin || (exit 0)
    
    ### Cleanup
    chroot /mnt/rootfs apt autoremove || (exit 0)
    umount /target/ && mkdir -p /target/var/log/ && mount -o subvol=@var_log $ROOT_DEV /target/var/log/   #needed for install logs
    fstrim -v /mnt/rootfs || (exit 0)
       
    reboot

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment