iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Ingress

An Ingress exposes HTTP/HTTPS services to the outside world. Acts as a layer-7 reverse proxy: host/path routing, TLS termination, optional auth. Requires an Ingress Controller (nginx, traefik, AWS ALB, etc.) to actually serve traffic.

Resource + controller + TLS + best practices

EXAMPLE
# 1) Install an Ingress Controller (one per cluster)
# nginx-ingress (most common)
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/cloud/deploy.yaml

# Or via Helm
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm install nginx ingress-nginx/ingress-nginx --namespace ingress-nginx --create-namespace

# Other controllers:
#   - Traefik (CRD-driven, modern)
#   - HAProxy Ingress
#   - AWS Load Balancer Controller (ALB / NLB)
#   - GCE Ingress (on GKE)
#   - Azure Application Gateway Ingress
#   - Istio Gateway (service mesh)

# 2) Basic Ingress — host + path routing
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
    name: app
    annotations:
        nginx.ingress.kubernetes.io/rewrite-target: /
spec:
    ingressClassName: nginx
    rules:
        - host: app.example.com
          http:
              paths:
                  - path: /
                    pathType: Prefix
                    backend:
                        service:
                            name: web
                            port:
                                number: 80

# 3) Multiple hosts → multiple services
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata: { name: multi-host }
spec:
    ingressClassName: nginx
    rules:
        - host: api.example.com
          http: { paths: [{ path: /, pathType: Prefix, backend: { service: { name: api-svc,    port: { number: 80 } } } }] }
        - host: app.example.com
          http: { paths: [{ path: /, pathType: Prefix, backend: { service: { name: web-svc,    port: { number: 80 } } } }] }
        - host: admin.example.com
          http: { paths: [{ path: /, pathType: Prefix, backend: { service: { name: admin-svc,  port: { number: 80 } } } }] }

# 4) Path-based routing on one host
rules:
    - host: example.com
      http:
          paths:
              - path: /api
                pathType: Prefix
                backend: { service: { name: api-svc, port: { number: 80 } } }
              - path: /admin
                pathType: Prefix
                backend: { service: { name: admin-svc, port: { number: 80 } } }
              - path: /
                pathType: Prefix
                backend: { service: { name: web-svc, port: { number: 80 } } }

# pathType:
#   Prefix       — matches if path starts with this prefix (most common)
#   Exact        — must match exactly
#   ImplementationSpecific — controller decides

# 5) TLS — terminate at the ingress
apiVersion: v1
kind: Secret
metadata: { name: app-tls }
type: kubernetes.io/tls
data:
    tls.crt: <base64-cert>
    tls.key: <base64-key>
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
    name: app-tls
    annotations:
        nginx.ingress.kubernetes.io/ssl-redirect: 'true'
spec:
    ingressClassName: nginx
    tls:
        - hosts: [app.example.com]
          secretName: app-tls
    rules:
        - host: app.example.com
          http: { paths: [{ path: /, pathType: Prefix, backend: { service: { name: web, port: { number: 80 } } } }] }

# 6) cert-manager — automatic Let's Encrypt
# 1. Install cert-manager
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/latest/download/cert-manager.yaml

# 2. Define a ClusterIssuer
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata: { name: letsencrypt-prod }
spec:
    acme:
        server: https://acme-v02.api.letsencrypt.org/directory
        email:  ops@example.com
        privateKeySecretRef: { name: letsencrypt-account-key }
        solvers:
            - http01: { ingress: { class: nginx } }

# 3. Annotate the Ingress; cert-manager creates + renews the cert automatically
metadata:
    annotations:
        cert-manager.io/cluster-issuer: letsencrypt-prod

# 7) Common annotations (nginx-ingress)
annotations:
    nginx.ingress.kubernetes.io/rewrite-target:       /
    nginx.ingress.kubernetes.io/use-regex:            'true'
    nginx.ingress.kubernetes.io/ssl-redirect:         'true'
    nginx.ingress.kubernetes.io/force-ssl-redirect:   'true'
    nginx.ingress.kubernetes.io/proxy-body-size:      '10m'
    nginx.ingress.kubernetes.io/proxy-read-timeout:   '60'
    nginx.ingress.kubernetes.io/proxy-connect-timeout: '5'
    nginx.ingress.kubernetes.io/limit-rps:            '30'              # rate limit
    nginx.ingress.kubernetes.io/auth-type:            'basic'
    nginx.ingress.kubernetes.io/auth-secret:          'basic-auth'
    nginx.ingress.kubernetes.io/cors-allow-origin:    'https://app.example.com'
    nginx.ingress.kubernetes.io/configuration-snippet: |
        more_set_headers "X-Custom-Header: yes";

# 8) Sticky sessions
annotations:
    nginx.ingress.kubernetes.io/affinity:        'cookie'
    nginx.ingress.kubernetes.io/session-cookie-name: 'route'
    nginx.ingress.kubernetes.io/session-cookie-expires: '172800'
    nginx.ingress.kubernetes.io/session-cookie-max-age: '172800'

# 9) Canary releases — shift % traffic to a new version
# Production Ingress: app.example.com → web-v1 service
# Canary Ingress:
metadata:
    name: app-canary
    annotations:
        nginx.ingress.kubernetes.io/canary:        'true'
        nginx.ingress.kubernetes.io/canary-weight: '10'      # 10% of traffic
spec:
    rules:
        - host: app.example.com
          http: { paths: [{ path: /, pathType: Prefix, backend: { service: { name: web-v2, port: { number: 80 } } } }] }

# 10) Gateway API — the modern replacement for Ingress
# Promoted to GA in Kubernetes 1.29. Richer routing (HTTPRoute, TCPRoute, GRPCRoute), better multi-tenancy.
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata: { name: app }
spec:
    parentRefs: [{ name: example-gateway }]
    hostnames: ['app.example.com']
    rules:
        - matches: [{ path: { type: PathPrefix, value: / } }]
          backendRefs: [{ name: web, port: 80 }]

# Gateway API is portable across controllers + has clearer separation between
# 'infra owners' (Gateway) and 'app owners' (HTTPRoute).

# 11) Common controllers — quick guide
# nginx-ingress             : most common; mature; rich annotation set
# Traefik                   : great defaults; native CRDs (IngressRoute)
# AWS ALB Controller        : provisions an AWS ALB; tight cloud integration
# Istio Gateway             : if you're already running a service mesh
# Cloudflare Tunnel          : zero-config tunnel for non-cluster traffic
# Contour / Envoy            : high-performance Envoy-based

# 12) Debug
kubectl get ingress
kubectl describe ingress app
kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx
kubectl get events -A --sort-by='.lastTimestamp' | head

curl -v -H 'Host: app.example.com' http://<ingress-lb-ip>/

# 13) Best practices
#   • Use Gateway API for new clusters
#   • Terminate TLS at the ingress; pod-internal traffic is plaintext (or use mTLS via mesh)
#   • cert-manager for auto-issued + renewed Let's Encrypt certs
#   • Set readiness probes on backend pods — ingress only routes to ready ones
#   • One Ingress per app — easier to delete + reason about
#   • Use NetworkPolicies to restrict who can call the backend service directly
#   • Rate limit at the ingress; deeper limits at the app
#   • Use external-dns to auto-create DNS records from Ingress hosts

# 14) Anti-patterns
#   ❌ One mega-Ingress with 50 hosts — slow updates, hard to manage
#   ❌ Multiple Ingress resources mounting overlapping paths — undefined behavior
#   ❌ Forgetting ingressClassName — controller may not pick it up
#   ❌ TLS cert renewed manually — use cert-manager
#   ❌ Exposing internal admin endpoints via the same Ingress as user traffic — use a separate one with auth

Why it matters

Use cert-manager + Let’s Encrypt for free auto-renewed TLS — the days of forgetting to renew a cert are over. For new clusters, lean into Gateway API: clearer roles, richer routing, controller-portable.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
kind: Ingress
spec:
    rules:
        - host: api.example.com
            http: { paths: [{ path: /, pathType: Prefix, backend: { service: { name: api, port: { number: 80 } } } }] }
Try it Yourself »

Test yourself

Q1. Ingress provides…
Q2. You typically also install…
Q3. TLS certs come from…

Discussion

Loading…