Ingress and Gateway API
CKA Domain 3 — Kubernetes Ingress controller configuration and Gateway API concepts
Overview
Ingress is a Kubernetes API object that manages external access to cluster services, providing HTTP/HTTPS-based routing rules. Gateway API is the next-generation API gateway standard, designed to replace Ingress, offering more powerful routing capabilities and clearer separation of responsibilities.
1. Ingress
Ingress Controller vs Ingress Resource
- Ingress Controller: The actual running reverse proxy/load balancer (e.g., nginx-ingress, traefik, HAProxy)
- Ingress Resource: The YAML declaration that defines routing rules
Ingress resources only take effect after an Ingress controller is installed.
Installing an Ingress Controller
# NGINX Ingress Controller (minikube)
minikube addons enable ingress
# NGINX Ingress Controller (K8s cluster)
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.9.4/deploy/static/provider/cloud/deploy.yaml
Basic Ingress YAML
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: minimal-ingress
spec:
ingressClassName: nginx # K8s v1.18+, specifies the Ingress controller
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-service
port:
number: 80
pathType
| Type | Description |
|---|---|
Prefix | URL prefix-based matching (e.g., /api matches /api/users) |
Exact | Exact URL matching |
ImplementationSpecific | Matching logic defined by the Ingress controller |
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: path-type-ingress
spec:
ingressClassName: nginx
rules:
- host: example.com
http:
paths:
# Exact match
- path: /exact-match
pathType: Exact
backend:
service:
name: exact-svc
port:
number: 80
# Prefix match
- path: /api
pathType: Prefix
backend:
service:
name: api-svc
port:
number: 8080
Multi-Hostname Routing
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: multi-host-ingress
spec:
ingressClassName: nginx
rules:
- host: app1.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app1-svc
port:
number: 80
- host: app2.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app2-svc
port:
number: 80
Ingress Annotations
Annotations are used to configure specific behaviors of the Ingress controller:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: annotated-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: / # URL rewrite
nginx.ingress.kubernetes.io/ssl-redirect: "true" # SSL redirect
nginx.ingress.kubernetes.io/force-ssl-redirect: "false"
nginx.ingress.kubernetes.io/limit-rps: "10" # Rate limiting
spec:
ingressClassName: nginx
rules:
- host: myapp.example.com
http:
paths:
- path: /old-path
pathType: Prefix
backend:
service:
name: my-service
port:
number: 80
Common Annotations List:
| Annotation | Description |
|---|---|
nginx.ingress.kubernetes.io/rewrite-target | URL rewrite target |
nginx.ingress.kubernetes.io/ssl-redirect | Auto-redirect HTTP to HTTPS |
nginx.ingress.kubernetes.io/cors-enabled | Enable CORS |
nginx.ingress.kubernetes.io/limit-rps | Requests per second limit |
nginx.ingress.kubernetes.io/whitelist-source-range | IP whitelist |
TLS/SSL Configuration
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tls-ingress
spec:
ingressClassName: nginx
tls:
- hosts:
- secure.example.com
secretName: tls-secret # Created using kubectl create secret tls
rules:
- host: secure.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: secure-svc
port:
number: 443
# Create a TLS Secret
kubectl create secret tls tls-secret --cert=path/to/tls.crt --key=path/to/tls.key
Common Commands
# Create an Ingress
kubectl create ingress my-ingress --rule="example.com/=my-service:80"
# View Ingress
kubectl get ingress
kubectl get ingress -o wide
kubectl describe ingress my-ingress
# Edit Ingress
kubectl edit ingress my-ingress
2. Gateway API
Overview
Gateway API is an extension API for Kubernetes designed to significantly improve upon Ingress functionality. It introduces a new service networking model with key features including:
- Role-oriented design: Distinguishes between infrastructure providers, cluster administrators, and application developers
- Portability: A standard API across different implementations
- Greater expressiveness: Supports HTTP header matching, weighted routing, traffic splitting, and more
Core Resources
GatewayClass → Cluster-scoped gateway class definition
↓
Gateway → Gateway instance (similar to an Ingress controller instance)
↓
HTTPRoute → Routing rules (similar to Ingress rules)
Gateway Example
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: example-gateway-class
spec:
controllerName: example.io/gateway-controller
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: my-gateway
spec:
gatewayClassName: example-gateway-class
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: All
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: my-http-route
spec:
parentRefs:
- name: my-gateway
hostnames:
- example.com
rules:
- matches:
- path:
type: PathPrefix
value: /api
backendRefs:
- name: api-svc
port: 8080
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: web-svc
port: 80
Gateway API Features
# Traffic Splitting (Canary)
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: traffic-split
spec:
parentRefs:
- name: my-gateway
rules:
- backendRefs:
- name: stable-svc
port: 80
weight: 90
- name: canary-svc
port: 80
weight: 10
Ingress vs Gateway API Comparison
| Feature | Ingress | Gateway API |
|---|---|---|
| Standard specification | Kubernetes core API | Extension API (CRD) |
| Role separation | Single resource | Three-tier: GatewayClass / Gateway / Route |
| Protocol support | HTTP/HTTPS | HTTP, HTTPS, TCP, UDP, TLS |
| Traffic splitting | Annotation-dependent | Native support (weighted routing) |
| Header matching | Annotation-dependent | Native support |
| Cross-namespace | Not supported by default | Native support |
| Maturity | GA (stable) | Beta (v1.0+) |
🧪 Complete Hands-on Example: Configure Path-Based Ingress Routing
Scenario Description
Create two Deployments (app1 and app2), and use an Ingress with path prefixes (/app1 and /app2) to route traffic to different backend Services.
Prerequisites
- The cluster has the NGINX Ingress Controller installed (or minikube has the ingress addon enabled)
- kubectl is configured for cluster access
- The test machine can modify /etc/hosts or use curl --resolve
Steps
Step 1: Create app1 Deployment and its Service
# Create app1 Deployment (simulating a frontend application)
kubectl create deployment app1 --image=nginx:1.25 --replicas=2
# Expected output: deployment.apps/app1 created
# Customize app1's homepage content for easy differentiation
kubectl exec deployment/app1 -- sh -c 'echo "<h1>App 1</h1>" > /usr/share/nginx/html/index.html'
# Expected output: no errors
# Expose app1 as a ClusterIP Service
kubectl expose deployment app1 --name=app1-svc --port=80 --target-port=80
# Expected output: service/app1-svc exposed
Step 2: Create app2 Deployment and its Service
# Create app2 Deployment (simulating a backend API service)
kubectl create deployment app2 --image=nginx:1.25 --replicas=1
# Expected output: deployment.apps/app2 created
# Customize app2's homepage content
kubectl exec deployment/app2 -- sh -c 'echo "<h1>App 2</h1>" > /usr/share/nginx/html/index.html'
# Expected output: no errors
# Expose app2 as a ClusterIP Service
kubectl expose deployment app2 --name=app2-svc --port=80 --target-port=80
# Expected output: service/app2-svc exposed
# Confirm Services have been created
kubectl get svc app1-svc app2-svc
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# app1-svc ClusterIP 10.96.100.1 <none> 80/TCP 1m
# app2-svc ClusterIP 10.96.100.2 <none> 80/TCP 1m
Step 3: Create the Ingress resource
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: path-based-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: myapp.example.com
http:
paths:
- path: /app1
pathType: Prefix
backend:
service:
name: app1-svc
port:
number: 80
- path: /app2
pathType: Prefix
backend:
service:
name: app2-svc
port:
number: 80
EOF
# Expected output: ingress.networking.k8s.io/path-based-ingress created
kubectl get ingress path-based-ingress
# NAME CLASS HOSTS ADDRESS PORTS AGE
# path-based-ingress nginx myapp.example.com localhost 80 10s
Step 4: Configure local domain name resolution
# Get the IP exposed by the Ingress controller
# For minikube:
minikube ip
# Assume output: 192.168.49.2
# For kind or other clusters, get the node IP where the Ingress controller Pod is running:
kubectl get pods -n ingress-nginx -o wide
# Add hosts record (sudo required for Linux/macOS):
# echo "192.168.49.2 myapp.example.com" | sudo tee -a /etc/hosts
# For minikube, you can also use minikube tunnel (in a separate terminal):
# minikube tunnel
# Or use curl --resolve to avoid modifying hosts
INGRESS_IP=$(kubectl get ingress path-based-ingress -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "Ingress IP: $INGRESS_IP"
# If IP is empty, minikube may need minikube tunnel
Step 5: Verify path routing
# Test /app1 path using curl
curl -H "Host: myapp.example.com" http://localhost/app1
# Or if you already have the Ingress IP:
curl --resolve myapp.example.com:80:$INGRESS_IP http://myapp.example.com/app1
# Expected output: <h1>App 1</h1> (rewrite-target rewrites /app1 to /)
# Test /app2 path
curl --resolve myapp.example.com:80:$INGRESS_IP http://myapp.example.com/app2
# Expected output: <h1>App 2</h1>
# Test root path (should return 404 because no root path route is defined)
curl --resolve myapp.example.com:80:$INGRESS_IP http://myapp.example.com/
# Expected output: nginx 404 Not Found
Step 6: Compare with Gateway API format (bonus)
# View the equivalent Gateway API configuration (requires Gateway API CRDs installed)
cat <<EOF
# Equivalent HTTPRoute configuration in Gateway API:
# apiVersion: gateway.networking.k8s.io/v1
# kind: HTTPRoute
# metadata:
# name: app-routes
# spec:
# parentRefs:
# - name: my-gateway
# hostnames:
# - "myapp.example.com"
# rules:
# - matches:
# - path:
# type: PathPrefix
# value: /app1
# backendRefs:
# - name: app1-svc
# port: 80
# - matches:
# - path:
# type: PathPrefix
# value: /app2
# backendRefs:
# - name: app2-svc
# port: 80
EOF
Verification
# View Ingress details
kubectl describe ingress path-based-ingress
# Rules:
# Host Path Backends
# ---- ---- --------
# myapp.example.com
# /app1 app1-svc:80 (10.244.1.5:80,10.244.2.7:80)
# /app2 app2-svc:80 (10.244.3.9:80)
# View Ingress controller logs (confirm request routing)
kubectl logs -n ingress-nginx -l app.kubernetes.io/component=controller --tail=50 | grep -i "myapp.example.com"
# Clean up resources
kubectl delete ingress path-based-ingress
kubectl delete deployment app1 app2
kubectl delete svc app1-svc app2-svc
Exam Tips
-
The rewrite-target annotation is key:
nginx.ingress.kubernetes.io/rewrite-target: /rewrites the path prefix to/, otherwise the backend Pod receives the request path with the prefix still present -
pathType selection: Prefix matches by prefix (e.g., /api matches /api/users), Exact matches precisely
-
The Ingress controller must be installed first, otherwise the Ingress resource status stays
<pending>after creation -
In the CKA exam, usually use
kubectl create ingressfor quick creation, but the YAML approach is more controllable -
Before accessing Ingress, ensure network reachability (minikube:
minikube tunnelorkubectl port-forward) -
If you cannot modify /etc/hosts, use
curl --resolveorcurl -H "Host: ..."as an alternative -
https://kubernetes.io/docs/concepts/services-networking/ingress/
-
https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/
-
https://kubernetes.io/docs/tasks/access-application-cluster/ingress-minikube/
-
https://kubernetes.io/docs/concepts/services-networking/gateway/