- Add CLAUDE.md with project architecture and build documentation - Add verify-image.sh script to validate generated netboot images - Fix boot.ipxe kernel parameters: - Add boot=netboot to invoke custom initramfs script - Add console=tty0 for VGA output alongside serial console - Fix earlyprintk serial specification - Remove dead symlink creation in build-image.sh (http/latest pointed to non-existent directory) The boot=netboot parameter is critical - without it, initramfs falls back to local boot and fails with /dev/root errors. The console changes enable viewing boot messages on monitor instead of only serial port.
6.3 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
This is a netboot system for diskless Ubuntu Noble (24.04) nodes designed for K3s clusters. It builds bootable images (kernel, initramfs, squashfs) that are served via HTTP and loaded using iPXE for network booting.
Boot Flow:
- Machine PXE boots and loads iPXE from network
- iPXE fetches and executes
boot.ipxeconfiguration - iPXE downloads kernel (
vmlinuz) and custom initramfs (initrd-netboot.img) over HTTP - Kernel boots with custom initramfs that downloads the squashfs root filesystem over HTTP
- Root filesystem is mounted as read-only squashfs with writable overlay (tmpfs)
Build Commands
# Build netboot image (15-30 minutes, requires sudo)
make build
# Builds: http/vmlinuz, http/initrd-netboot.img, http/filesystem.squashfs
# Deploy to NAS server
make deploy
# Syncs http/ directory to phoenix:/srv/netboot/http/
# Build and deploy in one step
make all
# Clean build artifacts (unmounts any stray filesystem mounts first)
make clean
# Check NAS connectivity
make check-nas
Configuration:
NAS_HOST=phoenix- target server for deploymentNAS_PATH=/srv/netboot- deployment path on NAS- Edit these in
Makefileif deployment target changes
Architecture
Build System
build-image.sh - Main build script that:
- Creates Ubuntu Noble base system using
debootstrap - Chroots into rootfs and installs packages (kernel, K3s prerequisites, container runtime, tools)
- Configures system (networking via netplan, SSH keys, tmpfs mounts, services)
- Builds custom initramfs using
mkinitramfswith customizations frominitramfs/ - Creates compressed squashfs image of entire rootfs
- Copies artifacts to
images/<VERSION>/andhttp/directories - Sets proper file permissions (644) for HTTP serving
Path handling: All scripts use SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" to work from any location, not just hardcoded paths.
Custom Initramfs
Located in initramfs/ directory, passed to mkinitramfs with -d flag:
- initramfs.conf - Configuration (MODULES=most, COMPRESS=gzip, RESUME=none)
- modules - Extra kernel modules to include (squashfs, overlay, r8125 network driver for 2.5GbE)
- hooks/netboot - Copies binaries into initramfs (wget, curl, unsquashfs, switch_root)
- scripts/netboot - Provides
mountroot()function that:- Parses kernel cmdline for
root=http://...URL andoverlayroot=tmpfs - Configures networking via
configure_networking - Downloads squashfs over HTTP using wget (with retries)
- Validates downloaded file is squashfs
- Mounts squashfs read-only
- If
overlayroot=tmpfs, creates overlay with tmpfs upper layer for writes
- Parses kernel cmdline for
iPXE Boot Configuration
http/boot.ipxe - iPXE script that:
- Loads kernel from
http://192.168.100.1:8800/vmlinuz - Loads initramfs from
http://192.168.100.1:8800/initrd-netboot.img - Sets kernel args:
root=http://192.168.100.1:8800/filesystem.squashfs rootfstype=squashfs overlayroot=tmpfs ip=dhcp console=ttyS0,115200 - Boots the kernel
IMPORTANT: The HTTP server IP (192.168.100.1:8800) is hardcoded in boot.ipxe. Update this if the boot server changes.
System Configuration
Built systems are configured with:
- Norwegian keyboard layout (nb_NO.UTF-8 + en_US.UTF-8 locales)
- Root SSH access with specific authorized keys (see build-image.sh:138-141)
- Password auth disabled, pubkey only
- Network via netplan with DHCP (systemd-networkd)
- Ephemeral tmpfs mounts: /tmp (2G), /var/tmp (1G), /var/log (1G), /run (512M)
- systemd-journald configured for volatile storage (tmpfs, 256M max)
- K3s dependencies: apparmor, iptables, conntrack, containerd, runc
- No hibernation/resume support
Utility Scripts
chroot-rootfs.sh - Enter chroot for manual tweaking
- Mounts proc/sys/dev into existing rootfs
- Cleanup trap unmounts on exit
- Hardcoded path:
/srv/netboot/build/rootfs- update if repo moves
rebuild-squashfs.sh - Rebuild squashfs after manual changes
- Creates new versioned image from existing rootfs
- Skips full debootstrap/package installation
- Hardcoded paths:
/srv/netboot/*- update if repo moves
File Structure
.
├── build-image.sh # Main build script
├── Makefile # Build/deploy automation
├── boot.ipxe # iPXE boot configuration (in http/)
├── initramfs/ # Custom initramfs configuration
│ ├── initramfs.conf # mkinitramfs config
│ ├── modules # Extra kernel modules
│ ├── hooks/netboot # Binary copying hook
│ └── scripts/netboot # HTTP root mounting logic
├── chroot-rootfs.sh # Chroot helper (hardcoded paths)
├── rebuild-squashfs.sh # Rebuild helper (hardcoded paths)
├── build/ # Build artifacts (gitignored)
│ └── rootfs/ # debootstrap rootfs
├── images/ # Versioned builds (gitignored)
│ ├── <YYYYMMDD-HHMM>/ # Timestamped builds
│ └── latest -> <VERSION> # Symlink to latest
└── http/ # HTTP serving directory (gitignored except boot.ipxe)
├── boot.ipxe # iPXE config (tracked)
├── vmlinuz # Kernel (generated)
├── initrd-netboot.img # Custom initramfs (generated)
├── filesystem.squashfs # Root filesystem (generated)
└── version.txt # Build metadata (generated)
Development Notes
Hardcoded paths issue: chroot-rootfs.sh and rebuild-squashfs.sh use hardcoded /srv/netboot/ paths instead of dynamic path detection like build-image.sh. They need updating if repo is cloned elsewhere.
Build requirements:
- Ubuntu/Debian host with debootstrap, mkinitramfs, mksquashfs
- Sudo access for chroot operations and filesystem mounting
- 15-30 minute build time
- ~1GB disk space for build artifacts
SSH key management: Root SSH keys are embedded in build-image.sh:138-141. Update these before building images for new environments.
Network driver: RTL8125 (r8125) driver is explicitly loaded in initramfs for 2.5GbE NICs. If different NICs are used, update initramfs/modules and initramfs/scripts/netboot.