Building Talos Linux for Raspberry Pi 5 with Custom Kernel
Building Talos Linux for Raspberry Pi 5 with Custom Kernel
Getting Talos Linux running on the Raspberry Pi 5 requires a custom kernel build. The stock Talos kernel doesn’t include the necessary drivers for RPi5’s RP1 PCIe controller and MACB ethernet. This post documents the complete build process and the issues I encountered along the way.
The Problem
The RPi5 uses a new architecture with the RP1 southbridge chip connected via PCIe. This means:
- Different ethernet driver (MACB + Broadcom BCM54213PE PHY)
- Different device tree files (bcm2712 instead of bcm2711)
- Network interface named
end0instead ofeth0 - Potential 4K vs 16K page size conflicts
Prerequisites
- Docker with buildx support
- Local container registry (I used
localhost:5001) - ~50GB disk space for builds
- ARM64 cross-compilation support
Repository Structure
I created a monorepo with Talos and related projects as submodules:
talso-rpi5/
├── checkouts/
│ ├── pkgs/ # kernel builds
│ ├── talos/ # main OS
│ └── sbc-raspberrypi5/ # RPi5 overlay
├── _out/ # Build outputs
├── CLAUDE.md # Build documentation
└── AGENTS.md # Task delegation docs
Step 1: Build the Custom Kernel
The kernel needs specific configuration for RPi5:
# Clear Docker cache to ensure fresh build
docker builder prune -af
# Build kernel for arm64
cd checkouts/pkgs
gmake kernel PLATFORM=linux/arm64 PUSH=true \
REGISTRY=localhost:5001 USERNAME=wittenbude
Critical Kernel Config Settings
In checkouts/pkgs/kernel/build/config-arm64:
# Use 4K pages (16K causes Talos mount API issues)
CONFIG_ARM64_4K_PAGES=y
# CONFIG_ARM64_16K_PAGES is not set
# SD card drivers must be built-in (not modules)
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_SDHCI_BRCMSTB=y
# Ethernet support
CONFIG_MACB=y
CONFIG_PHYLIB=y
CONFIG_PHYLINK=y
CONFIG_BROADCOM_PHY=y
The 4K vs 16K page dilemma:
- 16K pages: Networking works, but Talos shadow bind mounts fail with EINVAL
- 4K pages: Talos boots cleanly, networking requires matching kernel and DTB versions
Step 2: Build the Imager
The imager creates the final bootable image. It needs to reference our custom kernel:
cd checkouts/talos
# Get the kernel tag
KERNEL_TAG=$(cd ../pkgs && git describe --tag --always --dirty)
# Build imager with custom kernel
gmake imager PLATFORM=linux/arm64 PUSH=true \
REGISTRY=localhost:5001 USERNAME=wittenbude \
PKG_KERNEL=localhost:5001/wittenbude/kernel:$KERNEL_TAG
Step 3: Build the RPi5 Overlay
The overlay provides RPi5-specific device tree files and firmware:
cd checkouts/sbc-raspberrypi5
# Get kernel tag for PKGS reference
KERNEL_TAG=$(cd ../pkgs && git describe --tag --always --dirty)
# Build overlay with our custom kernel's DTBs
gmake PLATFORM=linux/arm64 PUSH=true \
REGISTRY=localhost:5001 USERNAME=wittenbude \
PKGS_PREFIX=localhost:5001/wittenbude PKGS=$KERNEL_TAG
This ensures the DTB files match the kernel version - critical for RP1 initialization.
Step 4: Generate the Metal Image
cd checkouts/talos
IMAGER_TAG=$(git describe --tag --always --dirty)
OVERLAY_TAG=$(cd ../sbc-raspberrypi5 && git describe --tag --always --dirty)
docker run --rm -t --network=host \
-v ./_out:/out -v /dev:/dev --privileged \
localhost:5001/wittenbude/imager:$IMAGER_TAG \
metal --arch arm64 \
--board=rpi_generic \
--overlay-name=rpi5 \
--overlay-image=localhost:5001/wittenbude/sbc-raspberrypi5:$OVERLAY_TAG \
--extra-kernel-arg="console=tty1" \
--extra-kernel-arg="console=ttyAMA10,115200" \
--system-extension-image=ghcr.io/siderolabs/iscsi-tools:v0.1.10
Output: _out/metal-arm64.raw.zst (~88MB)
Step 5: Flash and Boot
# Identify SD card
diskutil list
# Unmount
diskutil unmountDisk /dev/disk4
# Flash (use rdisk for faster writes)
zstd -d -c _out/metal-arm64.raw.zst | sudo dd of=/dev/rdisk4 bs=4m status=progress
# Eject
diskutil eject /dev/disk4
Step 6: Apply Worker Configuration
Once booted, the node enters maintenance mode. Apply the worker config:
# In maintenance mode (first boot)
talosctl apply-config --insecure --nodes <NODE_IP> --file worker.yaml
# After leaving maintenance mode
talosctl -n <NODE_IP> apply-config --file worker.yaml
Critical: Enable Discovery
The worker config must include cluster discovery settings, or the node won’t appear in cluster membership:
cluster:
id: <CLUSTER_ID>
secret: <CLUSTER_SECRET> # Required for discovery auth
controlPlane:
endpoint: https://<CONTROL_PLANE_IP>:6443
clusterName: <CLUSTER_NAME>
discovery:
enabled: true # THIS IS CRITICAL
registries:
service:
endpoint: https://discovery.talos.dev/
kubernetes:
disabled: true
Without discovery.enabled: true and the cluster.secret, the node boots and kubelet runs, but talosctl get members won’t show it.
Network Interface
RPi5 uses end0 for ethernet (not eth0):
machine:
network:
interfaces:
- interface: end0
dhcp: true
UART Debugging
For boot issues, connect a UART adapter to the GPIO pins:
# Start logging session
screen -L -Logfile /tmp/uart.log /dev/cu.usbserial-* 115200
Key boot messages to watch for:
BL31- ARM Trusted Firmware startingmmc0: new- SD card detectedmacb- Ethernet driver loadingBCM54213PE- PHY detectedmachined- Talos starting
Troubleshooting
No Network Activity (NIC lights off)
- Check kernel/DTB version mismatch
- Verify RP1 PCIe initialization in dmesg
- Consider 16K page kernel if RP1 isn’t initializing
Node Not Appearing in Cluster
- Check
talosctl get discoveryconfig- must showdiscoveryEnabled: true - Verify
cluster.secretmatches control plane - Check
talosctl get membersfrom the node itself
Kubelet Certificate Errors
- Verify
cluster.ca.crtmatches the control plane’s certificate - Extract correct CA:
talosctl -n <CP_IP> get machineconfig -o yaml | grep -A1 "cluster:" | grep crt
Boot Loop at BL31
- Usually indicates 16K page kernel incompatibility
- Rebuild with
CONFIG_ARM64_4K_PAGES=y
Final Result
After all this, I have a working RPi5 node in my Talos cluster:
$ kubectl get nodes -o wide
NAME STATUS ROLES VERSION INTERNAL-IP KERNEL-VERSION
talos-192-168-150-8 Ready <none> v1.35.0 192.168.150.8 6.12.67-talos
talos-ek0-5dx Ready control-plane v1.35.0 100.78.183.103 6.18.2-talos
talos-lwn-dba Ready <none> v1.35.0 100.95.115.98 6.18.2-talos
The RPi5 is running the custom 6.12.67-talos kernel with 4K pages, working ethernet, and is fully participating in cluster workloads.
Repository
The build configuration and documentation are available at:
- Main repo: github.com/kcirtapfromspace/talos-rpi5
Submodule Forks (rpi5-support branch)
- pkgs (kernel config): github.com/kcirtapfromspace/pkgs
- talos (OS changes): github.com/kcirtapfromspace/talos
- sbc-raspberrypi5 (overlay): github.com/kcirtapfromspace/sbc-raspberrypi5