Kubernetes Ingress — Interview Questions & Answers
Section 1 — Fundamentals
Q1. What is Kubernetes Ingress and why do we need it?
Ingress is a Kubernetes API object that manages external HTTP/HTTPS access to services inside a cluster. It provides a single entry point that can route traffic to multiple services based on host, path, or headers — without needing a separate LoadBalancer service per application.
Without Ingress: Service A → LoadBalancer → public IP 20.x.x.1 ($$$) Service B → LoadBalancer → public IP 20.x.x.2 ($$$) Service C → LoadBalancer → public IP 20.x.x.3 ($$$)With Ingress: Single LoadBalancer → public IP 20.x.x.1 /api → Service A /app → Service B /admin → Service C One IP, one LB, one TLS certificate
Q2. What is the difference between Ingress and a Service of type LoadBalancer?
| LoadBalancer Service | Ingress | |
|---|---|---|
| Layer | L4 (TCP/UDP) | L7 (HTTP/HTTPS) |
| Routing | IP + port only | host, path, headers |
| TLS termination | ❌ | ✅ |
| Cost | One LB per service | One LB for all services |
| Path-based routing | ❌ | ✅ |
| Host-based routing | ❌ | ✅ |
Q3. What are the components of an Ingress resource?
apiVersion: networking.k8s.io/v1kind: Ingressmetadata: name: my-ingress namespace: production annotations: # controller-specific config nginx.ingress.kubernetes.io/rewrite-target: /spec: ingressClassName: nginx # which controller handles this tls: # TLS configuration - hosts: - app.contoso.com secretName: tls-secret rules: # routing rules - host: app.contoso.com # host-based routing http: paths: - path: /api # path-based routing pathType: Prefix backend: service: name: api-service port: number: 8080 - path: / # default backend pathType: Prefix backend: service: name: frontend-service port: number: 80
Q4. What is an Ingress Controller? Is it included in Kubernetes by default?
An Ingress Controller is the implementation — it reads Ingress resources and configures an actual reverse proxy or load balancer accordingly. Kubernetes defines the Ingress API but ships with no controller by default — you must install one.
Popular controllers:
| Controller | Best for |
|---|---|
| NGINX Ingress Controller | General purpose — most widely used |
| Traefik | Dynamic config, microservices |
| HAProxy | High performance, enterprise |
| AWS ALB Ingress Controller | EKS on AWS |
| Azure Application Gateway Ingress (AGIC) | AKS on Azure |
| GCE Ingress Controller | GKE on GCP |
| Istio Gateway | Service mesh environments |
Q5. What are the three pathType values and how do they differ?
# Exact — must match exactly- path: /api/v1 pathType: Exact# Matches: /api/v1# Does NOT match: /api/v1/, /api/v1/users# Prefix — matches path prefix split by /- path: /api pathType: Prefix# Matches: /api, /api/, /api/v1, /api/v1/users# Does NOT match: /apiv1, /apiusers# ImplementationSpecific — controller decides- path: /api/* pathType: ImplementationSpecific# Behaviour depends on your ingress controller# NGINX: regex support# Traefik: glob support
Q6. What is the difference between host-based and path-based routing?
# Host-based routing — different subdomains → different servicesrules: - host: api.contoso.com http: paths: - path: / pathType: Prefix backend: service: name: api-service port: number: 80 - host: app.contoso.com http: paths: - path: / pathType: Prefix backend: service: name: frontend-service port: number: 80# Path-based routing — same host, different paths → different servicesrules: - host: contoso.com http: paths: - path: /api pathType: Prefix backend: service: name: api-service port: number: 80 - path: /static pathType: Prefix backend: service: name: cdn-service port: number: 80 - path: / pathType: Prefix backend: service: name: frontend-service port: number: 80
Q7. What is a default backend?
The default backend handles requests that match no rule in any Ingress. It returns a 404 or custom error page:
spec: defaultBackend: service: name: default-404-service port: number: 80 rules: - host: app.contoso.com ...# Any request not matching app.contoso.com → default-404-service
Section 2 — Ingress Controllers
Q8. How does NGINX Ingress Controller work internally?
1. You apply an Ingress resource to the cluster2. NGINX Ingress Controller watches Ingress objects via Kubernetes API server watch stream3. Controller translates Ingress rules into nginx.conf: server { server_name api.contoso.com; location /v1 { proxy_pass http://api-service.production.svc.cluster.local:8080; } }4. Controller hot-reloads NGINX with new config (without dropping existing connections)5. Traffic arrives at NGINX pod → routes to upstream service
Q9. What is IngressClass and why was it introduced?
IngressClass was introduced in Kubernetes 1.18 to allow multiple ingress controllers in the same cluster, each handling different Ingress resources:
# Define an IngressClassapiVersion: networking.k8s.io/v1kind: IngressClassmetadata: name: nginx-internal annotations: ingressclass.kubernetes.io/is-default-class: "false"spec: controller: k8s.io/ingress-nginx---# Reference it in an Ingressspec: ingressClassName: nginx-internal # only nginx-internal controller handles this
Common multi-controller pattern:
nginx-external → handles public internet trafficnginx-internal → handles internal VPN-only trafficagic → handles Azure Application Gateway traffic
Q10. How do annotations work in Ingress and give examples?
Annotations configure controller-specific behaviour that the Ingress spec itself doesn’t support:
metadata: annotations: # NGINX — rewrite URL before forwarding nginx.ingress.kubernetes.io/rewrite-target: /$2 # NGINX — rate limiting nginx.ingress.kubernetes.io/limit-rps: "10" # NGINX — enable CORS nginx.ingress.kubernetes.io/enable-cors: "true" nginx.ingress.kubernetes.io/cors-allow-origin: "https://contoso.com" # NGINX — client body size limit nginx.ingress.kubernetes.io/proxy-body-size: "50m" # NGINX — connection timeout nginx.ingress.kubernetes.io/proxy-connect-timeout: "30" nginx.ingress.kubernetes.io/proxy-read-timeout: "60" # NGINX — sticky sessions nginx.ingress.kubernetes.io/affinity: "cookie" nginx.ingress.kubernetes.io/session-cookie-name: "route" # NGINX — whitelist specific IPs nginx.ingress.kubernetes.io/whitelist-source-range: "10.0.0.0/8" # cert-manager — auto issue TLS certificate cert-manager.io/cluster-issuer: "letsencrypt-prod"
Q11. What is the difference between NGINX Ingress Controller and AGIC (Azure Application Gateway Ingress Controller)?
| NGINX Ingress | AGIC | |
|---|---|---|
| Runs as | Pod inside cluster | Azure resource outside cluster |
| Load balancer | Service type LB in front | Azure Application Gateway |
| WAF | Manual config | Azure WAF built-in |
| TLS | cert-manager or manual | Azure-managed certs |
| Health probes | Internal | Azure LB health probes |
| Autoscaling | HPA on NGINX pods | App Gateway autoscales natively |
| Best for | Any cluster | AKS on Azure |
| ARO support | ✅ | Limited |
Section 3 — TLS and Security
Q12. How do you configure TLS termination in Ingress?
# Step 1: Create TLS secretkubectl create secret tls tls-contoso \ --cert=tls.crt \ --key=tls.key \ -n production# Step 2: Reference in Ingressspec: tls: - hosts: - app.contoso.com - api.contoso.com secretName: tls-contoso # must be in same namespace as Ingress rules: - host: app.contoso.com ...
TLS is terminated at the Ingress controller — traffic between the controller and backend pods travels unencrypted inside the cluster by default (unless you enable backend SSL).
Q13. How does cert-manager automate TLS certificate issuance?
# Install cert-manager, then create a ClusterIssuerapiVersion: cert-manager.io/v1kind: ClusterIssuermetadata: name: letsencrypt-prodspec: acme: server: https://acme-v02.api.letsencrypt.org/directory email: admin@contoso.com privateKeySecretRef: name: letsencrypt-prod-key solvers: - http01: ingress: class: nginx # cert-manager creates a temporary Ingress for ACME challenge---# Reference in Ingress — cert-manager auto-issues and renewsmetadata: annotations: cert-manager.io/cluster-issuer: "letsencrypt-prod"spec: tls: - hosts: - app.contoso.com secretName: tls-app-contoso # cert-manager creates this Secret automatically
cert-manager watches the Ingress → sees the annotation → calls Let’s Encrypt ACME API → completes HTTP-01 challenge → stores cert in the named Secret → auto-renews before expiry.
Q14. How do you enforce HTTPS redirect in Ingress?
metadata: annotations: # Force HTTP → HTTPS redirect (301) nginx.ingress.kubernetes.io/ssl-redirect: "true" nginx.ingress.kubernetes.io/force-ssl-redirect: "true" # Add HSTS header nginx.ingress.kubernetes.io/configuration-snippet: | add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
Q15. How do you implement authentication at the Ingress level?
# Basic authmetadata: annotations: nginx.ingress.kubernetes.io/auth-type: basic nginx.ingress.kubernetes.io/auth-secret: basic-auth-secret nginx.ingress.kubernetes.io/auth-realm: "Authentication Required"# External OAuth2 (with oauth2-proxy)metadata: annotations: nginx.ingress.kubernetes.io/auth-url: "http://oauth2-proxy.auth.svc.cluster.local/oauth2/auth" nginx.ingress.kubernetes.io/auth-signin: "https://auth.contoso.com/oauth2/start"# mTLS (client certificate authentication)metadata: annotations: nginx.ingress.kubernetes.io/auth-tls-secret: "production/ca-secret" nginx.ingress.kubernetes.io/auth-tls-verify-client: "on" nginx.ingress.kubernetes.io/auth-tls-verify-depth: "1"
Section 4 — Advanced Routing
Q16. How do you implement canary deployments with Ingress?
# Production Ingress (main traffic)apiVersion: networking.k8s.io/v1kind: Ingressmetadata: name: app-productionspec: rules: - host: app.contoso.com http: paths: - path: / pathType: Prefix backend: service: name: app-v1 port: number: 80---# Canary Ingress (10% of traffic)apiVersion: networking.k8s.io/v1kind: Ingressmetadata: name: app-canary annotations: nginx.ingress.kubernetes.io/canary: "true" nginx.ingress.kubernetes.io/canary-weight: "10" # 10% to v2spec: rules: - host: app.contoso.com http: paths: - path: / pathType: Prefix backend: service: name: app-v2 port: number: 80
Other canary strategies:
# Route by header — specific users get canarynginx.ingress.kubernetes.io/canary-by-header: "X-Canary"nginx.ingress.kubernetes.io/canary-by-header-value: "true"# Route by cookie — sticky canary for logged-in usersnginx.ingress.kubernetes.io/canary-by-cookie: "canary_user"
Q17. How do you configure rate limiting in Ingress?
metadata: annotations: # Limit requests per second per IP nginx.ingress.kubernetes.io/limit-rps: "10" # Limit connections per IP nginx.ingress.kubernetes.io/limit-connections: "5" # Limit requests per minute nginx.ingress.kubernetes.io/limit-rpm: "100" # Whitelist IPs from rate limiting nginx.ingress.kubernetes.io/limit-whitelist: "10.0.0.0/8,172.16.0.0/12" # Return 429 when rate limit exceeded (default is 503) nginx.ingress.kubernetes.io/limit-req-status-code: "429"
Q18. How does rewrite-target work and what is a common gotcha?
# Without capture group — rewrites entire pathmetadata: annotations: nginx.ingress.kubernetes.io/rewrite-target: /spec: rules: - host: contoso.com http: paths: - path: /api # Request: contoso.com/api/users # Forwarded as: backend/ ← loses /users# With capture group — preserves remainder of pathmetadata: annotations: nginx.ingress.kubernetes.io/rewrite-target: /$2spec: rules: - host: contoso.com http: paths: - path: /api(/|$)(.*) # capture group $2 pathType: ImplementationSpecific # Request: contoso.com/api/users # Forwarded as: backend/users ✅
Q19. What is the difference between Ingress and Gateway API?
Gateway API is the next generation of Kubernetes ingress — more expressive, role-oriented, and extensible:
| Feature | Ingress | Gateway API |
|---|---|---|
| API stability | Stable (v1) | Stable (v1 for core) |
| Role separation | Single resource | GatewayClass · Gateway · HTTPRoute |
| TCP/UDP routing | ❌ | ✅ TCPRoute · UDPRoute |
| Header manipulation | Annotation only | Native spec |
| Traffic weighting | Annotation only | Native spec |
| Multi-tenant | Difficult | Designed for it |
| TLS passthrough | Annotation | Native |
| Future direction | Maintenance mode | Active development |
# Gateway API exampleapiVersion: gateway.networking.k8s.io/v1kind: HTTPRoutemetadata: name: app-routespec: parentRefs: - name: prod-gateway hostnames: - app.contoso.com rules: - matches: - path: type: PathPrefix value: /api backendRefs: - name: api-service port: 8080 weight: 90 - name: api-service-v2 port: 8080 weight: 10 # native canary without annotations
Section 5 — Troubleshooting
Q20. A service is returning 404 from Ingress. How do you debug it?
# Step 1: Verify Ingress resource is created and has an addresskubectl get ingress -n production# NAME CLASS HOSTS ADDRESS PORTS AGE# my-ingress nginx app.contoso.com 20.x.x.x 80,443 5m# If ADDRESS is empty → controller not reconciling → check controller pods# Step 2: Describe Ingress — look for eventskubectl describe ingress my-ingress -n production# Events show: backend service not found, port mismatch, etc.# Step 3: Verify backend service exists and has endpointskubectl get svc api-service -n productionkubectl get endpoints api-service -n production# If endpoints are empty → no pods matching service selector# Step 4: Check service selector matches pod labelskubectl get pods -n production --show-labelskubectl get svc api-service -n production -o yaml | grep selector# Step 5: Check Ingress controller logskubectl logs -n ingress-nginx \ -l app.kubernetes.io/name=ingress-nginx \ --tail=100# Step 6: Verify IngressClass matches controllerkubectl get ingressclasskubectl get ingress my-ingress -o yaml | grep ingressClassName
Q21. Ingress is returning 502 Bad Gateway. What are the causes?
# 502 means Ingress reached the backend but got an error# Cause 1: Backend pod is crashingkubectl get pods -n productionkubectl logs <pod-name> -n production --previous# Cause 2: Port mismatch — Ingress port ≠ container portkubectl get ingress -o yaml # check backend portkubectl get svc api-service -o yaml # check targetPortkubectl get pods -o yaml | grep containerPort# Cause 3: Backend requires HTTPS but Ingress sending HTTPmetadata: annotations: nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" # add this# Cause 4: Upstream timeoutmetadata: annotations: nginx.ingress.kubernetes.io/proxy-read-timeout: "120" nginx.ingress.kubernetes.io/proxy-send-timeout: "120"# Cause 5: Pod not ready — readiness probe failingkubectl describe pod <pod-name> -n production# Check: Readiness probe failed
Q22. How does Ingress handle WebSocket connections?
# WebSockets require long-lived connections — default timeouts too shortmetadata: annotations: nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" nginx.ingress.kubernetes.io/proxy-send-timeout: "3600" # NGINX automatically detects Upgrade header and handles WebSocket # No additional annotation needed for basic WebSocket support# For sticky sessions (WebSocket clients must hit same pod) nginx.ingress.kubernetes.io/affinity: "cookie" nginx.ingress.kubernetes.io/session-cookie-name: "ws-route" nginx.ingress.kubernetes.io/session-cookie-hash: "sha1"
Q23. What happens when two Ingress resources define the same host and path?
Two Ingress resources both define: host: app.contoso.com path: /apiResult: NGINX Ingress uses the OLDER resource (by creation timestamp) The newer one is effectively ignoredBest practice: - Use a single Ingress per namespace for overlapping hosts - Or merge rules into one Ingress resource - NGINX logs a warning about duplicate pathCheck for conflicts: kubectl get ingress -A | grep app.contoso.com
Q24. How do you expose an Ingress controller in different environments?
# Cloud (AKS, EKS, GKE) — LoadBalancer service (most common)apiVersion: v1kind: Servicemetadata: name: ingress-nginx-controllerspec: type: LoadBalancer # cloud provider provisions LB + public IP ports: - port: 80 - port: 443# On-premises / bare metal — NodePortspec: type: NodePort ports: - port: 80 nodePort: 30080 - port: 443 nodePort: 30443# On-premises with MetalLB — LoadBalancer with IP pool# MetalLB assigns IP from your on-prem address pool# ARO / OpenShift — use Route instead of IngressapiVersion: route.openshift.io/v1kind: Routemetadata: name: my-appspec: host: app.cluster.aroapp.io to: kind: Service name: my-service tls: termination: edge
Quick-Reference Cheat Sheet
Ingress components: ingressClassName → which controller handles this tls → TLS secret reference rules → host + path → service mapping defaultBackend → catch-all for unmatched requests annotations → controller-specific configurationpathType values: Exact → /api matches only /api Prefix → /api matches /api, /api/v1, /api/users ImplementationSpecific → controller decides (regex, glob)Common debug commands: kubectl get ingress -A kubectl describe ingress <name> kubectl get endpoints <service> kubectl logs -n ingress-nginx -l app=ingress-nginxCommon HTTP errors: 404 → no matching rule / wrong path 502 → backend unreachable or crashing 503 → no healthy endpoints / rate limited 504 → backend timeout (increase proxy-read-timeout) SSL certificate error → cert not in same namespace as Ingress