This repository provides manifests and a Makefile to configure and deploy a single-node Kubernetes cluster on a Raspberry Pi 4B (arm64) using k0s and Cilium with the modern Gateway API.
+-----------------------------+
| Home Router |
| Exposes ports 80 & 443 |
+--------------+--------------+
|
Port 80 | Port 443
(HTTP Challenge)| (Secure Traffic)
v
+--------------+--------------+
| Raspberry Pi Node |
| (Envoy Gateway on Host Net)|
| HTTP: 80, HTTPS: 443 |
+--------------+--------------+
|
| (Gateway API / Routing)
v
+---------------+---------------+
| |
v v
+--------+-------+ +---------+-------+
| deathstar | | xwing |
| (Service: Port | | (Service: Port |
| 80) | | 80) |
+----------------+ +-----------------+
-
Install Ubuntu Server 64-bit (aarch64) on your Raspberry Pi 4B.
-
Install necessary kernel modules and tools:
make apt
This installs
linux-modules-extra-raspi(mandatory for Cilium eBPF functionalities on Raspberry Pi kernels),git,build-essential, andpython3. -
Ensure systemd-sysctl uses the correct rp_filter settings if running on latest Arch/Ubuntu distributions:
echo 'net.ipv4.conf.lxc*.rp_filter = 0' | sudo tee /etc/sysctl.d/99-override_cilium_rp_filter.conf sudo systemctl restart systemd-sysctl
-
Install
container-structure-test(ARM64 binary) to verify container structures during testing:make container-structure-test-install
We boot a single-node k0s cluster configured to allow a custom CNI and optimized for a low memory footprint (ideal for a Raspberry Pi 4B).
- No Telemetry: Disabled to save CPU and bandwidth.
- No kube-proxy: Disabled completely to allow Cilium to run in
kube-proxy-replacementmode, saving significant memory. - Custom Network Provider: Set to
customin k0s.yaml to prevent the installation of default CNI plugins (e.g. Kube-Router or Calico), preparing the cluster for Cilium.
Run the installer target:
make k0s-installExtract the administrative kubeconfig:
mkdir -p ~/.kube
sudo k0s kubeconfig admin | tee ~/.kube/config > /dev/null
chmod 600 ~/.kube/configDownload and install the latest ARM64 binary:
make cilium-cli-installDeploy Cilium with Gateway API, L2 Announcements, and Hubble observability enabled. The deployment uses the helm configuration file cilium/values.yaml:
make cilium-installThis target:
- Applies the Gateway API CRDs.
- Deploys Cilium using the configuration file cilium/values.yaml, which configures:
cluster.name: bomber: Configures the cluster name.kubeProxyReplacement: true: Enables eBPF-based kube-proxy replacement, which is required for Gateway API.operator.replicas: 1: Sets replicas to 1 (ideal for single-node setups).routingMode: tunnel&tunnelProtocol: vxlan: Uses VXLAN tunneling for network routing.ingressController.enabled: false: Disables default Cilium Ingress Controller.l7Proxy: true: Enables the L7 proxy.l2announcements.enabled: true: Enables L2 announcements.gatewayAPI.enabled: true: Enables support for Gateway API resources.gatewayAPI.hostNetwork.enabled: true: Enables host networking for the Gateway proxy (Envoy binds directly to host ports80and443on the Raspberry Pi node).k8sServiceHost: 192.168.86.27&k8sServicePort: 6443: Explicitly points to the Kubernetes API server host.hubble: Enables Hubble, Hubble Relay, and Hubble UI for observability.
- Applies
cilium/l2-announcements.yamlto define the LoadBalancer IP pool (192.168.86.30-192.168.86.35) and the L2 Announcement Policy. - Applies
cilium/certificate.yamlto request the Let's Encrypt production SSL certificate for the domain.
Install cert-manager and wait for its webhook service to start:
make cert-manager-installThis applies the cluster_issuer.yaml which defines staging and production Let's Encrypt ClusterIssuers configured to use the Gateway HTTPRoute solver:
solvers:
- http01:
gatewayHTTPRoute:
parentRefs:
- name: orbo-mate-gateway
namespace: defaultBecause your Raspberry Pi is hosted inside a private home network behind a NAT router:
- Let's Encrypt requires port
80to be reachable from the internet for theHTTP-01challenge validation. - Setup Port Forwarding on your home internet router:
- Forward incoming WAN port 80 to the Raspberry Pi node's IP on LAN port 80.
- Forward incoming WAN port 443 to the Raspberry Pi node's IP on LAN port 443.
- Since Cilium is configured with
gatewayAPI.hostNetwork.enabled: true, Envoy binds directly to host ports80and443on the Raspberry Pi node, handling the HTTP-01 challenge and secure traffic directly on those ports.
Once Cilium and cert-manager are running, apply the Gateway and HTTPRoute manifests:
Apply gateway.yaml:
kubectl apply -f cilium/gateway.yamlThis deploys a Gateway utilizing gatewayClassName: cilium that listens on port 80 (HTTP) and port 443 (HTTPS with TLS termination pointing to secret cilium-gateway-tls).
Apply httproutes.yaml:
kubectl apply -f cilium/httproutes.yamlThis routes paths:
/deathstarto thedeathstarservice./xwingto thexwingservice.
- Create a secret for
image-updaterbuilds (matching default namespace pull credentials):echo '{"auths":{"ghcr.io":{"auth":"*****************"}}}' | kubectl create secret generic regcred-github --type=kubernetes.io/dockerconfigjson --from-file=.dockerconfigjson=/dev/stdin -n argocd
- Port-forward the service locally and follow the ArgoCD getting started guide.
- Setup SSH Git credentials for image-updater:
kubectl -n argocd create secret generic git-creds --from-file=sshPrivateKey=<path/to/id_rsa>
- Register SSH repository links:
argocd repo add git@github.com:shipperizer/furry-train.git --ssh-private-key-path ~/.ssh/bomber_id_ed25519 --name furry-train argocd repo add git@github.com:shipperizer/fluffy-octo-telegram.git --ssh-private-key-path ~/.ssh/bomber_id_ed25519 --name fluffy-octo-telegram
Create an opaque secret for container registry credentials:
echo '{"auths":{"ghcr.io":{"auth":"****************"}}}' | kubectl create secret generic regcred-github-kaniko --from-file=config.json=/dev/stdinIf you prefer Contour:
- Disable Traefik/Cilium ingress.
- Deploy Contour via Skaffold:
skaffold run --profile contour
- Expose the Envoy service port on your router.