Why does a Kubernetes LoadBalancer Service show EXTERNAL-IP <pending> in kubectl get svc, and which component is supposed to replace it?
answer
- a request, not a resource
- status written by someone else
- cloud-controller-manager's service controller
- loadBalancerClass nobody watches
- describe svc events
basics
~20 sA type=LoadBalancer Service only records a request. The cloud-controller-manager's service controller, or another load-balancer implementation such as MetalLB, must create the balancer and write its address into status. <pending> means nothing has done that yet.
solid answer
~40 sSetting `type: LoadBalancer` does not create anything outside the cluster. The API server allocates a ClusterIP and NodePorts, and then an implementation must act on the Service. On a cloud cluster that is the **service controller in the cloud-controller-manager**: it asks the provider for a balancer and writes the address into `status.loadBalancer.ingress`, which `kubectl get svc` prints as EXTERNAL-IP. `<pending>` means that field is still empty. The usual causes: - no implementation is installed at all (bare metal, kind, a plain kubeadm cluster) - `spec.loadBalancerClass` names a class nobody watches - provisioning is failing, which shows up as `SyncLoadBalancerFailed` events - the provider is simply still working Check with `kubectl describe svc`. The Service still works inside the cluster through its ClusterIP the whole time.
code
bash · 2 lineskubectl -n billing-invoices get svc invoice-renderer
kubectl -n billing-invoices describe svc invoice-renderer | sed -n '/Events:/,$p'go deeper
Remember the chain: the Service asks, the cloud-controller-manager's service controller builds the balancer and writes its address. <pending> means that address was never written. Start with kubectl describe svc.
Name the causes separately: no implementation, a loadBalancerClass nobody watches, SyncLoadBalancerFailed from the provider, or no eligible nodes. Each looks different in the Service's events.
Show you check the platform before the provider: is a CCM or MetalLB running, is the class correct, what do the events say. Mention that ClusterIP and NodePort already work, so in-cluster callers are unaffected.
Frame one balancer per Service as a cost and quota decision, and describe how the platform chooses load-balancer implementations and classes so tenants never end up waiting on an address with no explanation.
## What a LoadBalancer Service actually asks for A Kubernetes **Service** gives a stable address to a set of pods. With `spec.type: LoadBalancer`, the Service also asks for an **external load balancer**: something outside the cluster with its own address that forwards traffic in. The request is only data in the API. The **API server** allocates the parts it owns, a **ClusterIP** and (by default) a **NodePort** for each port. Nothing in the core API server talks to a cloud. The external address goes in `status.loadBalancer.ingress`, a list of entries that each carry an `ip` or a `hostname`. `kubectl get svc` prints that list in the **EXTERNAL-IP** column. When the list is empty and the Service has no `spec.externalIPs`, kubectl prints `<pending>`. ## Who is supposed to fill it in - **cloud-controller-manager (CCM)**: the provider-specific control-plane component. One of its loops is the **service controller** (`service-lb-controller`). It watches Services and acts on those with `type: LoadBalancer` and **no** `spec.loadBalancerClass`. - The controller calls the provider's `EnsureLoadBalancer`. When the balancer exists, it patches the Service status with the balancer's IP or hostname. - In current Kubernetes, **kube-controller-manager contains no cloud-provider code**. Cloud integration lives only in an external CCM, and kubelets are started with `--cloud-provider=external`. - **Other implementations** fill the same field on clusters without a cloud: MetalLB on bare metal, the simple built-in balancer that k3s ships, or `minikube tunnel` on a laptop. - **kube-proxy does not create balancers.** Once the address exists, it only programs node rules so that traffic arriving for it reaches pods. ## Why it stays <pending> 1. **No implementation exists.** A kubeadm cluster on bare metal or a kind cluster has no CCM with load-balancer support. The Service waits forever, and no event says why, because nothing is watching it. 2. **`spec.loadBalancerClass` is set** (for example `example.com/internal-vip`). The default implementation deliberately skips classed Services. If no controller watches that class, nothing happens. 3. **Provisioning fails.** The service controller emits a Warning event with reason `SyncLoadBalancerFailed` and the provider's error text (quota, permissions, an invalid annotation value), then retries with backoff. 4. **No eligible nodes.** The event `UnAvailableLoadBalancer` with the message "There are no available nodes for LoadBalancer" means every node was filtered out, for example by the `node.kubernetes.io/exclude-from-external-load-balancers` label. 5. **It is just slow.** Some providers take a minute or more. `EnsuringLoadBalancer` is logged with no `EnsuredLoadBalancer` yet. | What `kubectl describe svc` shows | Likely cause | |---|---| | No load-balancer events at all | No implementation installed, or a `loadBalancerClass` nobody watches | | `SyncLoadBalancerFailed` repeating | Provider rejected the request; read the error text | | `UnAvailableLoadBalancer` | Every node excluded or ineligible | | `EnsuringLoadBalancer`, nothing after | Provider still creating it | ## Diagnosing it Say the PDF-invoice renderer on a 210-node multi-tenant platform cluster has to move to a new public endpoint before the old one's certificate expires in 18 hours, and its Service stays pending: ```bash kubectl -n billing-invoices get svc invoice-renderer kubectl -n billing-invoices describe svc invoice-renderer kubectl -n billing-invoices get svc invoice-renderer -o jsonpath='{.spec.loadBalancerClass}' kubectl -n kube-system get pods | grep -i cloud-controller ``` If the events are empty, check whether a CCM (or MetalLB) is running at all before you blame the provider. ## What still works while it is pending - The **ClusterIP** and the Service's **DNS name** work normally for in-cluster clients. - Unless `allocateLoadBalancerNodePorts: false` is set, the **NodePort** is already open on every node, so `nodeIP:nodePort` works too. - Pod readiness is a separate question: pods that are not Ready leave the Service without backends, but they do not keep EXTERNAL-IP pending. So `<pending>` is a question about **the load-balancer implementation**, not about your pods.
- On a laptop kind or minikube cluster, how do you get past <pending> for local testing?Neither cluster has a cloud controller, so nothing fills in the status. With minikube, run `minikube tunnel`: it creates routes and writes an address into the Service status. With kind, install a local load-balancer implementation, such as MetalLB with a pool taken from the Docker network's range, or a kind-specific cloud-provider helper. For quick checks, `kubectl port-forward` or the NodePort avoids the question entirely.
- Why does giving every tenant Service its own LoadBalancer get expensive on a 210-node multi-tenant cluster?Each LoadBalancer Service normally becomes a separate cloud balancer, usually with its own billed address and hourly charge. Its backend set also tracks the node list, which is large here. Fifty tenant Services mean fifty balancers. HTTP services usually share one balancer in front of an ingress or gateway controller, and dedicated balancers are kept for non-HTTP protocols or hard isolation needs.
- If a Service shows an EXTERNAL-IP but external clients still cannot connect, is that still a provisioning problem?Usually not. An address in status means the implementation did its part. Next, check whether the Service has ready backends, whether the balancer's health checks pass against the nodes, and whether firewall rules or `loadBalancerSourceRanges` block the client. That is connectivity triage, a different job from provisioning.
Filing a Service of type LoadBalancer is like filing a work order. Nothing gets built until a contractor picks it up, and <pending> means no contractor has signed it yet.
saying these in an interview costs you the question
- kube-proxy creates the cloud load balancer
- Pending means the pods behind the Service are not ready
- The Service is unusable until the external IP appears
- Kubernetes provisions a load balancer on any cluster automatically
- kube-controller-manager's built-in cloud code handles it in current releases