DEV Community

The Cyber Sidekick
The Cyber Sidekick

Posted on

CKA Exam 2026 - Scenario 6 Migrate an Ingress to the Gateway API without dropping HTTPS (CKA Services & Networking)

Migrate Ingress to the Gateway API

A web application is exposed over HTTPS with a classic Ingress, and the exam wants it migrated to the Gateway API while keeping HTTPS working. The GatewayClass is already installed. Let's recreate the routing with a Gateway and an HTTPRoute, then retire the Ingress.

🎥 Watch the video: https://www.youtube.com/watch?v=v5_1KKFWLGE

This is a CKA Services & Networking walkthrough. Every command below is real output from a live cluster, and you can reproduce the whole thing yourself (scripts at the end).

The scenario

Here is the setup. A Deployment named web sits behind a Service, and an Ingress named web terminates TLS for the host gateway.web.k8s.local and routes to it. A GatewayClass is already installed. Your task is to migrate this to the Gateway API, keep the same HTTPS host, and once it works, delete the old Ingress.

  • An Ingress named 'web' serves HTTPS for gateway.web.k8s.local
  • A GatewayClass is already installed in the cluster
  • Recreate the routing with a Gateway + HTTPRoute
  • Keep HTTPS, then delete the old Ingress

How an Ingress maps onto the Gateway API

The Gateway API splits what one Ingress did into three objects. The GatewayClass is the controller, like the ingress class. The Gateway is the listener: the port and the TLS the Ingress used to own. The HTTPRoute holds the routing rules: the hostname, the paths, and the backend Service. Map the Ingress onto those three and the migration is mechanical.

Where the YAML comes from (you author it, not apply -f)

There is no imperative kubectl create for a Gateway or HTTPRoute, so in the exam you
write the YAML yourself, copying a starting template from the Gateway API docs (linked from
the Kubernetes documentation, which is allowed during the exam):

Every value is something you already have. gatewayClassName is the class from
kubectl get gatewayclass. The HTTPS listener port and the certificateRefs Secret are
carried over from the existing Ingress's tls block. The hostname, the path, and the
backend Service (web:80) are the Ingress's own routing rule, re-expressed as an HTTPRoute.
You can see both files (cat) right before each kubectl apply below.

Inspect what's running

Start by reading the current state. The web Deployment and Service are running, and the Ingress named web is serving the host gateway.web.k8s.local on ports 80 and 443. The GatewayClass is present and Accepted, so the controller is ready for a Gateway to bind to it.

$ kubectl -n web get deploy,svc,ingress
NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/tester   1/1     1            1           117m
deployment.apps/web      1/1     1            1           117m

NAME          TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
service/web   ClusterIP   10.96.31.154   <none>        80/TCP    117m

NAME                            CLASS   HOSTS                   ADDRESS     PORTS     AGE
ingress.networking.k8s.io/web   nginx   gateway.web.k8s.local   localhost   80, 443   74m

$ kubectl get gatewayclass
NAME   CONTROLLER                                      ACCEPTED   AGE
eg     gateway.envoyproxy.io/gatewayclass-controller   True       117m
Enter fullscreen mode Exit fullscreen mode

The Ingress serves HTTPS today

Prove the starting point. A client that resolves gateway.web.k8s.local to the Ingress controller gets the page back over HTTPS, returning WEB APP OK. This is the behavior we must preserve through the migration.

$ curl -k https://gateway.web.k8s.local/
WEB APP OK
Enter fullscreen mode Exit fullscreen mode

Create the Gateway

There is no kubectl create for these, so you author the YAML by hand from the Gateway API docs, the Simple Gateway and TLS termination examples, which are linked from the Kubernetes docs. Look at the file. apiVersion and kind declare a Gateway. The gatewayClassName is eg, the class you just saw was Accepted. Then one listener: HTTPS on port 443 for the hostname gateway.web.k8s.local. Under tls, mode Terminate with a certificateRef to web-tls, the very same Secret the Ingress used, so HTTPS is preserved. Every value came from the GatewayClass or the old Ingress. Apply it and wait until it reports Programmed, which means the controller has provisioned the data plane and assigned an address.

$ cat gateway.yaml
# Gateway: an HTTPS listener on 443 that terminates TLS with the web-tls Secret.
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: web-gateway
  namespace: web
spec:
  gatewayClassName: eg
  listeners:
    - name: https
      protocol: HTTPS
      port: 443
      hostname: gateway.web.k8s.local
      tls:
        mode: Terminate
        certificateRefs:
          - name: web-tls

$ kubectl apply -f gateway.yaml
gateway.gateway.networking.k8s.io/web-gateway created

$ kubectl -n web get gateway web-gateway
NAME          CLASS   ADDRESS         PROGRAMMED   AGE
web-gateway   eg      10.96.138.181   True         9s
Enter fullscreen mode Exit fullscreen mode

Create the HTTPRoute

Now the routing, from the docs HTTP routing example. Read the file. It is an HTTPRoute. parentRefs attaches it to the web-gateway you just made, so this route is served by that Gateway. hostnames matches gateway.web.k8s.local, the same host as before. And the one rule matches the path prefix slash and sends it to backendRefs, the web Service on port 80. The host, the path, and the backend are lifted straight from the old Ingress rule. Apply it and confirm the hostname is bound.

$ cat httproute.yaml
# HTTPRoute: same host as the Ingress, path / -> the web Service on port 80.
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: web-route
  namespace: web
spec:
  parentRefs:
    - name: web-gateway
  hostnames:
    - gateway.web.k8s.local
  rules:
    - matches:
        - path:
            value: /
      backendRefs:
        - name: web
          port: 80

$ kubectl apply -f httproute.yaml
httproute.gateway.networking.k8s.io/web-route created

$ kubectl -n web get httproute web-route
NAME        HOSTNAMES                   AGE
web-route   ["gateway.web.k8s.local"]   0s
Enter fullscreen mode Exit fullscreen mode

Verify, then delete the Ingress

Verify before you remove anything. The same request, now routed through the Gateway, returns WEB APP OK over HTTPS. Only once that works do you delete the old Ingress. Test one more time: traffic still flows through the Gateway, with the Ingress gone. The migration is complete with no outage.

$ curl -k https://gateway.web.k8s.local/
WEB APP OK

$ kubectl -n web delete ingress web
ingress.networking.k8s.io "web" deleted from web namespace

$ curl -k https://gateway.web.k8s.local/
WEB APP OK
Enter fullscreen mode Exit fullscreen mode

Exam tips

A few traps. There is no kubectl create for Gateways or HTTPRoutes, so keep the Gateway API docs open and copy the manifests. Reuse the same TLS Secret on the Gateway listener so HTTPS keeps working. Wait for Programmed before testing, or you will curl a listener that is not up yet. And delete the Ingress last, only after the Gateway is verified, so you never drop traffic.

  • No imperative command: copy Gateway + HTTPRoute YAML from gateway-api.sigs.k8s.io
  • Reuse the same TLS Secret on the Gateway listener to keep HTTPS
  • Wait for the Gateway to be Programmed before you test
  • Delete the Ingress LAST, only after the Gateway is verified

Recap

  • Gateway = listener + TLS; HTTPRoute = host + path -> Service
  • Reuse the TLS Secret; wait for Programmed
  • Verify HTTPS, then delete the Ingress last
  • Subscribe + dev.to writeup

Reproduce this yourself

The entire scenario is scripted on a throwaway kind cluster: https://github.com/The-Cyber-Sidekick/TCS_CKA_2026_Exam_Scenarios

git clone https://github.com/The-Cyber-Sidekick/TCS_CKA_2026_Exam_Scenarios.git
cd TCS_CKA_2026_Exam_Scenarios/learning/scenarios/scenario6-ingress-to-gateway
./setup.sh        # creates the cluster AND arms the scenario
# solve it by hand, or:
./solution.sh     # apply the answer key and verify
Enter fullscreen mode Exit fullscreen mode

If this helped, subscribe to The Cyber SideKick on YouTube for more CKA drills, and grab the newsletter at https://thecybersidekick.beehiiv.com.

Top comments (0)