proxmox-k8s · Talos + Cilium on 192.168.20.0/24
All VMs run on a single Proxmox host (pve). Each K8s node VM gets a static IP on the LAN via cloud-init. GPUs are passed through via VFIO-PCI.
| IP / Range | Assignment | Managed by |
|---|---|---|
| 192.168.20.1 | Gateway / router | static |
| 192.168.20.2 | AdGuard Home DNS (Proxmox LXC) | OpenTofu |
| 192.168.20.10 | Proxmox VE host (pve) | static |
| 192.168.20.50 | k8s-cp-1 — control plane | OpenTofu |
| 192.168.20.51 | k8s-worker-1 — RTX 3090 (LLM inference) | OpenTofu |
| 192.168.20.52 | k8s-worker-2 — RTX 4070 (Immich / ML) | OpenTofu |
| 192.168.20.60 – 80 | Cilium L2 LoadBalancer pool | Cilium |
Node IPs are set via Proxmox cloud-init. LB IPs are virtual — Cilium responds to ARP on behalf of worker nodes, so external clients reach Services at those IPs on the LAN.
| CIDR | Purpose | Assigned by | Example |
|---|---|---|---|
| 10.244.0.0/16 | Pod IPs — every pod gets a unique IP | Cilium | 10.244.1.15 (an ArgoCD pod) |
| 10.96.0.0/12 | Service ClusterIPs — stable virtual IPs for services | kube-api | 10.96.0.10 (CoreDNS) |
| 192.168.20.50-52 | Node IPs — used by kubelet, Cilium tunnels | cloud-init | 192.168.20.51 (worker-1) |
Pod and Service IPs are virtual — they exist only inside the cluster. Cilium's eBPF programs route packets between all three spaces. Node IPs must be unique LAN addresses for VXLAN tunnels to work.
Kubelet injects nameserver 10.96.0.10 into every pod's /etc/resolv.conf. CoreDNS watches the kube-api for Service/Endpoint changes and serves name.namespace.svc.cluster.local → ClusterIP records. Cilium replaces kube-proxy entirely — Service routing is done in eBPF, not iptables.
Cilium L2 Announcements replace MetalLB. When a type: LoadBalancer Service is created, Cilium assigns an IP from the pool and responds to ARP on the LAN. External clients reach the Service at that IP without any router config.
Gateway API is the successor to Ingress. A single Gateway can serve many HTTPRoute resources across namespaces. The gatewayClassName field selects which controller (NGINX or Cilium/Envoy) handles the traffic — change it, push, and ArgoCD switches the L7 provider. Both controllers are installed; only the selected one processes the Gateway.
CNI (pod networking), kube-proxy replacement (eBPF Service routing), VXLAN tunnels between nodes, L2 LoadBalancer announcements, network policy enforcement.
Cluster DNS at 10.96.0.10. Resolves svc.cluster.local names to ClusterIPs. Injected into every pod by kubelet. Forwards non-cluster queries to 192.168.20.2 (AdGuard).
Two providers installed: NGINX Gateway Fabric (default) and Cilium/Envoy. Switch via gatewayClassName in the Gateway resource. HTTP host/path routing, TLS termination, cross-namespace routes.
Automated Let's Encrypt certificates via DNS-01 challenge. Provisions wildcard certs for Gateway listeners.