#!/bin/bash # Netboot image builder for diskless K3s nodes # Builds Ubuntu Noble base system with SquashFS set -e # Get the directory where this script is located (works on any machine) SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" BUILD_DIR="$SCRIPT_DIR/build" IMAGE_DIR="$SCRIPT_DIR/images" HTTP_DIR="$SCRIPT_DIR/http" VERSION=$(date +%Y%m%d-%H%M) echo "Building netboot image version $VERSION" # Clean previous build - unmount any stray mounts first if [ -d "$BUILD_DIR/rootfs" ]; then echo "Cleaning up previous build mounts..." mount | grep "$BUILD_DIR/rootfs" | awk '{print $3}' | while read mount; do umount -l "$mount" 2>/dev/null || true done fi rm -rf $BUILD_DIR/rootfs mkdir -p $BUILD_DIR/rootfs # Copy custom initramfs config into rootfs BEFORE debootstrap, so it's available during chroot echo "Setting up custom initramfs configuration..." INITRAMFS_CONFIG="$SCRIPT_DIR/initramfs" if [ ! -d "$INITRAMFS_CONFIG" ]; then echo "ERROR: Custom initramfs config not found at $INITRAMFS_CONFIG" exit 1 fi # These dirs will be created by debootstrap, so we'll copy after that # Create base Ubuntu system echo "Running debootstrap (this will take several minutes)..." debootstrap --arch=amd64 --variant=minbase --components=main,universe,multiverse \ noble $BUILD_DIR/rootfs \ http://archive.ubuntu.com/ubuntu # Chroot and configure cat << 'CHROOT_SCRIPT' > $BUILD_DIR/rootfs/setup.sh #!/bin/bash set -e # Set keyboard layout and encoding to Norwegian UTF-8 (non-interactive) export DEBIAN_FRONTEND=noninteractive export DEBCONF_NONINTERACTIVE_SEEN=true echo "keyboard-configuration keyboard-configuration/layout select Norwegian" | debconf-set-selections echo "keyboard-configuration keyboard-configuration/variant select Norwegian" | debconf-set-selections echo "locales locales/default_environment_locale select en_US.UTF-8" | debconf-set-selections echo "locales locales/locales_to_be_generated multiselect en_US.UTF-8 UTF-8, nb_NO.UTF-8 UTF-8" | debconf-set-selections # Update and upgrade apt-get update apt-get upgrade -y # Install essential packages apt-get install -y \ linux-image-generic \ linux-firmware \ cloud-initramfs-rooturl \ busybox-initramfs \ initramfs-tools \ keyboard-configuration \ systemd \ systemd-sysv \ dbus \ udev \ kmod \ iproute2 \ iputils-ping \ netplan.io \ openssh-server \ curl \ wget \ ca-certificates \ gnupg \ sudo \ locales # K3s prerequisites apt-get install -y \ apparmor \ apparmor-utils \ iptables \ nftables \ conntrack \ socat \ ethtool \ nfs-common # Container runtime prerequisites apt-get install -y \ containerd \ runc # Useful tools apt-get install -y \ htop \ iotop \ vim \ less \ rsync \ git \ squashfs-tools # Clean up apt-get clean rm -rf /var/lib/apt/lists/* rm -rf /tmp/* rm -rf /var/tmp/* # Configure hostname (will be overridden by netplan) echo "k3s-node" > /etc/hostname # Configure network with netplan cat > /etc/netplan/01-netcfg.yaml <> /root/.ssh/authorized_keys <> /etc/fstab < /etc/systemd/journald.conf.d/tmpfs.conf < /etc/locale.gen locale-gen # Build initramfs will be done outside the chroot after mount cleanup echo "Initramfs build will be done after chroot cleanup" CHROOT_SCRIPT # Make script executable and run in chroot with proper mounts chmod +x $BUILD_DIR/rootfs/setup.sh # Mount required filesystems for DKMS compilation mount -t proc proc $BUILD_DIR/rootfs/proc mount -t sysfs sysfs $BUILD_DIR/rootfs/sys mount -t devtmpfs devtmpfs $BUILD_DIR/rootfs/dev mount -t devpts devpts $BUILD_DIR/rootfs/dev/pts # Run setup script in chroot chroot $BUILD_DIR/rootfs /setup.sh # Unmount filesystems umount -l $BUILD_DIR/rootfs/dev/pts umount -l $BUILD_DIR/rootfs/dev umount -l $BUILD_DIR/rootfs/sys umount -l $BUILD_DIR/rootfs/proc rm $BUILD_DIR/rootfs/setup.sh # Copy custom initramfs config into rootfs while /proc is mounted echo "Installing custom initramfs hooks and scripts..." INITRAMFS_CONFIG="$SCRIPT_DIR/initramfs" cp "$INITRAMFS_CONFIG/initramfs.conf" "$BUILD_DIR/rootfs/etc/initramfs-tools/" cp "$INITRAMFS_CONFIG/modules" "$BUILD_DIR/rootfs/etc/initramfs-tools/" cp -r "$INITRAMFS_CONFIG/hooks/"* "$BUILD_DIR/rootfs/usr/share/initramfs-tools/hooks/" cp -r "$INITRAMFS_CONFIG/scripts/"* "$BUILD_DIR/rootfs/usr/share/initramfs-tools/scripts/" # Build initramfs while /proc/sys/dev are still mounted echo "Building custom netboot initramfs..." KERNEL_VERSION=$(ls -1 $BUILD_DIR/rootfs/boot/vmlinuz-* | sed 's|.*/vmlinuz-||' | head -1) chroot $BUILD_DIR/rootfs mkinitramfs -v -o /boot/initrd-netboot.img $KERNEL_VERSION INITRAMFS_OUTPUT="$BUILD_DIR/rootfs/boot/initrd-netboot.img" echo "Initramfs build complete. Size: $(du -h $INITRAMFS_OUTPUT | cut -f1)" # Copy kernel and netboot initramfs mkdir -p $IMAGE_DIR/$VERSION cp $BUILD_DIR/rootfs/boot/vmlinuz-* $IMAGE_DIR/$VERSION/vmlinuz cp $BUILD_DIR/rootfs/boot/initrd-netboot.img $IMAGE_DIR/$VERSION/initrd-netboot.img echo "Creating squashfs image..." mksquashfs $BUILD_DIR/rootfs \ $IMAGE_DIR/$VERSION/filesystem.squashfs \ -comp xz \ -Xbcj x86 \ -b 1M \ -noappend \ -no-progress # Create version info file cat > $IMAGE_DIR/$VERSION/version.txt <