{"id":380,"date":"2025-02-04T12:52:42","date_gmt":"2025-02-04T12:52:42","guid":{"rendered":"https:\/\/blog.ngocha.biz\/?p=380"},"modified":"2025-02-04T12:52:42","modified_gmt":"2025-02-04T12:52:42","slug":"migrate-kubernetes-ingress-to-gateway-api","status":"publish","type":"post","link":"https:\/\/blog.ngocha.biz\/?p=380","title":{"rendered":"How To Migrate Kubernetes Ingress To Gateway API?"},"content":{"rendered":"<p>In this blog, we will learn to migrate Kubernetes Ingress to gateway API and follow the easy migrating steps.<\/p>\n<p>Most of the workflows still use the standard Ingress traffic routing mechanism for traffic routing, but it has limitations in the routing rules.<\/p>\n<p>The Gateway API offers a lot of traffic routing features to simplify the advanced routing rules.<\/p>\n<h2 id=\"kubernetes-ingress\">Kubernetes Ingress<\/h2>\n<p>Before we jump into the migration, let me give a brief introduction about the Ingress.<\/p>\n<p>Ingress in the Kubernetes cluster helps to route the traffic to the applications based on certain rules such as domain name and path.<\/p>\n<p>But, in Ingress, it is difficult to configure the header-based routing or method-based routing. Also, there is no separation for the TCP\/UDP or HTTP\/HTTPS-based routing.<\/p>\n<p>Here, we can use the Gateway API, which has all the features for the Ingress resource as well as more advanced functions.<\/p>\n<h2 id=\"kubernetes-gateway-api\">Kubernetes Gateway API<\/h2>\n<p>Kubernetes Gateway API is the replacement for the Ingress resource because of its advanced features for traffic routing when compared to Ingress.<\/p>\n<p>To learn the complete setup of the Kubernetes Gateway API in the Kubernetes cluster, please refer to this <a href=\"https:\/\/devopscube.com\/kubernetes-gateway-api\/\">blog<\/a>.<\/p>\n<p>Let&#8217;s compare the core components of the Kubernetes Gateway API with the Ingress.<\/p>\n<p><strong>Gateway Class <\/strong>&#8211; Defines the controller information like <strong>Ingress Class<\/strong><\/p>\n<p><strong>Gateway<\/strong> &#8211; The entry point for the traffic, like <strong>Ingress<\/strong>.<\/p>\n<p><strong>HTTPRoute<\/strong> &#8211; Defines the HTTP routing rules, like <strong>Ingress rules<\/strong>.<\/p>\n<h4 id=\"prerequisites\">Prerequisites<\/h4>\n<ol>\n<li><a href=\"https:\/\/devopscube.com\/create-helm-chart\/\" rel=\"noreferrer noopener\">Helm<\/a> v3.17.0 or a higher version should be available on the local machine.<\/li>\n<li><a href=\"https:\/\/devopscube.com\/upgrade-kubernetes-cluster-kubeadm\/\" rel=\"noreferrer noopener\">Kubernetes Cluster<\/a> v1.30 or higher<\/li>\n<li>Kubectl v1.30 or higher should be available on the local machine, and the config file should be configured to access the cluster.<\/li>\n<\/ol>\n<h2 id=\"migrating-from-kubernetes-ingress-to-gateway-api\">Migrating from Kubernetes Ingress to Gateway API<\/h2>\n<p>In this section, will migrate an existing Ingress routing configuration to the Gateway API.<\/p>\n<h3 id=\"step-1-setup-the-nginx-ingress-controller-in-the-kubernetes-cluster\">Step 1: Setup the Nginx Ingress Controller in the Kubernetes  Cluster<\/h3>\n<p>I am setting up the Nginx Ingress Controller to show the demo from the beginning.<\/p>\n<p>You might be thinking why we need a controller to route the traffic, but actually the Controller is an Nginx Pod which act as a reverse proxy, when we add rules in the Ingress object, the routing informations will be configured in the Nginx Pod.<\/p>\n<p>When the traffic reaches the controller, it will route the traffic to the intended endpoints based on the rules and conditions.<\/p>\n<p>To pull the <a href=\"https:\/\/devopscube.com\/how-to-deploy-helm-charts-using-argo-cd\/\" rel=\"noreferrer noopener\">Helm chart<\/a> of the Nginx Ingress Controller and to untar, use the following command.<\/p>\n<pre><code>helm pull oci:\/\/ghcr.io\/nginx\/charts\/nginx-ingress --untar<\/code><\/pre>\n<p>This will give a local copy of the Helm chart, and open the following directory.<\/p>\n<pre><code>cd nginx-ingress<\/code><\/pre>\n<p>We can see a <code>values.yaml<\/code> file inside the directory, which has all the modifiable parameters.<\/p>\n<p>We can change the values as per our requirements or store the entire chart on our repositories to reuse.<\/p>\n<p>We are not modifying the default file, instead creating a new file <code>demo-values.yaml<\/code> file.<\/p>\n<pre><code>cat &lt;&lt;EOF&gt; demo-values.yaml\ncontroller:\n  service:\n    create: true\n    type: NodePort\n    httpPort:\n      enable: true\n      port: 80\n      nodePort: 30080  \n      targetPort: 80\nEOF<\/code><\/pre>\n<p>By default, the Service Type of the Nginx Ingress Controller is Load Balancer, but if you are testing the setup on your local cluster, the setup might not work properly.<\/p>\n<blockquote><p><strong>Note<\/strong>: If you are deploying the Nginx Ingress Controller on any production or in a cloud environment, keep the Service type as default (Load Balancer), which is an actual best practice.<\/p><\/blockquote>\n<p>Now, we can deploy the Nginx Ingress Controller with the new values file.<\/p>\n<pre><code>helm install nginx-ingress -f demo-values.yaml --create-namespace --namespace=ingress-nginx .<\/code><\/pre>\n<p><code>nginx-ingress<\/code> is the release name, and you can give any name.<\/p>\n<p><code>demo-values.yaml<\/code> is the configuration file to override the default installation.<\/p>\n<p><code>ingress-nginx<\/code> is the Namespace name where the Nginx Ingress Controller components need to be deployed.<\/p>\n<p>Once the installation is properly done, you can see the following output.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-43-3.png\" class=\"kg-image\" alt=\"the confirmation message of the nginx ingress controller deployment in the kubernetes cluster\" loading=\"lazy\" width=\"1632\" height=\"870\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-43-3.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-43-3.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1600\/2025\/03\/image-43-3.png 1600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-43-3.png 1632w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>Let&#8217;s check the Nginx Ingress Controller components status.<\/p>\n<p>If you want to know more about the Nginx Ingress Controller and configuration, please refer to this <a href=\"https:\/\/devopscube.com\/setup-ingress-kubernetes-nginx-controller\/\">blog<\/a>.<\/p>\n<pre><code>kubectl -n ingress-nginx get all<\/code><\/pre>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-5-12.png\" class=\"kg-image\" alt=\"listing the deployed components and its status of the nginx ingress controller\" loading=\"lazy\" width=\"1867\" height=\"842\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-5-12.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-5-12.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1600\/2025\/03\/image-5-12.png 1600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-5-12.png 1867w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>The Nginx Ingress Controller Pod is in a running state, which indicates all the Controller components are running without any issues.<\/p>\n<p>Note down the Node Port number (<code>30080<\/code>) for the access-related operations.<\/p>\n<p>Currently, we haven&#8217;t installed any application, so once that is done, we can use the public IP of the cluster nodes with the Node Port number to access the application.<\/p>\n<p>My cluster nodes are in the AWS cloud, so I can get the IP information over the GUI or CLI.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-1-16.png\" class=\"kg-image\" alt=\"listing the kubernetes cluster nodes and its public its\" loading=\"lazy\" width=\"1868\" height=\"547\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-1-16.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-1-16.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1600\/2025\/03\/image-1-16.png 1600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-1-16.png 1868w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>We can directly use the Public IP of any one of the Nodes with the Node Port number as a URL (<code>34.209.152.25:30080<\/code>) to access the application, but that won&#8217;t be quite convenient.<\/p>\n<p>To make the access more convenient, we use the Local DNS Resolution.<\/p>\n<h3 id=\"step-2-setup-local-dns-resolution\">Step 2: Setup Local DNS Resolution<\/h3>\n<p>For the local DNS resolution, we need to map the Nodes public IPs along with a host name in the <code>\/etc\/hosts<\/code> directory of the local system.<\/p>\n<p>We already know the public IPs of the cluster nodes so open the <code>\/etc\/hosts<\/code> directory with sudo privileges.<\/p>\n<pre><code>sudo vim \/etc\/hosts<\/code><\/pre>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-2-15.png\" class=\"kg-image\" alt=\"Describing the local DNS resolution configuration. \" loading=\"lazy\" width=\"772\" height=\"580\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-2-15.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-2-15.png 772w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>This is how we map the IP address with the hostname (<code>dev.techiescamp.com<\/code>), you can provide any host name you want.<\/p>\n<p>The DNS resolution only happens on the local machine where you configured it.<\/p>\n<blockquote><p>Note: To access the application over the internet using the domain name, you need to configure it with the DNS servers such as Route53, GoDaddy, etc.<\/p><\/blockquote>\n<h3 id=\"step-3-deploy-an-application-for-the-demo\">Step 3: Deploy an Application for the Demo<\/h3>\n<p>We have an container image in the Docker hub, so we are using it for testing, you can also you it if you want.<\/p>\n<p>Create a Namespace to deploy the applications and services.<\/p>\n<pre><code>kubectl create ns colors<\/code><\/pre>\n<p>Now, we can deploy the applications.<\/p>\n<pre><code>cat &lt;&lt;EOF &gt; colors-deployments.yaml\napiVersion: apps\/v1\nkind: Deployment\nmetadata:\n  name: orange-app\n  namespace: colors\n  labels:\n    app: orange-app\nspec:\n  replicas: 3\n  selector:\n    matchLabels:\n      app: orange-app\n  template:\n    metadata:\n      labels:\n        app: orange-app\n    spec:\n      containers:\n      - name: color-app\n        image: techiescamp\/go-color-app-demo:latest\n        ports:\n        - containerPort: 8080\n        env:\n        - name: POD_NAME\n          valueFrom:\n            fieldRef:\n              fieldPath: metadata.name\n        - name: POD_IP\n          valueFrom:\n            fieldRef:\n              fieldPath: status.podIP\n\n---\napiVersion: apps\/v1\nkind: Deployment\nmetadata:\n  name: green-app\n  namespace: colors\n  labels:\n    app: green-app\nspec:\n  replicas: 3\n  selector:\n    matchLabels:\n      app: green-app\n  template:\n    metadata:\n      labels:\n        app: green-app\n    spec:\n      containers:\n      - name: color-app\n        image: techiescamp\/go-color-app-demo:latest\n        ports:\n        - containerPort: 8080\n        env:\n        - name: POD_NAME\n          valueFrom:\n            fieldRef:\n              fieldPath: metadata.name\n        - name: POD_IP\n          valueFrom:\n            fieldRef:\n              fieldPath: status.podIP\nEOF<\/code><\/pre>\n<pre><code>kubectl apply -f colors-deployments.yaml<\/code><\/pre>\n<p>Here, I have deployed two deployments, which help to demonstrate the path based routing.<\/p>\n<p>We need services for these two Deployments to get the endpoints.<\/p>\n<pre><code>cat &lt;&lt;EOF &gt; colors-svc.yaml\napiVersion: v1\nkind: Service\nmetadata:\n  name: orange-app-service\n  namespace: colors\n  labels:\n    app: orange-app\nspec:\n  selector:\n    app: orange-app\n  ports:\n  - protocol: TCP\n    port: 80\n    targetPort: 8080\n  type: ClusterIP\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: green-app-service\n  namespace: colors\n  labels:\n    app: green-app\nspec:\n  selector:\n    app: green-app\n  ports:\n  - protocol: TCP\n    port: 80\n    targetPort: 8080\n  type: ClusterIP\nEOF<\/code><\/pre>\n<pre><code>kubectl apply -f colors-svc.yaml<\/code><\/pre>\n<p>Once all the deployments are completed, we can check the status.<\/p>\n<pre><code>kubectl -n colors get po,svc -o wide<\/code><\/pre>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-3-9.png\" class=\"kg-image\" alt=\"listing the demo deployment resources and its status\" loading=\"lazy\" width=\"1869\" height=\"793\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-3-9.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-3-9.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1600\/2025\/03\/image-3-9.png 1600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-3-9.png 1869w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>The resources are ready for the testing, let&#8217;s explore the Ingress resources.<\/p>\n<h3 id=\"step-4-describe-ingress-class\">Step 4: Describe Ingress Class<\/h3>\n<p>The Ingress Class is an object which has the information about the Ingress Controller.<\/p>\n<p>The default Ingress Class will automatically be created when we deploy an Ingress Controller.<\/p>\n<p>The Ingress Class is a cluster scoped resource.<\/p>\n<p>Let&#8217;s describe the Ingress Class.<\/p>\n<pre><code>kubectl get ingressclass<\/code><\/pre>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-4-7.png\" class=\"kg-image\" alt=\"listing the ingress classes from the kubernetes cluster\" loading=\"lazy\" width=\"1414\" height=\"690\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-4-7.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-4-7.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-4-7.png 1414w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>Here, we can see that the controller is <code>nginx.org\/ingress-controller<\/code>, which indicates that it is Nginx Ingress Controller.<\/p>\n<h3 id=\"step-5-create-an-ingress-to-define-routing-rules\">Step 5: Create an Ingress to Define Routing Rules<\/h3>\n<p>The Ingress is an object where we define the routing rules for traffic.<\/p>\n<p>The controller keeps on watching the Ingress object creation and modifications.<\/p>\n<p>The defined rules in the Ingress object will be configured in the controller so that once the traffic is reached in the controller, will route to the correct endpoint based on the rules.<\/p>\n<p>We can create an Ingress object will the rules for path based as well as hostname based routing.<\/p>\n<pre><code>cat &lt;&lt;EOF &gt; colors-ingress.yaml\napiVersion: networking.k8s.io\/v1\nkind: Ingress\nmetadata:\n  name: colors-ingress\n  namespace: colors\nspec:\n  ingressClassName: nginx\n  rules:\n  - host: dev.techiescamp.com\n    http:\n      paths:\n      - path: \/green\n        pathType: Prefix\n        backend:\n          service:\n            name: green-app-service\n            port:\n              number: 80\n      - path: \/orange\n        pathType: Prefix\n        backend:\n          service:\n            name: orange-app-service\n            port:\n              number: 80\nEOF<\/code><\/pre>\n<p>Ingress objects are Namespace scoped so where the applications are lying, there you have to create the Ingress.<\/p>\n<p>We have deployed the applications at <code>colors<\/code> Namespace, so the Ingress object must be created in <code>colors<\/code> Namespace.<\/p>\n<p>Under the <code>spec<\/code> section, need to mention the Ingress Class name, which is <code>nginx<\/code>.<\/p>\n<p>For the host name based traffic routing we have provided the hostname (<code>dev.techiescamp.com<\/code>) that we have already configured with the local DNS resolution configuration.<\/p>\n<p>Under the <code>rules<\/code> sections, there are two rules, one for the first application (<code>Green<\/code>) and the other for the second application (<code>Orange<\/code>).<\/p>\n<p>The Ingress to identify the service endpoints, we have provided the service names such as <code>green-app-service<\/code> and <code>orange-app-service<\/code>.<\/p>\n<p>The demo application is created for the path based routing so that the paths are mentioned in the rules, such as <code>\/green<\/code> for the first application and <code>\/orange<\/code> for the second application.<\/p>\n<p>So if want to access the applications, the URL should be <code>&lt;HOST_NAME&gt;:&lt;NODE_PORT_NUMBER&gt;\/&lt;PATH&gt;<\/code>.<\/p>\n<pre><code>kubectl apply -f colors-ingress.yaml<\/code><\/pre>\n<p>After the Ingress object deployment, use the following command to list it.<\/p>\n<pre><code>kubectl -n colors get ingress<\/code><\/pre>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-6-9.png\" class=\"kg-image\" alt=\"listing the deployed ingress objects from the cluster\" loading=\"lazy\" width=\"1728\" height=\"630\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-6-9.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-6-9.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1600\/2025\/03\/image-6-9.png 1600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-6-9.png 1728w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>Now, the configurations are ready, so need to access the applications.<\/p>\n<p>For that, open any of the web browsers from the local machine and paste the URL <code>dev.techiescamp.com:30080\/green<\/code>.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-7-13.png\" class=\"kg-image\" alt=\"the output for the application with the ingress controller and resource\" loading=\"lazy\" width=\"974\" height=\"506\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-7-13.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-7-13.png 974w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>We can see the output in the browser also if you notice the Pod name and IP, which is pointing to Pods of the first application deployment, so this ensures that the traffic is properly routed based on the rules that we provided in the Ingress object.<\/p>\n<p>You can check the second application if you want with this URL <code>dev.techiescamp.com:30080\/orange<\/code><\/p>\n<p>We have understood how the traffic is routed through the Ingress controller, so now, it is time to migrate this configuration to the Kubernetes Gateway API.<\/p>\n<h3 id=\"step-6-install-kubernetes-gateway-api-in-the-kubernetes-cluster\">Step 6: Install Kubernetes Gateway API in the Kubernetes Cluster<\/h3>\n<p>First, we need to install the Gateway API Custom Resource Definitions in the Kubernetes cluster.<\/p>\n<pre><code>kubectl apply -f https:\/\/github.com\/kubernetes-sigs\/gateway-api\/releases\/download\/v1.2.1\/standard-install.yaml<\/code><\/pre>\n<p>To check the CRDs, use the following command.<\/p>\n<pre><code>kubectl get crds | grep gateway<\/code><\/pre>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-8-8.png\" class=\"kg-image\" alt=\"listing the custom resource definitions of the Kubernetes Gateway API\" loading=\"lazy\" width=\"1656\" height=\"750\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-8-8.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-8-8.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1600\/2025\/03\/image-8-8.png 1600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-8-8.png 1656w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<ol>\n<li><code>Gateway Class<\/code> defines the <a href=\"https:\/\/devopscube.com\/setup-envoy-gateway-api\/\">Gateway API Controller<\/a> informations, same like the <code>Ingress Class<\/code> in Ingress<\/li>\n<li><code>Gateway<\/code> defines the entry point for the incoming traffic.<\/li>\n<li><code>gRPC Route, HTTP Route<\/code> are the resources where we define the routing rules.<\/li>\n<\/ol>\n<h3 id=\"step-7-install-nginx-fabric-gateway-api-controller\">Step 7: Install Nginx Fabric Gateway API Controller.<\/h3>\n<p>Similar to the Ingress, we need a controller for the Gateway API, and we can&#8217;t use the same controller of the Ingress because that doesn&#8217;t have the capabilities for the Gateway API routing configurations.<\/p>\n<p>For the <strong>Ingress<\/strong>, we have used the <strong>Nginx Ingress Controller<\/strong>, and for the <strong>Gateway API<\/strong>, we use the <strong>Nginx Fabric Gateway API Controller<\/strong>.<\/p>\n<p>To pull the <a href=\"https:\/\/devopscube.com\/how-to-deploy-helm-charts-using-argo-cd\/\" rel=\"noreferrer noopener\">Helm Chart<\/a> of the controller, use the following command.<\/p>\n<pre><code>helm pull oci:\/\/ghcr.io\/nginxinc\/charts\/nginx-gateway-fabric --untar<\/code><\/pre>\n<p>For this also, we use the Node Port service for the controller.<\/p>\n<p>Navigate to the <code>Nginx-gateway-fabric<\/code> directory.<\/p>\n<pre><code>cd nginx-gateway-fabric <\/code><\/pre>\n<p>Create a values file with the necessary parameters to deploy the controller with the Node Port service.<\/p>\n<pre><code>cat &lt;&lt;EOF&gt; demo-values.yaml\nservice:\n  type: NodePort\n  ports:\n    - port: 80\n      targetPort: 80\n      protocol: TCP\n      name: http\n      nodePort: 31080\nEOF<\/code><\/pre>\n<p>In this, we have changed the Node Port number (<code>31080<\/code>).<\/p>\n<p>To deploy the controller, use the following command.<\/p>\n<pre><code>helm install nginx-fabric --create-namespace -n fabric-gateway -f demo-values.yaml .<\/code><\/pre>\n<p>Once the installation is done correctly, you will get the following output.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-9-12.png\" class=\"kg-image\" alt=\" the installation confirmation message of the Kubernetes Gateway API\" loading=\"lazy\" width=\"1030\" height=\"510\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-9-12.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-9-12.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-9-12.png 1030w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>After the deployment, we can check the components of the Gateway API Controller.<\/p>\n<p>If you want to know the setup of the Kubernetes Gateway API in the EKS cluster with the Load Balancer, you can refer to this <a href=\"https:\/\/devopscube.com\/kubernetes-gateway-api\/\">blog<\/a>.<\/p>\n<pre><code>kubectl -n fabric-gateway get all<\/code><\/pre>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-10-11.png\" class=\"kg-image\" alt=\"listing the Kubernetes gateway api controller components and its status\" loading=\"lazy\" width=\"2000\" height=\"805\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-10-11.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-10-11.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1600\/2025\/03\/image-10-11.png 1600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w2400\/2025\/03\/image-10-11.png 2400w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>We don&#8217;t have to make any modifications in the local DNS resolution because the hostname and IPs are the same.<\/p>\n<h3 id=\"step-8-describe-kubernetes-gateway-api-gateway-class\">Step 8: Describe Kubernetes Gateway API Gateway Class.<\/h3>\n<p>As with the Ingress, when we deploy the Gateway API Controller, the Gateway Class will be created with the controller information.<\/p>\n<pre><code>kubectl get gatewayclass<\/code><\/pre>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-11-10.png\" class=\"kg-image\" alt=\"listing the default gateway api class of the gateway api\" loading=\"lazy\" width=\"1728\" height=\"570\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-11-10.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-11-10.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1600\/2025\/03\/image-11-10.png 1600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-11-10.png 1728w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>The <code>gateway.nginx.org\/nginx-gateway-controller<\/code> is the Gateway API Controller name.<\/p>\n<h3 id=\"step-9-create-the-kubernetes-gateway-api-gateway-resource\">Step 9: Create the Kubernetes Gateway API Gateway Resource.<\/h3>\n<p>This is slightly different from Ingress because in Ingress, we can directly create the rules with the Ingress object, but in Gateway API, we need to create an entry point for the traffic. Then only we can create rules.<\/p>\n<p>To create an entry point for the traffic, we need to create a Gateway object.<\/p>\n<pre><code>cat &lt;&lt;EOF &gt; colors-gateway.yaml\napiVersion: gateway.networking.k8s.io\/v1\nkind: Gateway\nmetadata:\n  name: colors-gateway\n  namespace: colors\nspec:\n  gatewayClassName: nginx\n  listeners:\n  - name: http\n    port: 80\n    protocol: HTTP\n    allowedRoutes:\n      namespaces:\n        from: All\nEOF<\/code><\/pre>\n<p>Gateway is a Namespace scoped object, so we need to create the Gateway on where the endpoints are.<\/p>\n<p>In <strong>Ingress<\/strong>, we define the <strong>Ingress Class<\/strong> in the Ingress object, but in <strong>Gateway API<\/strong>, the <strong>Gateway Class<\/strong> will be specified in the <strong>Gateway<\/strong> object.<\/p>\n<p>Listeners are the type of network, we can define multiple listeners in a same Gateway (Example: 443, 8080).<\/p>\n<p>The <code>allowRoutes<\/code> section, we can instruct from what are the Namespaces to allow the traffic to the Gateway.<\/p>\n<p>These are some of the basic configurations in the Gateway object.<\/p>\n<pre><code>kubectl apply -f colors-gateway.yaml<\/code><\/pre>\n<p>To list the Gateway, use the following command.<\/p>\n<pre><code>kubectl -n colors get gateway<\/code><\/pre>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-12-10.png\" class=\"kg-image\" alt=\"listing the deployed gateway class from the Kubernetes cluster\" loading=\"lazy\" width=\"1318\" height=\"510\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-12-10.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-12-10.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-12-10.png 1318w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>If you describe it, you will get more information about the Gateway.<\/p>\n<pre><code>kubectl -n colors describe gateway colors-gateway<\/code><\/pre>\n<p>Now, we can define rules for routing.<\/p>\n<h3 id=\"step-10-create-gateway-api-http-route-resources-to-define-routing-rules\">Step 10: Create Gateway API HTTP Route Resources to Define Routing Rules<\/h3>\n<p>We have multiple resources to define our rules based on the protocol.<\/p>\n<p>We know that our demo application is HTTP based, so we are using the HTTP Route resource.<\/p>\n<pre><code>cat &lt;&lt;EOF &gt; colors-http-route.yaml\napiVersion: gateway.networking.k8s.io\/v1\nkind: HTTPRoute\nmetadata:\n  name: colors-httproute\n  namespace: colors\nspec:\n  parentRefs:\n  - name: colors-gateway\n    sectionName: http\n  hostnames:\n  - \"dev.techiescamp.com\"\n  rules:\n  - matches:\n    - path:\n        type: PathPrefix\n        value: \/green\n    backendRefs:\n    - name: green-app-service\n      port: 80\n  - matches:\n    - path:\n        type: PathPrefix\n        value: \/orange\n    backendRefs:\n    - name: orange-app-service\n      port: 80\nEOF<\/code><\/pre>\n<p>The <code>parentRefs<\/code> section where we define the Gateway resource.<\/p>\n<p><code>hostname<\/code> section where we define the host name (<code>dev.techiescamp.com<\/code>).<\/p>\n<p>Under the <code>rules<\/code> sections, we can define the service details to get the endpoints.<\/p>\n<p>The HTTP Route Custom Resource is similar to the Ingress object in Ingress, where we define the routing rules.<\/p>\n<p>The only difference is that in Ingress, the Ingress Class will be defined in the Ingress object, but in Gateway API, the Gateway Class will be defined in the Gateway object, and the Gateway object will be defined in the HTTP Route.<\/p>\n<pre><code>kubectl apply -f colors-http-route.yaml<\/code><\/pre>\n<p>After the deployment, we list the HTTP Routes using the following command.<\/p>\n<pre><code>kubectl -n colors get httproutes<\/code><\/pre>\n<p>You can describe to ensure the routes are properly configured and the status is active or not.<\/p>\n<pre><code>kubectl -n colors describe httproutes colors-httproute<\/code><\/pre>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-13-12.png\" class=\"kg-image\" alt=\"listing the HTTP route custom resource of the Gateway API\" loading=\"lazy\" width=\"1246\" height=\"450\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-13-12.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-13-12.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-13-12.png 1246w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>The migration configuration is properly done so we can check the application.<\/p>\n<p>This time, for the testing, we need to use the URL with the Gateway API Controller Node Port, which is 31080.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-14-13.png\" class=\"kg-image\" alt=\"the output of the application and the traffic routing by the Kubernetes gateway api\" loading=\"lazy\" width=\"966\" height=\"475\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-14-13.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-14-13.png 966w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>We have successfully migrated the traffic routing from the Ingress to the Gateway API.<\/p>\n<h3 id=\"step-11-remove-the-nginx-ingress-controller-from-the-cluster\">Step 11: Remove the Nginx Ingress Controller from the Cluster<\/h3>\n<p>Use the following command to uninstall the Nginx Ingress Controller.<\/p>\n<pre><code>helm -n ingress-nginx uninstall nginx-ingress<\/code><\/pre>\n<blockquote><p>Note: We have migrated the traffic routing from Ingress to Gateway API without any downtime, but in actual production, the Controller will be exposed with Load Balancer service and the domain name will be configured with DNS Servers.<\/p>\n<p>During the migration, the Load Balancer DNS records were also remapped with the DNS server, so it might face some downtime.<\/p><\/blockquote>\n<h2 id=\"conclusion\">Conclusion<\/h2>\n<p>This blog explains how we can migrate the existing Ingress setup to Gateway API for the futuristic traffic routing. This is the basic migration, but you can configure the entire traffic routing to Gateway API.<\/p>\n<p>In future blogs, we will cover the Gateway API and its use cases more. Please refer to the <a href=\"https:\/\/gateway-api.sigs.k8s.io\/?ref=devopscube.com\">official documentation<\/a> to learn more about the Gateway API.<\/p>\n<hr>\n<p><strong>Ngu\u1ed3n:<\/strong> <a href=\"https:\/\/devopscube.com\/migrate-kubernetes-ingress-to-gateway-api\/\" target=\"_blank\" rel=\"noopener noreferrer\">How To Migrate Kubernetes Ingress To Gateway API? \u2014 DevOpsCube<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Source: https:\/\/devopscube.com\/migrate-kubernetes-ingress-to-gateway-api\/<\/p>\n","protected":false},"author":1,"featured_media":381,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-380","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops"],"_links":{"self":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/posts\/380","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=380"}],"version-history":[{"count":0,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/posts\/380\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/media\/381"}],"wp:attachment":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=380"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=380"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=380"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}