Add netboot infrastructure: custom initramfs hooks, build scripts, iPXE configuration
This commit is contained in:
11
.gitignore
vendored
Normal file
11
.gitignore
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# Build artifacts
|
||||||
|
build/
|
||||||
|
images/
|
||||||
|
*.img
|
||||||
|
filesystem.squashfs
|
||||||
|
version.txt
|
||||||
|
latest
|
||||||
|
|
||||||
|
# OS files
|
||||||
|
.DS_Store
|
||||||
|
*~
|
||||||
10
http/boot.ipxe
Normal file
10
http/boot.ipxe
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#!ipxe
|
||||||
|
echo Booting Ubuntu Noble K3s Node via iPXE
|
||||||
|
echo Loading kernel from http://192.168.100.1:8800/vmlinuz
|
||||||
|
kernel --name vmlinuz http://192.168.100.1:8800/vmlinuz
|
||||||
|
echo Loading initramfs from http://192.168.100.1:8800/initrd-netboot.img
|
||||||
|
initrd --name initrd http://192.168.100.1:8800/initrd-netboot.img
|
||||||
|
echo Setting kernel arguments for HTTP root mounting
|
||||||
|
imgargs vmlinuz root=http://192.168.100.1:8800/filesystem.squashfs rootfstype=squashfs overlayroot=tmpfs ip=dhcp console=ttyS0,115200 earlyprintk=ttyS0,115200 loglevel=7
|
||||||
|
echo Booting system...
|
||||||
|
boot vmlinuz
|
||||||
38
initramfs/hooks/netboot
Executable file
38
initramfs/hooks/netboot
Executable file
@@ -0,0 +1,38 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# Add useful binaries to initrd for netboot HTTP root mounting
|
||||||
|
#
|
||||||
|
|
||||||
|
if [ "$1" = "prereqs" ]; then
|
||||||
|
echo "udev"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
. /usr/share/initramfs-tools/hook-functions
|
||||||
|
|
||||||
|
# Essential utilities for netboot - copy_exec handles dependencies automatically
|
||||||
|
copy_exec "/usr/bin/wget"
|
||||||
|
copy_exec "/usr/bin/curl"
|
||||||
|
copy_exec "/usr/bin/unsquashfs"
|
||||||
|
copy_exec "/usr/sbin/switch_root"
|
||||||
|
|
||||||
|
# Useful tools for debugging
|
||||||
|
copy_exec "/usr/bin/awk"
|
||||||
|
copy_exec "/usr/bin/bash"
|
||||||
|
copy_exec "/usr/bin/chmod"
|
||||||
|
copy_exec "/usr/bin/file"
|
||||||
|
copy_exec "/usr/bin/free"
|
||||||
|
copy_exec "/usr/bin/grep"
|
||||||
|
copy_exec "/usr/bin/gunzip"
|
||||||
|
copy_exec "/usr/bin/gzip"
|
||||||
|
copy_exec "/usr/bin/less"
|
||||||
|
copy_exec "/usr/bin/lsblk"
|
||||||
|
copy_exec "/usr/bin/mount"
|
||||||
|
copy_exec "/usr/bin/readlink"
|
||||||
|
copy_exec "/usr/bin/sed"
|
||||||
|
copy_exec "/usr/bin/timeout"
|
||||||
|
copy_exec "/usr/bin/touch"
|
||||||
|
copy_exec "/usr/bin/vi"
|
||||||
|
|
||||||
|
# Note: copy_exec automatically handles all shared library dependencies via ldd()
|
||||||
|
# No need to manually copy libc or other libraries - copy_exec handles this
|
||||||
70
initramfs/initramfs.conf
Normal file
70
initramfs/initramfs.conf
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
#
|
||||||
|
# initramfs.conf
|
||||||
|
# Configuration file for mkinitramfs(8). See initramfs.conf(5).
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# MODULES: [ most | netboot | dep | list ]
|
||||||
|
#
|
||||||
|
# most - Add most filesystem and all harddrive drivers.
|
||||||
|
#
|
||||||
|
# dep - Try and guess which modules to load.
|
||||||
|
#
|
||||||
|
# netboot - Add the base modules, network modules, but skip block devices.
|
||||||
|
#
|
||||||
|
# list - Only include modules from the 'additional modules' list
|
||||||
|
#
|
||||||
|
|
||||||
|
MODULES=most
|
||||||
|
|
||||||
|
#
|
||||||
|
# BUSYBOX: [ y | n | auto ]
|
||||||
|
#
|
||||||
|
# Use busybox shell and utilities. If set to n, klibc utilities will be used.
|
||||||
|
# If set to auto (or unset), busybox will be used if installed and klibc will
|
||||||
|
# be used otherwise.
|
||||||
|
#
|
||||||
|
|
||||||
|
BUSYBOX=auto
|
||||||
|
|
||||||
|
#
|
||||||
|
# COMPRESS: [ gzip | bzip2 | lz4 | lzma | lzop | xz | zstd ]
|
||||||
|
#
|
||||||
|
|
||||||
|
COMPRESS=gzip
|
||||||
|
|
||||||
|
#
|
||||||
|
# DEVICE: ...
|
||||||
|
#
|
||||||
|
# Specify a specific network interface, like eth0
|
||||||
|
# Overridden by optional ip= or BOOTIF= bootarg
|
||||||
|
#
|
||||||
|
|
||||||
|
DEVICE=
|
||||||
|
|
||||||
|
#
|
||||||
|
# NFSROOT: [ auto | HOST:MOUNT ]
|
||||||
|
#
|
||||||
|
|
||||||
|
NFSROOT=auto
|
||||||
|
|
||||||
|
#
|
||||||
|
# RUNSIZE: ...
|
||||||
|
#
|
||||||
|
# The size of the /run tmpfs mount point, like 256M or 10%
|
||||||
|
# Overridden by optional initramfs.runsize= bootarg
|
||||||
|
#
|
||||||
|
|
||||||
|
RUNSIZE=10%
|
||||||
|
|
||||||
|
#
|
||||||
|
# FSTYPE: ...
|
||||||
|
#
|
||||||
|
# The filesystem type(s) to support, or "auto" to use the current root
|
||||||
|
# filesystem type
|
||||||
|
#
|
||||||
|
|
||||||
|
FSTYPE=auto
|
||||||
|
|
||||||
|
# Disable hibernation
|
||||||
|
RESUME=none
|
||||||
18
initramfs/modules
Normal file
18
initramfs/modules
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# List of modules that you want to include in your initramfs.
|
||||||
|
# They will be loaded at boot time in the order below.
|
||||||
|
#
|
||||||
|
# Syntax: module_name [args ...]
|
||||||
|
#
|
||||||
|
|
||||||
|
# Filesystem support
|
||||||
|
nls_iso8859-1
|
||||||
|
isofs
|
||||||
|
ext4
|
||||||
|
squashfs
|
||||||
|
overlay
|
||||||
|
|
||||||
|
# Network modules
|
||||||
|
af_packet
|
||||||
|
|
||||||
|
# RTL8125 network driver for 2.5GbE
|
||||||
|
r8125
|
||||||
147
initramfs/scripts/netboot
Executable file
147
initramfs/scripts/netboot
Executable file
@@ -0,0 +1,147 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Import standard initramfs functions
|
||||||
|
. /scripts/functions
|
||||||
|
|
||||||
|
export PATH=/usr/bin:/usr/sbin:/bin:/sbin
|
||||||
|
MOUNTPOINT=/root
|
||||||
|
TMPFS_MOUNT=/mnt
|
||||||
|
|
||||||
|
# Parse kernel command line for HTTP root
|
||||||
|
parse_cmdline() {
|
||||||
|
for x in $(cat /proc/cmdline); do
|
||||||
|
case $x in
|
||||||
|
root=http://*)
|
||||||
|
export ROOT_URL="${x#root=}" ;;
|
||||||
|
rootfstype=*)
|
||||||
|
export ROOTFSTYPE="${x#rootfstype=}" ;;
|
||||||
|
overlayroot=*)
|
||||||
|
export OVERLAYROOT="${x#overlayroot=}" ;;
|
||||||
|
ip=*)
|
||||||
|
export BOOTIP="${x#ip=}" ;;
|
||||||
|
*)
|
||||||
|
: ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
mountroot() {
|
||||||
|
rc=1
|
||||||
|
parse_cmdline
|
||||||
|
|
||||||
|
if test -z "${ROOT_URL}"; then
|
||||||
|
log_failure_msg "No root URL defined (root=http://... not found)"
|
||||||
|
return ${rc}
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Configure networking before attempting downloads
|
||||||
|
log_begin_msg "Configuring network"
|
||||||
|
modprobe af_packet || log_warning_msg "af_packet load failed"
|
||||||
|
|
||||||
|
# Load RTL8125 driver (already in module list but explicit load for debugging)
|
||||||
|
modprobe r8125 || log_warning_msg "r8125 driver load failed, may use generic driver"
|
||||||
|
|
||||||
|
configure_networking
|
||||||
|
udevadm trigger
|
||||||
|
timeout 30 udevadm settle || log_warning_msg "udevadm settle timed out"
|
||||||
|
export DEVICE
|
||||||
|
log_end_msg
|
||||||
|
|
||||||
|
# Validate networking is up
|
||||||
|
INTERFACE_UP=0
|
||||||
|
for iface in $(ip link show | grep "^[0-9]" | awk -F: '{print $2}' | tr -d ' '); do
|
||||||
|
if ip addr show "$iface" | grep -q "inet "; then
|
||||||
|
INTERFACE_UP=1
|
||||||
|
log_begin_msg "Interface $iface has IP address"
|
||||||
|
ip addr show "$iface" | grep "inet " | awk '{print $2}'
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ $INTERFACE_UP -eq 0 ]; then
|
||||||
|
log_failure_msg "No network interface obtained an IP address"
|
||||||
|
return ${rc}
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Extract filename from URL
|
||||||
|
FILE_NAME=$(basename "${ROOT_URL}")
|
||||||
|
FILE_PATH="/${FILE_NAME}"
|
||||||
|
|
||||||
|
# Download the root filesystem with retries and timeouts
|
||||||
|
log_begin_msg "Downloading root filesystem from ${ROOT_URL}"
|
||||||
|
if wget --timeout=30 --tries=3 --waitretry=5 \
|
||||||
|
--progress=dot:mega \
|
||||||
|
"${ROOT_URL}" -O "${FILE_PATH}"; then
|
||||||
|
log_end_msg
|
||||||
|
else
|
||||||
|
log_failure_msg "Failed to download from ${ROOT_URL} after retries"
|
||||||
|
rm -f "${FILE_PATH}"
|
||||||
|
return ${rc}
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Verify the downloaded file is a valid SquashFS
|
||||||
|
if ! file "${FILE_PATH}" | grep -q "Squash"; then
|
||||||
|
log_failure_msg "Downloaded file is not a valid SquashFS image"
|
||||||
|
rm -f "${FILE_PATH}"
|
||||||
|
return ${rc}
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Handle SquashFS images with overlay
|
||||||
|
if echo "${FILE_NAME}" | grep -q squashfs; then
|
||||||
|
log_begin_msg "Setting up SquashFS with overlay"
|
||||||
|
|
||||||
|
# Mount read-only SquashFS
|
||||||
|
if ! mount -t squashfs "${FILE_PATH}" "${MOUNTPOINT}" -o ro; then
|
||||||
|
log_failure_msg "Failed to mount SquashFS at ${MOUNTPOINT}"
|
||||||
|
rm -f "${FILE_PATH}"
|
||||||
|
return ${rc}
|
||||||
|
fi
|
||||||
|
log_begin_msg "SquashFS mounted at ${MOUNTPOINT}"
|
||||||
|
log_end_msg
|
||||||
|
|
||||||
|
# Setup overlay if requested
|
||||||
|
if [ -n "${OVERLAYROOT}" ]; then
|
||||||
|
log_begin_msg "Mounting ${OVERLAYROOT} for overlay"
|
||||||
|
|
||||||
|
# Create tmpfs for upper and work directories
|
||||||
|
if ! mount -o size=2G -t "${OVERLAYROOT}" tmpfs_overlay "${TMPFS_MOUNT}"; then
|
||||||
|
log_failure_msg "Failed to mount tmpfs for overlay"
|
||||||
|
umount "${MOUNTPOINT}"
|
||||||
|
rm -f "${FILE_PATH}"
|
||||||
|
return ${rc}
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create overlay structure
|
||||||
|
mkdir -p "${TMPFS_MOUNT}/upper" "${TMPFS_MOUNT}/work"
|
||||||
|
|
||||||
|
# Mount overlay combining read-only lower + writable upper
|
||||||
|
if ! mount -t overlay \
|
||||||
|
-o "lowerdir=${MOUNTPOINT},upperdir=${TMPFS_MOUNT}/upper,workdir=${TMPFS_MOUNT}/work" \
|
||||||
|
overlay_root "${MOUNTPOINT}"; then
|
||||||
|
log_failure_msg "Failed to mount overlay filesystem"
|
||||||
|
umount "${TMPFS_MOUNT}"
|
||||||
|
umount "${MOUNTPOINT}"
|
||||||
|
rm -f "${FILE_PATH}"
|
||||||
|
return ${rc}
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_end_msg
|
||||||
|
log_begin_msg "Overlay mounted successfully"
|
||||||
|
log_end_msg
|
||||||
|
|
||||||
|
# Clean up downloaded image as it's now mounted
|
||||||
|
rm -f "${FILE_PATH}"
|
||||||
|
rc=0
|
||||||
|
else
|
||||||
|
# Direct SquashFS mount without overlay
|
||||||
|
log_begin_msg "Mounted SquashFS without overlay"
|
||||||
|
log_end_msg
|
||||||
|
rc=0
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log_failure_msg "Unknown filesystem type: ${FILE_NAME}"
|
||||||
|
rm -f "${FILE_PATH}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
return ${rc}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user