Kubernetes Ingress

The Kubernetes API object that provides Layer 7 (HTTP/HTTPS) routing into the cluster. Ingress enables a single external IP to serve multiple applications based on hostnames and URL paths — a core topic in the CKA “Services & Networking” domain (~20%). Synthesized from CKA Day 33 — Kubernetes Ingress Tutorial | Ingress Explained by @AbhishekVeeramalla.

The Problem Services Cannot Solve

Kubernetes Services are Layer 4 (TCP/UDP) load balancers. While they provide stable networking for Pods, they are not designed for HTTP-specific routing:

  • One Service = one app. If you run 10 web applications, you need 10 Services.
  • NodePort consumes high ports. Each Service needs a unique port in the 30,000–32,767 range — users must remember NodeIP:30001 for app A, NodeIP:30002 for app B.
  • LoadBalancer is expensive. Every Service of type LoadBalancer provisions a separate cloud load balancer with its own public IP. Ten apps = ten cloud LBs = ten bills.
  • No hostname or path routing. Services route by IP and port alone. You cannot say “app1.example.com goes to Service A, /api goes to Service B.”

Ingress solves all of these by introducing a single entry point that understands HTTP semantics.

Ingress Resource vs Ingress Controller

The most important distinction in Kubernetes networking: the Ingress resource is just a rulebook; the Ingress Controller is the traffic cop that reads it.

ComponentTypeRole
Ingress ResourceKubernetes API object (kind: Ingress)Declares routing rules: which host/path goes to which Service
Ingress ControllerPod/Deployment (third-party)Watches Ingress resources and configures a reverse proxy (nginx, Traefik, Envoy)
IngressClassKubernetes API object (kind: IngressClass)Binds an Ingress resource to a specific controller when multiple controllers exist

Critical Trap: Kubernetes clusters ship with no default Ingress Controller. Creating an Ingress resource on a fresh cluster does absolutely nothing until you install a controller (nginx, Traefik, HAProxy, etc.). Source: CKA Day 33

Ingress YAML Anatomy

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: multi-app-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
    - host: frontend.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: frontend-svc
                port:
                  number: 80
    - host: api.example.com
      http:
        paths:
          - path: /v1
            pathType: Prefix
            backend:
              service:
                name: api-v1-svc
                port:
                  number: 8080
          - path: /v2
            pathType: Prefix
            backend:
              service:
                name: api-v2-svc
                port:
                  number: 8080
  tls:
    - hosts:
        - frontend.example.com
      secretName: frontend-tls

Field Reference

FieldDescriptionRequired
apiVersionnetworking.k8s.io/v1 (stable since 1.19; replaces deprecated extensions/v1beta1)Yes
metadata.nameUnique name in the namespaceYes
metadata.annotationsController-specific hints (not validated by Kubernetes)No
spec.ingressClassNameReferences an IngressClass object to select the controllerRecommended
spec.rules[].hostVirtual hostname to match (HTTP Host header)No (omitting creates a catch-all)
spec.rules[].http.paths[].pathURL path to matchYes
spec.rules[].http.paths[].pathTypeMatching semantics: Exact, Prefix, or ImplementationSpecificYes
spec.rules[].http.paths[].backend.service.nameTarget Service nameYes
spec.rules[].http.paths[].backend.service.port.numberTarget Service portYes
spec.tls[].hostsHostnames to secure with TLSNo
spec.tls[].secretNameName of a kubernetes.io/tls Secret holding the certificate and keyNo

Path Types Explained

TypeBehaviorExample
ExactCase-sensitive, full-path match only/foo matches /foo; does NOT match /foo/ or /foo/bar
PrefixMatches beginning of path, split on //foo matches /foo, /foo/bar, /foo/bar/baz; does NOT match /foobar
ImplementationSpecificController decides matching rulesnginx may treat it as regex-capable Prefix

CKA Tip: On the exam, use Prefix for most routing and Exact when you need strict single-path matching. Avoid ImplementationSpecific unless the question explicitly references a controller-specific feature.

The Default Backend

Every Ingress Controller maintains a default backend — a fallback Service that receives all requests matching no rules. This is how the controller returns HTTP 404 pages for unknown hosts/paths. You can inspect it with:

kubectl get svc -n ingress-nginx   # The default backend is usually named "ingress-nginx-defaultbackend"

IngressClass: Selecting the Right Controller

When multiple Ingress Controllers run in one cluster (e.g., one for public traffic, one for internal), IngressClass objects disambiguate which controller handles which Ingress:

apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: nginx
spec:
  controller: k8s.io/ingress-nginx   # The controller's self-reported identifier

The Ingress resource references it via spec.ingressClassName: nginx. Before Kubernetes 1.18, this was done with the annotation kubernetes.io/ingress.class: nginx — now deprecated in favor of the explicit field.

Annotations: Controller-Specific Power-User Features

Annotations are the escape hatch for features that the Ingress API spec does not cover. They are controller-specific and silently ignored if the controller does not recognize them.

AnnotationControllerPurpose
nginx.ingress.kubernetes.io/rewrite-target: /nginxRemoves the matched path prefix before forwarding to the backend
nginx.ingress.kubernetes.io/ssl-redirect: "true"nginxRedirects all HTTP requests to HTTPS
nginx.ingress.kubernetes.io/proxy-body-size: "10m"nginxIncreases maximum allowed upload body size
nginx.ingress.kubernetes.io/rate-limit: "100"nginxEnables request-rate limiting

Trap: Typos in annotations are not rejected by kubectl apply. If an annotation does not work, check the controller logs first.

TLS Termination at Ingress

Ingress is the canonical place to terminate TLS for cluster applications. Rather than managing certificates in every Pod, the Ingress Controller holds the certificate and decrypts traffic before forwarding HTTP to backend Services:

# Create a TLS Secret from certificate files
kubectl create secret tls frontend-tls \
  --cert=frontend.crt --key=frontend.key
spec:
  tls:
    - hosts:
        - frontend.example.com
      secretName: frontend-tls
  rules:
    - host: frontend.example.com
      http:
        paths:
          - path: /
            backend:
              service:
                name: frontend-svc
                port:
                  number: 80

Traffic flow with TLS:

Client (HTTPS)
    │
    ▼
Ingress Controller — TLS termination (cert from Secret)
    │
    ▼
Service (HTTP, port 80)
    │
    ▼
Pod (plain HTTP)

Security Note: By default, traffic from the Ingress Controller to the Service is unencrypted. For end-to-end encryption, use a service mesh (Istio, Linkerd) or configure the controller to re-encrypt to the backend. See TLS Fundamentals for certificate mechanics. Source: CKA Day 20

Common Ingress Controllers

ControllerBest ForNotable Features
NGINX Ingress ControllerGeneral purpose, learning, CKAMost popular; vast annotation set; community Helm chart
TraefikCloud-native, dynamic configNative Kubernetes CRDs (IngressRoute); automatic Let’s Encrypt
HAProxy IngressHigh-performance L4/L7Excellent performance; enterprise support
Cilium Gateway APIeBPF clustersReplaces Ingress with Kubernetes Gateway API; L7 policies
Istio GatewayService mesh environmentsAdvanced traffic splitting, mTLS, observability

Essential Commands

# List all Ingress resources
kubectl get ingress
kubectl get ingress -n <namespace>
 
# Describe an Ingress (shows rules, backend, and events)
kubectl describe ingress <name>
 
# Check Ingress Controller status
kubectl get pods -n ingress-nginx
kubectl logs -n ingress-nginx deployment/ingress-nginx-controller
 
# Validate Ingress YAML without applying
kubectl apply -f ingress.yaml --dry-run=client
 
# Get the external IP of the Ingress Controller
kubectl get svc -n ingress-nginx

Troubleshooting Matrix

SymptomRoot CauseFix
Ingress exists but routing failsNo Ingress Controller installedhelm install ingress-nginx ... or apply official manifest
404 from default backendHost or path mismatchVerify kubectl get ingress output; check DNS resolves to controller IP
TLS handshake errorWrong Secret name, wrong Secret type, or expired certEnsure Secret is type kubernetes.io/tls; check kubectl get secret
Path not strippedMissing rewrite-target annotationAdd nginx.ingress.kubernetes.io/rewrite-target: /
External IP <pending>No cloud provider integrationUse NodePort for the controller Service, or install MetalLB
Annotations ignoredWrong controller or typoCheck controller logs; verify annotation prefix matches controller

Ingress vs Gateway API

The Kubernetes community is gradually moving from Ingress to the Gateway API (a newer, more expressive standard). Gateway API introduces Gateway, HTTPRoute, and TCPRoute resources with better traffic splitting, cross-namespace routing, and role separation. However, Ingress remains the CKA exam standard and is still dominant in production.

FeatureIngressGateway API
MaturityStable, universally supportedBeta/GA (v1 since 1.23+)
FlexibilityLimited; relies on annotationsRich; built-in traffic splitting, weights
Cross-namespace routingComplexFirst-class support
Role separationNoneInfrastructure (Gateway) vs App (Route)
CKA exam✅ Tested❌ Not yet tested

Sources


Tags: kubernetes ingress nginx cka networking l7-routing tls gateway-api devops services annotations