πŸ“Œ CKA 2025 β€” Question 02

Migrate an existing web application from Ingress to Gateway API. HTTPS access must be maintained.

A GatewayClass named nginx is already installed in the cluster.

  1. Create a Gateway named web-gateway with hostname gateway.web.k8s.local, maintaining the existing TLS and listener configuration from the Ingress resource named web.

  2. Create an HTTPRoute named web-route with hostname gateway.web.k8s.local that maintains the same routing rules as the existing Ingress resource named web.

  3. Test with:

[candidate@cka2025] $ curl https://gateway.web.k8s.local

Finally, delete the existing Ingress resource named web.


βœ… Prerequisite

Run the following command on any Kubernetes cluster:

curl -sL https://raw.githubusercontent.com/ibtisam-iq/SilverKube/main/gateway-stack-installation.sh | bash

This will:

  1. Install Gateway API CRDs
  2. Install NGINX Gateway Fabric CRDs
  3. Deploy the NGINX Gateway Fabric controller (NodePort)

βœ… 1. Create TLS Certificate using OpenSSL

Generate self-signed cert

openssl req -x509 -nodes -days 365 \
  -newkey rsa:2048 \
  -keyout cert.key \
  -out cert.crt \
  -subj "/CN=web.k8s.local"

βœ… 2. Create TLS Secret

kubectl create secret tls web-tls \
  --cert=cert.crt \
  --key=cert.key \
  -n default

βœ… 3. Deployment, Service, Ingress

cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-deployment
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /usr/share/nginx/html
          name: html
      initContainers:
      - command:
        - sh
        - -c
        - echo 'love you my sweetheart, Ibtisam' > /html/index.html
        image: busybox:1.28
        name: init-container
        volumeMounts:
        - mountPath: /html
          name: html
      volumes:
      - emptyDir: {}
        name: html
---
apiVersion: v1
kind: Service
metadata:
  name: web-service
  namespace: default
spec:
  selector:
    app: web
  ports:
  - port: 80
    targetPort: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web
  namespace: default
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - web.k8s.local
    secretName: web-tls
  rules:
  - host: web.k8s.local
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 80
EOF

βœ… 4. Create Gateway (web-gateway)

⚠ Note: We are migrating from the Ingress’s TLS + hostname (web.k8s.local) TO the new Gateway’s hostname (gateway.web.k8s.local).

cat <<EOF | kubectl apply -f -
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: web-gateway
  namespace: default
spec:
  gatewayClassName: nginx
  listeners:
  - name: https
    protocol: HTTPS
    port: 443
    hostname: gateway.web.k8s.local
    tls:
      certificateRefs:
      - name: web-tls
EOF

βœ… 5. Create HTTPRoute (web-route)

Must match hostname: gateway.web.k8s.local

cat <<EOF | kubectl apply -f -
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: web-route
  namespace: default
spec:
  parentRefs:
  - name: web-gateway
  hostnames:
  - gateway.web.k8s.local
  rules:
  - backendRefs:
    - name: web-service
      port: 80
EOF

βœ… 6. Delete old Ingress

kubectl delete ingress web -n default

controlplane ~ ➜  k get no controlplane -owide
NAME           STATUS   ROLES           AGE   VERSION   INTERNAL-IP       
controlplane   Ready    control-plane   77m   v1.34.0   192.168.121.233

controlplane ~ ➜  echo "192.168.121.233 web.k8s.local" >> /etc/hosts 

controlplane ~ ➜  echo "192.168.121.233 gateway.web.k8s.local" >> /etc/hosts 

controlplane ~ ➜  curl -sL https://raw.githubusercontent.com/ibtisam-iq/SilverKube/main/gateway-stack-installation.sh | bash

===============================================
 βœ” All components installed successfully! 
===============================================

controlplane ~ ➜  k get deploy
NAME             READY   UP-TO-DATE   AVAILABLE   AGE
web-deployment   1/1     1            1           12s

controlplane ~ ➜  k get svc web-service 
NAME          TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
web-service   ClusterIP   172.20.246.187   <none>        80/TCP    11m

controlplane ~ ➜  openssl req -x509 -nodes -days 365 \
  -newkey rsa:2048 \
  -keyout cert.key \
  -out cert.crt \
  -subj "/CN=gateway.web.k8s.local"

controlplane ~ ➜  kubectl create secret tls web-tls \
  --cert=cert.crt \
  --key=cert.key \
  -n default
secret/web-tls created

controlplane ~ ➜  k get ingress web 
NAME   CLASS   HOSTS           ADDRESS   PORTS     AGE
web    nginx   web.k8s.local             80, 443   22s

controlplane ~ ➜  k get svc -n ingress-nginx ingress-nginx-controller
NAME                       TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx-controller   LoadBalancer   172.20.211.75   <pending>     80:32573/TCP,443:32252/TCP   25m

controlplane ~ ➜  curl https://web.k8s.local:32252 -k
love you my sweetheart, Ibtisam

controlplane ~ ➜  k get gateway
NAME          CLASS   ADDRESS   PROGRAMMED   AGE
web-gateway   nginx             True         6m11s

controlplane ~ ➜  k get gateway web-gateway -o jsonpath={.status.listeners[0].attachedRoutes}
1

controlplane ~ ➜  k get httproute web-route 
NAME        HOSTNAMES                   AGE
web-route   ["gateway.web.k8s.local"]   13m

controlplane ~ ➜  k get svc -n nginx-gateway nginx-gateway 
NAME            TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
nginx-gateway   NodePort   172.20.124.152   <none>        80:31391/TCP,443:32237/TCP   10m

controlplane ~ ➜  curl https://gateway.web.k8s.local:32237 -k
love you my sweetheart, Ibtisam

controlplane ~ ➜  k delete ingress web 
ingress.networking.k8s.io "web" deleted from default namespace

controlplane ~ ➜  curl https://web.k8s.local:32252 -k
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx</center>
</body>
</html>

controlplane ~ ➜  curl https://gateway.web.k8s.local:32237 -k
love you my sweetheart, Ibtisam