🎉 DevOps Interview Prep Bundle is live — 1000+ Q&A across 20 topicsGet it →
All Articles

Kubernetes Ingress External IP Stuck Pending: Fix in 5 Minutes

Ingress or LoadBalancer Service showing EXTERNAL-IP as <pending> forever? Here is exactly how to diagnose missing ingress controllers, cloud provider quota limits, and misconfigured service annotations blocking IP assignment.

Shubham4 min read
Share:Tweet

<pending> means Kubernetes is waiting on something external to assign an IP — either a cloud provider's load balancer controller or your ingress controller — and it will genuinely wait forever if that something never responds. Here is how to find what's actually missing.

Step 1: Confirm What Kind of Resource You're Waiting On

bash
kubectl get svc myapp -n production
# NAME    TYPE           EXTERNAL-IP   PORT(S)
# myapp   LoadBalancer   <pending>     80:31234/TCP
 
kubectl get ingress myapp -n production
# NAME    CLASS   HOSTS   ADDRESS   PORTS   AGE
# myapp   nginx   *                 80      10m    ← empty ADDRESS

A pending LoadBalancer Service and an empty-address Ingress have different root causes — check which one you actually have, and check events for both.

bash
kubectl describe svc myapp -n production | grep -A 10 Events:
kubectl describe ingress myapp -n production | grep -A 10 Events:

Cause 1: No Cloud Provider Integration for LoadBalancer Type (Bare-Metal/On-Prem Clusters)

bash
kubectl get nodes -o wide
# If this is a bare-metal or on-prem cluster (kubeadm, k3s without a
# cloud provider), there is NOTHING that knows how to provision a
# real external load balancer — LoadBalancer type will stay pending forever

Fix — install MetalLB or another bare-metal load balancer implementation:

yaml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: default-pool
  namespace: metallb-system
spec:
  addresses:
    - 192.168.1.240-192.168.1.250
bash
kubectl apply -f metallb-config.yaml
# Existing pending Services should get an IP assigned shortly after MetalLB is running

Cause 2: Missing Ingress Controller Entirely

bash
kubectl get pods -A | grep -i ingress
# If nothing shows up, no ingress controller is even installed —
# the Ingress resource exists but nothing is watching it

Creating an Ingress resource does nothing on its own — it needs a controller (nginx-ingress, AWS Load Balancer Controller, GKE Ingress) actually running and watching for Ingress objects.

Fix — install the appropriate controller for your environment:

bash
# Example: ingress-nginx via Helm
helm install ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx --create-namespace

Cause 3: Cloud Provider Quota or IAM Permission Blocking Provisioning

bash
kubectl describe svc myapp -n production
# Events:
#   Warning  SyncLoadBalancerFailed  ... could not find any suitable
#   subnets for creating the ELB

This is the most common AWS-specific cause — the AWS Load Balancer Controller (or in-tree provider) needs subnets tagged correctly, and IAM permissions to actually create the load balancer.

bash
# Check subnet tags — required for the controller to discover them
aws ec2 describe-subnets --filters "Name=vpc-id,Values=vpc-0abc123" \
  --query 'Subnets[*].[SubnetId,Tags]'

Fix — ensure subnets have the required discovery tags:

bash
aws ec2 create-tags --resources subnet-0abc123 \
  --tags Key=kubernetes.io/role/elb,Value=1    # public subnets for internet-facing LBs
aws ec2 create-tags --resources subnet-0def456 \
  --tags Key=kubernetes.io/role/internal-elb,Value=1   # private subnets for internal LBs
bash
# Also check the controller's own logs for IAM permission errors
kubectl logs -n kube-system deployment/aws-load-balancer-controller | grep -i "denied\|forbidden"

Also verify against your account's actual ELB quota:

bash
aws service-quotas get-service-quota --service-code elasticloadbalancing \
  --quota-code L-53DA6B97    # Application Load Balancers per region

Cause 4: IngressClass Not Matching Any Installed Controller

bash
kubectl get ingress myapp -n production -o jsonpath='{.spec.ingressClassName}'
# nginx
 
kubectl get ingressclass
# NAME      CONTROLLER
# alb                     ← only "alb" is actually installed, "nginx" was requested but doesn't exist

If the Ingress requests a class that isn't installed, no controller ever picks it up — it just sits there indefinitely with no address, and often no obvious error either.

Fix — match the ingressClassName to what's actually installed, or install the requested one:

yaml
spec:
  ingressClassName: alb    # Match to what's actually running in the cluster

Cause 5: Service Annotations Specific to a Different Cloud Provider

yaml
# This annotation is AWS-specific — has zero effect on GKE or AKS,
# and the Service will just stay pending with no clear error
metadata:
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-type: "nlb"

If manifests were copied from documentation or another cluster running on a different cloud, provider-specific annotations silently do nothing on the wrong provider — no error, just no load balancer created.

Fix — use the annotation set matching your actual cloud provider:

bash
# Confirm which cloud you're actually on before trusting copy-pasted annotations
kubectl get nodes -o jsonpath='{.items[0].spec.providerID}'
# aws:///us-east-1a/i-0abc123    ← confirms AWS, so AWS-specific annotations are correct here

Diagnostic Checklist

bash
kubectl describe svc myapp -n production | grep -A 10 Events:      # actual error from the controller
kubectl get pods -A | grep -i ingress                               # confirm a controller exists at all
kubectl get ingressclass                                             # confirm the requested class exists
kubectl logs -n kube-system deployment/aws-load-balancer-controller  # (if applicable) controller-side errors

More Kubernetes networking troubleshooting? Read our Kubernetes service not routing traffic fix and How to migrate ingress-nginx to Gateway API.

🔧

Today I Fixed

Short real fixes from production — posted daily

Browse fixes
Newsletter

Stay ahead of the curve

Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.

Related Articles

Comments