Files
netboot/CLAUDE.md
Torbjørn Lindahl b7a52c0c37 Switch to HWE kernel and improve boot reliability
- Install linux-image-generic-hwe-24.04 (6.14+) for RTL8125BP XID 689 support
- Enable noble-updates and noble-security repositories in chroot
- Add explicit rdinit=/init and panic=-1 kernel parameters for boot robustness
- Rename CLAUDE.md to AGENTS.md for broader AI assistant coverage
- Document dracut module alternative and verify-image.sh utility
- Clean up initramfs netboot script comments
2026-02-01 15:51:19 +01:00

7.5 KiB

AGENTS.md

This file provides guidance to AI coding assistants 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:

  1. Machine PXE boots and loads iPXE from network
  2. iPXE fetches and executes boot.ipxe configuration
  3. iPXE downloads kernel (vmlinuz) and custom initramfs (initrd-netboot.img) over HTTP
  4. Kernel boots with custom initramfs that downloads the squashfs root filesystem over HTTP
  5. 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 deployment
  • NAS_PATH=/srv/netboot - deployment path on NAS
  • Edit these in Makefile if deployment target changes

Architecture

Build System

build-image.sh - Main build script that:

  1. Creates Ubuntu Noble base system using debootstrap
  2. Chroots into rootfs and installs packages (kernel, K3s prerequisites, container runtime, tools)
  3. Configures system (networking via netplan, SSH keys, tmpfs mounts, services)
  4. Builds custom initramfs using mkinitramfs with customizations from initramfs/
  5. Creates compressed squashfs image of entire rootfs
  6. Copies artifacts to images/<VERSION>/ and http/ directories
  7. 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 and overlayroot=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

Dracut Module (Alternative)

Located in dracut-module/90netboot/, an alternative initramfs approach using dracut:

  • module-setup.sh - Dracut module setup and dependencies
  • parse-netboot.sh - Parses kernel command line for netboot parameters
  • mount-netboot.sh - Handles HTTP squashfs download and mounting

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: boot=netboot root=http://192.168.100.1:8800/filesystem.squashfs rootfstype=squashfs overlayroot=tmpfs ip=dhcp console=tty0 console=ttyS0,115200 earlyprintk=serial,ttyS0,115200 loglevel=7
  • 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 around line 160)
  • 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

verify-image.sh - Validate built image completeness

  • Checks all required files exist (vmlinuz, initrd, squashfs, boot.ipxe)
  • Validates file types (kernel, cpio archive, squashfs)
  • Verifies file permissions (644 for HTTP serving)
  • Inspects initramfs for custom netboot script and required binaries
  • Checks squashfs for critical directories and configurations
  • Validates iPXE configuration references correct files
  • Run with ./verify-image.sh after make build

File Structure

.
├── build-image.sh          # Main build script
├── Makefile                # Build/deploy automation
├── verify-image.sh         # Image validation script
├── chroot-rootfs.sh        # Chroot helper (hardcoded paths)
├── rebuild-squashfs.sh     # Rebuild helper (hardcoded paths)
├── AGENTS.md               # AI assistant guidance (this file)
├── CLAUDE.md               # Claude-specific guidance
├── initramfs/              # Custom initramfs configuration (mkinitramfs)
│   ├── initramfs.conf      # mkinitramfs config
│   ├── modules             # Extra kernel modules
│   ├── hooks/netboot       # Binary copying hook
│   └── scripts/netboot     # HTTP root mounting logic
├── dracut-module/          # Alternative initramfs (dracut)
│   └── 90netboot/
│       ├── module-setup.sh
│       ├── parse-netboot.sh
│       └── mount-netboot.sh
├── 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 around line 160. 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.