In the benchmark a LoadBalancer Service on port 80 was still <pending> after 20 seconds on all three. kind 14,561 and minikube 14,561 have no load-balancer controller. k3d's ServiceLB binds Service ports on every node with hostPort, and Traefik 27,315 holds 80 and 443, so the Service stays pending, as the k3s 51,195 documentation warns; port 33080 always worked. kind's answer is cloud-provider-kind 508 (The Cloud Controller Manager), run on the host:
REL=https://github.com/kubernetes-sigs/cloud-provider-kind/releases/download/v0.11.1
curl -sL $REL/cloud-provider-kind_0.11.1_linux_amd64.tar.gz | tar xz cloud-provider-kind
kubectl expose deployment nginx --type=LoadBalancer --port=33080 --target-port=80
./cloud-provider-kind > cpk.log 2>&1 & CPK=$!
sleep 20; kubectl get service nginx
IP=$(kubectl get service nginx -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
curl -s "http://$IP:33080/" | grep -o '<title>.*</title>'
docker ps --filter label=io.x-k8s.cloud-provider-kind.cluster --format '{{.Names}} {{.Image}}'
kill $CPKservice/nginx exposed NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx LoadBalancer 10.96.212.78 172.18.0.5 33080:30685/TCP 20s <title>Welcome to nginx!</title> kindccm-1d5e36ea3a4e envoyproxy/envoy:v1.33.2
It starts an Envoy 117,531 container per Service on the kind network, whose IP becomes the external IP, and here also published the port on the host. It serves every kind cluster on the Docker 514 host, and if stopped while a Service exists, kubectl 5,150 delete service hangs on the service.kubernetes.io/load-balancer-cleanup finalizer.
| Need | kind | k3d | minikube |
|---|---|---|---|
| LoadBalancer Services | cloud-provider-kind on the host | ServiceLB built in (node IPs) | minikube tunnel |
| Ingress | cloud-provider-kind, or install a controller | Traefik preinstalled | addons enable ingress |
| Gateway API | cloud-provider-kind (standard channel) | CRDs preinstalled by k3s | Install a controller |
| Load a local image | kind load docker-image | k3d image import | minikube image load |
| Local registry | containerd 234,762 hosts.toml script in the docs | k3d registry create | addons enable registry |
Since version 0.9.0, cloud-provider-kind also serves Ingress and the Gateway API with no separate controller, which matters now that ingress-nginx is retired (Ingress-NGINX Retirement). Images come from Image Registries's registry through the hosts.toml pattern (Loading Local Images).