Qingular

Ingress and Gateway API

·CKAk8sPractice

CKA Domain 3 — Kubernetes Ingress controller configuration and Gateway API concepts

← Back to CKA Practice Index

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

TypeDescription
PrefixURL prefix-based matching (e.g., /api matches /api/users)
ExactExact URL matching
ImplementationSpecificMatching 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:

AnnotationDescription
nginx.ingress.kubernetes.io/rewrite-targetURL rewrite target
nginx.ingress.kubernetes.io/ssl-redirectAuto-redirect HTTP to HTTPS
nginx.ingress.kubernetes.io/cors-enabledEnable CORS
nginx.ingress.kubernetes.io/limit-rpsRequests per second limit
nginx.ingress.kubernetes.io/whitelist-source-rangeIP 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

FeatureIngressGateway API
Standard specificationKubernetes core APIExtension API (CRD)
Role separationSingle resourceThree-tier: GatewayClass / Gateway / Route
Protocol supportHTTP/HTTPSHTTP, HTTPS, TCP, UDP, TLS
Traffic splittingAnnotation-dependentNative support (weighted routing)
Header matchingAnnotation-dependentNative support
Cross-namespaceNot supported by defaultNative support
MaturityGA (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