Ingress and Gateway API: Modern Traffic Management¶
In production Kubernetes environments, managing external access to your services is critical. While Services handle internal cluster networking, Ingress provides sophisticated HTTP/HTTPS routing from the outside world. This guide covers everything you need to know for the CKA exam and production deployments, including the modern Gateway API that's reshaping Kubernetes networking in 2025.
Why Ingress Matters¶
Imagine running 50 microservices in your cluster. Without Ingress, you'd need 50 LoadBalancer Services—each with its own expensive cloud load balancer and public IP address. That's not just costly; it's operationally nightmarish.
Ingress solves this by providing:
- Cost efficiency: One load balancer for multiple services
- Advanced routing: Path-based, host-based, header-based routing
- SSL/TLS termination: Centralized certificate management
- Name-based virtual hosting: Multiple domains on one IP
- Protocol support: HTTP, HTTPS, WebSocket, gRPC
For the CKA exam, you'll need to demonstrate hands-on competency with Ingress resources, troubleshoot misconfigurations, and understand controller selection. In production, mastering Ingress means the difference between elegant traffic management and a tangled mess of load balancers.
The landscape is evolving. While traditional Ingress remains the standard (and what's tested on the CKA), the Gateway API represents Kubernetes networking's future—offering role-oriented design, better extensibility, and more expressive routing rules. Understanding both is essential for modern Kubernetes practitioners.
graph TB
subgraph "External Traffic"
Client[Client Browser]
end
subgraph "Kubernetes Cluster"
LB[Cloud Load Balancer<br/>External IP: 203.0.113.10]
subgraph "Ingress Controller Pod"
IC[NGINX/Traefik/Contour<br/>Processes routing rules]
end
subgraph "Ingress Resources"
I1[Ingress: api.example.com]
I2[Ingress: app.example.com]
end
subgraph "Backend Services"
S1[Service: api-service<br/>ClusterIP: 10.96.0.10]
S2[Service: app-service<br/>ClusterIP: 10.96.0.20]
P1[Pod: api-v1<br/>10.244.1.5]
P2[Pod: api-v2<br/>10.244.2.8]
P3[Pod: app-frontend<br/>10.244.1.12]
end
end
Client -->|HTTPS Request<br/>Host: api.example.com| LB
LB -->|Forwards to<br/>NodePort/HostPort| IC
IC -.->|Reads rules| I1
IC -.->|Reads rules| I2
IC -->|Routes based on<br/>Host header| S1
IC -->|Routes based on<br/>Host header| S2
S1 --> P1
S1 --> P2
S2 --> P3
style IC fill:#e1f5ff
style I1 fill:#fff4e1
style I2 fill:#fff4e1
style LB fill:#ffe1e1
Ingress Fundamentals¶
What is Ingress?¶
Ingress is an API object that defines rules for routing external HTTP(S) traffic to services inside your cluster. Think of it as a sophisticated reverse proxy configuration expressed as Kubernetes YAML. Unlike Services which operate at Layer 4 (TCP/UDP), Ingress works at Layer 7 (HTTP/HTTPS), giving you application-aware routing.
The Two-Part Architecture:
- Ingress Resource: The YAML configuration defining routing rules
- Ingress Controller: The actual software that reads these resources and implements the routing logic
This separation is crucial—you can have dozens of Ingress resources, but they do nothing without a controller to act on them.
Ingress Controller Architecture¶
An Ingress controller is essentially three components working together:
graph LR
subgraph "Ingress Controller Components"
W[Watcher<br/>Monitors Ingress resources]
C[Configuration Generator<br/>Translates to proxy config]
P[Proxy Server<br/>NGINX/Envoy/HAProxy]
end
subgraph "Kubernetes API"
API[API Server<br/>Ingress resources]
end
subgraph "Traffic Flow"
Traffic[External Traffic] --> P
P --> Backend[Backend Services]
end
API -.->|Watch events| W
W -->|Resource changes| C
C -->|Generate config| P
P -.->|Reload| P
style W fill:#e1f5ff
style C fill:#ffe1e1
style P fill:#e1ffe1
How it works:
- Watcher continuously monitors the Kubernetes API for Ingress resource changes
- Configuration Generator translates Ingress rules into proxy-specific config (NGINX conf, Envoy YAML, etc.)
- Proxy Server reloads configuration and routes traffic accordingly
Popular Controllers (2025 Comparison)¶
| Controller | Best For | Strengths | Considerations |
|---|---|---|---|
| NGINX Ingress | General production use | Battle-tested, extensive features, large community | Configuration via annotations can be complex |
| Traefik | Dynamic environments | Auto-discovery, native Let's Encrypt, beautiful UI | Higher resource usage |
| Contour | Enterprise, security-focused | Envoy-based, graceful shutdowns, Gateway API support | Steeper learning curve |
| HAProxy Ingress | High performance | Excellent performance, advanced load balancing | Smaller community than NGINX |
2025 Recommendation for CKA Prep:
Use NGINX Ingress Controller for exam preparation. It's the de facto standard, well-documented, and most likely to match exam scenarios. Install with:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.11.2/deploy/static/provider/cloud/deploy.yaml
Production Recommendation:
Consider Contour if you're investing in Gateway API (it has excellent support), or stick with NGINX for mature, stable deployments with extensive community resources.
Ingress Resources¶
Basic Structure¶
Every Ingress resource follows this pattern:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
namespace: production
annotations:
# Controller-specific configuration
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx # Critical: specifies which controller handles this
rules:
- host: api.example.com
http:
paths:
- path: /v1
pathType: Prefix
backend:
service:
name: api-v1-service
port:
number: 8080
Key Fields:
- ingressClassName: Specifies which controller processes this Ingress (required in v1)
- rules: Array of routing rules
- host: Optional hostname for virtual hosting
- paths: Array of path-based routing rules
- pathType:
Exact,Prefix, orImplementationSpecific
Path-Based Routing¶
Route different paths to different services—perfect for microservices architectures:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: path-routing
namespace: default
spec:
ingressClassName: nginx
rules:
- host: shop.example.com
http:
paths:
# Product catalog microservice
- path: /products
pathType: Prefix
backend:
service:
name: catalog-service
port:
number: 80
# Shopping cart microservice
- path: /cart
pathType: Prefix
backend:
service:
name: cart-service
port:
number: 8080
# Exact match for homepage
- path: /
pathType: Exact
backend:
service:
name: frontend-service
port:
number: 3000
PathType Semantics:
- Exact: Matches the URL path exactly (case-sensitive)
- Prefix: Matches based on URL path prefix split by
/ - ImplementationSpecific: Interpretation depends on IngressClass
CKA Tip: Understand prefix matching behavior. /foo matches /foo, /foo/, and /foo/bar, but not /foobar.
Host-Based Routing¶
Single IP address, multiple domains—critical for multi-tenant environments:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: multi-tenant
namespace: saas-platform
spec:
ingressClassName: nginx
rules:
# Customer A's subdomain
- host: acme.platform.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: acme-tenant-service
port:
number: 80
# Customer B's subdomain
- host: globex.platform.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: globex-tenant-service
port:
number: 80
# Default backend for unmatched hosts
defaultBackend:
service:
name: default-404-service
port:
number: 80
TLS/SSL Termination¶
Production traffic must be encrypted. Ingress handles TLS termination at the edge:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tls-ingress
namespace: production
annotations:
# Force HTTPS redirect
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
# Modern TLS configuration
nginx.ingress.kubernetes.io/ssl-protocols: "TLSv1.2 TLSv1.3"
spec:
ingressClassName: nginx
tls:
# TLS configuration
- hosts:
- secure.example.com
- api.example.com
secretName: example-tls-cert # Secret containing tls.crt and tls.key
rules:
- host: secure.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: secure-service
port:
number: 443
Creating the TLS Secret:
# From certificate files
kubectl create secret tls example-tls-cert \
--cert=path/to/tls.crt \
--key=path/to/tls.key \
--namespace=production
# Using cert-manager (recommended for production)
# See Advanced Patterns section
sequenceDiagram
participant Client
participant LB as Load Balancer
participant IC as Ingress Controller
participant Secret as TLS Secret
participant Backend as Backend Pod
Note over Client,Backend: TLS Termination Flow
Client->>LB: HTTPS Request (encrypted)
LB->>IC: Forward to Ingress Controller
IC->>Secret: Read TLS certificate
Secret-->>IC: tls.crt + tls.key
IC->>IC: TLS handshake<br/>Decrypt request
Note over IC: Certificate validated<br/>Traffic decrypted
IC->>Backend: HTTP Request (plain text)<br/>Internal cluster communication
Backend-->>IC: HTTP Response
IC->>IC: Encrypt response
IC-->>LB: HTTPS Response (encrypted)
LB-->>Client: HTTPS Response (encrypted)
style IC fill:#e1f5ff
style Secret fill:#ffe1e1
Controller Annotations¶
Annotations provide controller-specific configuration beyond the Ingress spec. Here are production-critical NGINX examples:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: advanced-config
annotations:
# Rate limiting (DDoS protection)
nginx.ingress.kubernetes.io/limit-rps: "100"
# Connection limits
nginx.ingress.kubernetes.io/limit-connections: "10"
# Request body size (file uploads)
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
# Timeouts
nginx.ingress.kubernetes.io/proxy-connect-timeout: "60"
nginx.ingress.kubernetes.io/proxy-send-timeout: "60"
nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
# CORS headers
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-origin: "https://app.example.com"
# Sticky sessions (affinity)
nginx.ingress.kubernetes.io/affinity: "cookie"
nginx.ingress.kubernetes.io/session-cookie-name: "route"
# Custom error pages
nginx.ingress.kubernetes.io/custom-http-errors: "404,503"
nginx.ingress.kubernetes.io/default-backend: "custom-error-service"
spec:
ingressClassName: nginx
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service
port:
number: 8080
CKA Exam Warning: Annotations are controller-specific. NGINX annotations won't work with Traefik. Always check documentation for your chosen controller.
Gateway API: The Future of Kubernetes Networking¶
Why Gateway API Exists¶
Traditional Ingress has served Kubernetes well, but it has fundamental limitations:
Ingress Limitations:
- Annotations hell: Controller-specific configuration scattered across annotations
- Limited expressiveness: No header matching, query parameter routing, traffic splitting
- Single role design: No separation between cluster operators and application developers
- Protocol limitations: Primarily HTTP/HTTPS, limited gRPC/TCP support
Gateway API Solutions:
- Role-oriented: Separate resources for infrastructure (GatewayClass, Gateway) and application routing (HTTPRoute, TCPRoute)
- Expressive: First-class support for header matching, traffic splitting, redirects, rewrites
- Extensible: Policy attachment mechanism instead of annotations
- Protocol-rich: Native support for HTTP, HTTPS, gRPC, TCP, TLS, UDP
As of 2025, Gateway API v1.4.0 is production-ready and rapidly gaining adoption. It's not yet on the CKA exam, but forward-thinking practitioners should learn it now.
Gateway API Resource Hierarchy¶
graph TB
subgraph "Infrastructure Resources (Cluster Operator)"
GC[GatewayClass<br/>Cluster-scoped<br/>Controller specification]
G[Gateway<br/>Namespace-scoped<br/>Load balancer config]
end
subgraph "Routing Resources (Application Developer)"
HR[HTTPRoute<br/>HTTP/HTTPS routing rules]
GR[GRPCRoute<br/>gRPC-specific routing]
TR[TCPRoute<br/>TCP routing rules]
UR[UDPRoute<br/>UDP routing rules]
end
subgraph "Policy Resources (Security/Operations)"
BP[BackendPolicy<br/>Retry, timeout, circuit breaking]
TP[TimeoutPolicy<br/>Request/idle timeouts]
RP[RateLimitPolicy<br/>Traffic shaping]
end
GC -->|Defines controller| G
G -->|Attaches to| HR
G -->|Attaches to| GR
G -->|Attaches to| TR
G -->|Attaches to| UR
HR -.->|Policy attachment| BP
HR -.->|Policy attachment| TP
HR -.->|Policy attachment| RP
style GC fill:#ffe1e1
style G fill:#e1f5ff
style HR fill:#e1ffe1
style BP fill:#fff4e1
Core Resources¶
1. GatewayClass (Cluster Operator)
Defines which controller implementation to use—similar to IngressClass but more powerful:
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: contour-gateway
spec:
controllerName: projectcontour.io/gateway-controller
parametersRef:
group: projectcontour.io
kind: ContourDeployment
name: contour-gateway-config
2. Gateway (Platform Team)
Represents the load balancer configuration—infrastructure that application teams will use:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: production-gateway
namespace: infrastructure
spec:
gatewayClassName: contour-gateway
listeners:
# HTTPS listener
- name: https
protocol: HTTPS
port: 443
hostname: "*.example.com"
tls:
mode: Terminate
certificateRefs:
- kind: Secret
name: wildcard-tls-cert
allowedRoutes:
namespaces:
from: All # Allow routes from any namespace
# HTTP listener (redirect to HTTPS)
- name: http
protocol: HTTP
port: 80
hostname: "*.example.com"
allowedRoutes:
namespaces:
from: All
3. HTTPRoute (Application Developers)
Defines HTTP routing rules—what application teams interact with:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: api-route
namespace: production
spec:
parentRefs:
- name: production-gateway
namespace: infrastructure
hostnames:
- api.example.com
rules:
# Header-based routing
- matches:
- headers:
- name: X-API-Version
value: v2
backendRefs:
- name: api-v2-service
port: 8080
# Path-based routing with weight (traffic splitting)
- matches:
- path:
type: PathPrefix
value: /users
backendRefs:
- name: users-v1-service
port: 80
weight: 90 # 90% of traffic
- name: users-v2-service
port: 80
weight: 10 # 10% of traffic (canary)
# Query parameter matching
- matches:
- queryParams:
- name: beta
value: "true"
backendRefs:
- name: beta-service
port: 8080
Advantages Over Ingress¶
| Capability | Ingress | Gateway API |
|---|---|---|
| Role separation | No | Yes (GatewayClass/Gateway vs Routes) |
| Header matching | Via annotations | Native in HTTPRoute |
| Traffic splitting | Via annotations | Native with weights |
| Query parameters | Not supported | Native matching |
| Cross-namespace routing | Limited | First-class support |
| Retry/timeout policies | Via annotations | Separate policy resources |
| Protocol support | HTTP/HTTPS | HTTP, HTTPS, gRPC, TCP, UDP, TLS |
| Redirect/rewrite | Via annotations | Native in rules |
Real-World Example:
# Gateway API: Native canary deployment
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: canary-deployment
spec:
parentRefs:
- name: production-gateway
rules:
- backendRefs:
- name: stable-service
port: 80
weight: 95 # 95% to stable
- name: canary-service
port: 80
weight: 5 # 5% to canary
# Ingress: Requires complex annotations
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: canary-deployment
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "5"
spec:
# ... rest of configuration
Migration Strategies¶
1. Parallel Adoption (Recommended)
Run Ingress and Gateway API side-by-side:
# Install Gateway API CRDs
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.4.0/standard-install.yaml
# Install Contour Gateway (excellent Gateway API support)
kubectl apply -f https://projectcontour.io/quickstart/contour-gateway.yaml
# Migrate services incrementally
# - New services use Gateway API
# - Existing services remain on Ingress
# - Migrate critical services last
2. Testing Strategy
# Create test Gateway for validation
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: test-gateway
namespace: testing
spec:
gatewayClassName: contour-gateway
listeners:
- name: http
protocol: HTTP
port: 8080 # Different port to avoid conflicts
allowedRoutes:
namespaces:
from: Same
---
# Test HTTPRoute
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: test-route
namespace: testing
spec:
parentRefs:
- name: test-gateway
rules:
- backendRefs:
- name: test-service
port: 80
3. Production Cutover
Once validated:
- Deploy Gateway resource in production namespace
- Create HTTPRoutes for all services
- Update DNS to point to new Gateway load balancer IP
- Monitor traffic carefully (use weights for gradual shift)
- Deprecate Ingress resources after validation period
2025 Maturity Status¶
Gateway API v1.4.0 (Current):
- ✅ GA: GatewayClass, Gateway, HTTPRoute
- ✅ Beta: GRPCRoute, ReferenceGrant
- ✅ Alpha: TCPRoute, UDPRoute, TLSRoute, BackendTLSPolicy
Production-Ready Controllers (2025):
| Controller | Gateway API Support | Maturity |
|---|---|---|
| Contour | v1.4.0, excellent | Production-ready |
| Istio | v1.4.0, comprehensive | Production-ready |
| NGINX Gateway Fabric | v1.4.0, growing | Production-ready |
| Envoy Gateway | v1.4.0, native | Production-ready |
| Traefik | v1.4.0, mature | Production-ready |
Recommendation: Gateway API is ready for production in 2025. If starting new projects, prefer Gateway API over traditional Ingress.
Advanced Patterns¶
Path Rewriting¶
Transform incoming paths before forwarding to backends:
# NGINX Ingress: Annotation-based
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: path-rewrite
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
ingressClassName: nginx
rules:
- host: api.example.com
http:
paths:
# /api/users -> /users
- path: /api(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: backend-service
port:
number: 8080
# Gateway API: Native support
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: path-rewrite
spec:
parentRefs:
- name: production-gateway
rules:
- matches:
- path:
type: PathPrefix
value: /api
filters:
- type: URLRewrite
urlRewrite:
path:
type: ReplacePrefixMatch
replacePrefixMatch: /
backendRefs:
- name: backend-service
port: 8080
Traffic Splitting (Canary Deployments)¶
Gradually shift traffic to new versions:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: canary-rollout
namespace: production
spec:
parentRefs:
- name: production-gateway
hostnames:
- shop.example.com
rules:
- backendRefs:
# Stable version (90%)
- name: shop-v1
port: 80
weight: 90
# Canary version (10%)
- name: shop-v2
port: 80
weight: 10
---
# Progressive rollout plan:
# Week 1: 90/10 split
# Week 2: 75/25 split (update weights)
# Week 3: 50/50 split
# Week 4: 0/100 split (full cutover)
# Week 5: Remove shop-v1 service
Header Manipulation¶
Add, modify, or remove headers:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: header-manipulation
spec:
parentRefs:
- name: production-gateway
rules:
- matches:
- path:
type: PathPrefix
value: /api
filters:
# Add custom headers
- type: RequestHeaderModifier
requestHeaderModifier:
add:
- name: X-Request-Source
value: gateway-api
- name: X-Forwarded-Proto
value: https
# Remove headers
remove:
- X-Internal-Token
# Response headers
- type: ResponseHeaderModifier
responseHeaderModifier:
add:
- name: X-Cache-Status
value: MISS
- name: Strict-Transport-Security
value: max-age=31536000; includeSubDomains
backendRefs:
- name: api-service
port: 8080
Rate Limiting¶
Protect backends from traffic spikes:
# NGINX Ingress: Annotation-based
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: rate-limited
annotations:
# 10 requests per second per IP
nginx.ingress.kubernetes.io/limit-rps: "10"
# Burst capacity
nginx.ingress.kubernetes.io/limit-burst-multiplier: "5"
# Connection limits
nginx.ingress.kubernetes.io/limit-connections: "20"
# Custom error response
nginx.ingress.kubernetes.io/limit-rate-status-code: "429"
spec:
ingressClassName: nginx
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service
port:
number: 8080
For Gateway API, rate limiting is typically implemented via policy attachment (implementation-specific):
# Example: Contour BackendPolicy (implementation-specific)
apiVersion: projectcontour.io/v1alpha1
kind: RateLimitPolicy
metadata:
name: api-rate-limit
spec:
targetRef:
group: gateway.networking.k8s.io
kind: HTTPRoute
name: api-route
rateLimits:
- limit: 100
unit: minute
local:
type: PerIP
cert-manager Integration¶
Automate TLS certificate management:
# Install cert-manager
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.15.0/cert-manager.yaml
---
# Create ClusterIssuer for Let's Encrypt
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: admin@example.com
privateKeySecretRef:
name: letsencrypt-prod-key
solvers:
- http01:
ingress:
ingressClassName: nginx
---
# Ingress with automatic certificate
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: auto-tls
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
ingressClassName: nginx
tls:
- hosts:
- secure.example.com
secretName: secure-example-tls # cert-manager creates this automatically
rules:
- host: secure.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80
Certificate Lifecycle:
- cert-manager watches Ingress resources
- Detects
cert-manager.io/cluster-issuerannotation - Initiates ACME challenge with Let's Encrypt
- Creates temporary Ingress for HTTP-01 challenge
- Obtains certificate and stores in Secret
- Automatically renews 30 days before expiration
graph TB
subgraph "cert-manager Automation"
CM[cert-manager Controller]
CI[ClusterIssuer<br/>Let's Encrypt config]
end
subgraph "Ingress Resource"
I[Ingress with annotation<br/>cert-manager.io/cluster-issuer]
end
subgraph "ACME Challenge"
LE[Let's Encrypt CA]
Challenge[HTTP-01 Challenge<br/>Temporary Ingress]
end
subgraph "Certificate Storage"
Secret[Secret<br/>tls.crt + tls.key]
end
subgraph "Renewal Process"
Renewal[Auto-renewal<br/>30 days before expiry]
end
I -->|Watches| CM
CM -.->|Uses| CI
CM -->|Initiates| Challenge
Challenge -->|Requests cert| LE
LE -->|Validates & issues| CM
CM -->|Creates/updates| Secret
Secret -->|Used by| I
CM -->|Monitors expiry| Renewal
Renewal -.->|Triggers| Challenge
style CM fill:#e1f5ff
style Challenge fill:#ffe1e1
style Secret fill:#e1ffe1
CKA Exam Skills¶
Creating Ingress Imperatively¶
The CKA is a hands-on performance exam. Speed matters. Here's how to create Ingress resources quickly:
# Basic Ingress (doesn't exist in kubectl create, use dry-run)
kubectl create ingress simple-ingress \
--rule="example.com/path*=service:80" \
--dry-run=client -o yaml > ingress.yaml
# Edit and apply
vim ingress.yaml # Add ingressClassName: nginx
kubectl apply -f ingress.yaml
# Faster: Use kubectl run with generator (legacy but useful)
kubectl create ingress api-ingress \
--class=nginx \
--rule="api.example.com/v1*=api-svc:8080" \
--rule="api.example.com/v2*=api-v2-svc:8080"
# Multiple hosts
kubectl create ingress multi-host \
--class=nginx \
--rule="app1.example.com/*=app1-svc:80" \
--rule="app2.example.com/*=app2-svc:80"
# With TLS
kubectl create ingress tls-ingress \
--class=nginx \
--rule="secure.example.com/*=web-svc:443,tls=secure-tls-secret"
Exam Tip: Practice these commands repeatedly. In the exam, you can't afford to write 40 lines of YAML for a simple Ingress.
Troubleshooting Workflow¶
When Ingress isn't working, follow this systematic approach:
# 1. Verify Ingress controller is running
kubectl get pods -n ingress-nginx
# Should show: ingress-nginx-controller-xxx Running
# 2. Check Ingress resource exists and is valid
kubectl get ingress -A
kubectl describe ingress <name> -n <namespace>
# Look for: Address field populated, Events for errors
# 3. Verify IngressClass configuration
kubectl get ingressclass
# Should match spec.ingressClassName in your Ingress
# 4. Check backend Service exists
kubectl get svc <service-name> -n <namespace>
# Verify port matches Ingress backend port
# 5. Test backend Service directly (bypass Ingress)
kubectl run test-pod --image=curlimages/curl -it --rm -- \
curl http://<service-name>.<namespace>.svc.cluster.local:<port>
# If this fails, problem is backend, not Ingress
# 6. Check controller logs
kubectl logs -n ingress-nginx deployment/ingress-nginx-controller --tail=50
# Look for: Configuration errors, backend sync issues
# 7. Verify DNS/hostname resolution
kubectl run test-dns --image=busybox -it --rm -- nslookup <hostname>
# 8. Test from within cluster
kubectl run test-curl --image=curlimages/curl -it --rm -- \
curl -H "Host: example.com" http://<ingress-controller-service-ip>
# 9. Check Ingress controller Service
kubectl get svc -n ingress-nginx
# Type should be LoadBalancer or NodePort
# EXTERNAL-IP should be assigned (if LoadBalancer)
Common Misconfigurations¶
1. Missing IngressClass
# ❌ WRONG: No ingressClassName specified
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: broken-ingress
spec:
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-svc
port:
number: 80
# ✅ CORRECT: Explicitly set ingressClassName
spec:
ingressClassName: nginx # Critical in v1 API
rules:
# ... rest of spec
Symptom: Ingress exists but no Address assigned, controller ignores it.
2. Wrong PathType
# ❌ WRONG: PathType doesn't match intent
spec:
rules:
- http:
paths:
- path: /api
pathType: Exact # Only matches /api, not /api/users
backend:
service:
name: api-svc
port:
number: 8080
# ✅ CORRECT: Use Prefix for path hierarchies
- path: /api
pathType: Prefix # Matches /api, /api/, /api/users, etc.
Symptom: 404 errors for valid paths.
3. Service Port Mismatch
# Service definition
apiVersion: v1
kind: Service
metadata:
name: web-svc
spec:
ports:
- port: 8080 # Service port
targetPort: 80 # Container port
---
# ❌ WRONG: Using targetPort in Ingress
spec:
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-svc
port:
number: 80 # WRONG: Should be 8080 (Service port)
# ✅ CORRECT: Use Service port, not targetPort
port:
number: 8080 # Matches Service spec.ports[0].port
Symptom: 503 Service Temporarily Unavailable.
4. Namespace Confusion
# ❌ WRONG: Ingress in different namespace than Service
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: cross-namespace
namespace: default # Ingress is here
spec:
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-svc # Service is in 'production' namespace
port:
number: 80
# ✅ CORRECT: Ingress must be in same namespace as Service
metadata:
namespace: production # Match Service namespace
Symptom: Backend service not found errors.
Fast Debugging Techniques¶
Technique 1: Quick validation pod
# Create debug pod with networking tools
kubectl run debug --image=nicolaka/netshoot -it --rm -- bash
# Inside pod:
# Test Service directly
curl http://api-svc.production.svc.cluster.local:8080
# Test Ingress controller
curl -H "Host: api.example.com" http://<ingress-controller-ip>
# DNS resolution
nslookup api.example.com
Technique 2: Controller dry-run
# Check what controller would generate (NGINX)
kubectl exec -n ingress-nginx deployment/ingress-nginx-controller -- \
cat /etc/nginx/nginx.conf | grep -A 20 "server_name example.com"
Technique 3: Event watching
# Watch Ingress events in real-time
kubectl get events -n production --watch | grep ingress
# Filter for errors
kubectl get events -n production --field-selector type=Warning
Technique 4: Compare working vs broken
# Export working Ingress
kubectl get ingress working-ingress -o yaml > working.yaml
# Export broken Ingress
kubectl get ingress broken-ingress -o yaml > broken.yaml
# Compare
diff working.yaml broken.yaml
Conclusion¶
Mastering Ingress and Gateway API is essential for production Kubernetes operations and CKA exam success. Here's your action plan:
For CKA Exam Preparation:
- Practice creating Ingress resources imperatively with
kubectl create ingress - Master the troubleshooting workflow—it's predictable and systematic
- Understand PathType semantics (Exact vs Prefix)
- Know how to configure TLS with Secrets
- Practice with NGINX Ingress Controller (most common in exams)
For Production Systems:
- Use cert-manager for automated TLS certificate management
- Implement rate limiting and request timeouts via annotations
- Monitor controller logs and metrics
- Consider Gateway API for new projects—it's the future
- Separate infrastructure (Gateway) from application routing (HTTPRoute)
Migration Path:
- 2025-2026: Run Ingress and Gateway API in parallel
- 2026+: Migrate to Gateway API as primary routing mechanism
- Long-term: Gateway API will likely supersede Ingress in Kubernetes exams
The networking landscape is evolving, but the fundamentals remain: understand routing semantics, master troubleshooting, and build with production resilience in mind. Whether you're preparing for the CKA or architecting enterprise systems, these skills are your foundation.
Now go create some Ingress resources, break them, fix them, and build confidence through hands-on practice. That's how mastery happens.
Next in the CKA series: Network Policies and CNI Plugins—securing pod-to-pod communication and understanding cluster networking foundations.