
Overview
- Technologies: Cilium (L2 announcements), Kind (local cluster), Helm, kubectl.
- Goal: Assign external IPs from a node subnet to LoadBalancer services and have selected nodes respond to ARP for those IPs using Cilium L2 announcements.
- Key CRDs used:
- CiliumLoadBalancerIPPool: allocate external IPs for LoadBalancer services.
- CiliumL2AnnouncementPolicy: control which nodes/interfaces respond to ARP for which services.
Prerequisites
- A running Kind cluster and kubectl configured to that cluster.
- Helm installed and access to the Cilium Helm chart (cilium/cilium).
- Docker available if using Kind node containers for debugging.
- Cilium: https://cilium.io/
- Kind: https://kind.sigs.k8s.io/
- Helm: https://helm.sh/
1. Check cluster state and prepare Cilium values
Before installing Cilium, the cluster nodes may appear NotReady because the CNI is missing:When enabling kube-proxy replacement, provide the API server host and port (k8sServiceHost and k8sServicePort) so Cilium can reach the Kubernetes API. You can also edit the chart values file and set these keys before installing via Helm.
2. Deploy two simple applications with LoadBalancer services
Create a manifest named apps-and-svcs.yaml which deploys two HTTP echo applications and exposes each with a Service of type LoadBalancer. apps-and-svcs.yaml:<pending>:
3. Provide external IPs to LoadBalancer services with Cilium IPAM
Create a CiliumLoadBalancerIPPool so Cilium can allocate external IPs for your services from an address block on your node subnet. In this demo the node subnet is 172.19.0.0/16 and we pick a small range: ipam.yaml:4. Configure the Cilium L2 Announcement policy
Create a CiliumL2AnnouncementPolicy to control which nodes and interfaces respond to ARP for which services. The example below:- Matches services labeled app: myapp
- Excludes the control-plane node so only worker nodes respond
- Restricts interfaces with a regex ‘^eth[0-9]+’ (matches eth0, eth1, …)
- Enables both externalIPs and loadBalancerIPs
5. Which node responds for each service IP? (Leases)
Cilium coordinates which node will answer ARP for a given external IP using Lease objects. You can list the leases in the kube-system namespace:6. Test connectivity and validate ARP
After the L2 announcement policy is active, clients on the same subnet can reach the LoadBalancer external IPs:7. Summary and quick references
- Enable l2announcements and kube-proxy replacement in Cilium (via Helm values or values.yaml).
- Create a CiliumLoadBalancerIPPool to allocate external IPs on the node subnet for LoadBalancer services.
- Create a CiliumL2AnnouncementPolicy to specify which services, nodes, and interfaces should respond to ARP (externalIPs and/or loadBalancerIPs).
- Inspect Leases to determine which node is announcing each external IP, and validate connectivity with curl and arp.
Further reading and docs:
- Cilium L2 Announcement docs (search for “L2 announcements”)
- Kind - Kubernetes in Docker
- Helm documentation