- Status: Accepted (supersedes the MetalLB configuration used prior to 2026-04-16)
- Date: 2026-04-16
- Deciders: project author
make kind-up needs Service objects of type LoadBalancer to expose inventory and products externally for the e2e curl suite. A vanilla KinD cluster has no cloud provider, so LoadBalancer IPs stay in <pending> forever without a controller that watches those Services and allocates IPs on the host's kind Docker network.
The two established options are:
- MetalLB — mature, runs in-cluster as a Deployment + DaemonSet, configured via
IPAddressPool+L2AdvertisementCRDs. - cloud-provider-kind — kind-team-maintained host-side controller that runs as a Docker container on the
kindDocker network and watches Services via the Docker socket.
The project used MetalLB from initial setup until 2026-04-16.
Switch to cloud-provider-kind.
- Positive:
- Kind-team-maintained (
kubernetes-sigs/cloud-provider-kind) — newkindest/nodeimages are supported day-one. MetalLB releases on an independent cadence; MetalLB 0.15.3 refused to reach the K8s API onkindest/node:v1.35.0due to an nftables regression, stranding projects on v1.34.x for months. - Simpler Makefile: one
docker run --network kind ... cloud-provider-kind/cloud-controller-managerline replaces a kubectl-apply of the MetalLB manifest + twokubectl rollout statuswaits + adocker network inspect | awksubnet carve + asedtemplating pass onmetallb-config.yaml. - Smaller in-cluster footprint — no
metallb-systemnamespace, no controller Deployment, no speaker DaemonSet.
- Kind-team-maintained (
- Negative:
- Requires access to
/var/run/docker.sockon the host (MetalLB required onlykubectlaccess). - Not suitable for non-kind clusters (k3s, bare-metal, cloud) — those still need a cloud controller or MetalLB.
- Requires access to
- Neutral:
- LoadBalancer IP discovery remains identical from the application's perspective (
kubectl get svc -o jsonpath='{.status.loadBalancer.ingress[0].ip}').
- LoadBalancer IP discovery remains identical from the application's perspective (
| Option | Pros | Cons | Why not |
|---|---|---|---|
| MetalLB (previous choice) | Mature; prod-parity with teams that run MetalLB upstream | Independent release track → K8s-version drift; in-cluster footprint; more Makefile surface | Lost the parity argument when MetalLB's K8s support lagged KinD's |
| NodePort exposure | Zero controller overhead | Loses the LoadBalancer abstraction; e2e test logic has to handle port mapping per runtime | Breaks the cloud-parity goal of the stack |
| Skip LoadBalancer altogether | Simplest | E2E loses the external-IP hop that production uses | Would produce a less faithful integration test |
- Deployment diagram:
docs/diagrams/c4-deployment.puml - Makefile:
CLOUD_PROVIDER_KIND_VERSION,kind-createtarget - Deleted:
k8s/metallb-config.yaml(2026-04-16) - Upstream: https://github.com/kubernetes-sigs/cloud-provider-kind