{"id":822,"date":"2021-06-24T03:59:38","date_gmt":"2021-06-24T03:59:38","guid":{"rendered":"https:\/\/blog.ngocha.biz\/?p=822"},"modified":"2021-06-24T03:59:38","modified_gmt":"2021-06-24T03:59:38","slug":"setup-ingress-gke-ingress-controller","status":"publish","type":"post","link":"https:\/\/blog.ngocha.biz\/?p=822","title":{"rendered":"How to Setup Ingress on GKE using GKE Ingress Controller"},"content":{"rendered":"<p>This tutorial will guide you to setup Ingress on GKE using a GKE ingress controller that covers:<\/p>\n<ol>\n<li>The need for ingress<\/li>\n<li>The logic behind the GKE ingress controller<\/li>\n<li>Creating your first ingress with a demo application.<\/li>\n<li>Different ways of ingress domain\/host and path mappings<\/li>\n<\/ol>\n<p>Let\u2019s dive right in.<\/p>\n<h2 id=\"why-gke-ingress\">Why GKE Ingress?<\/h2>\n<p>Exposing each service as a Loadbalancer is not an ideal solution to deal with Kubernetes ingress traffic.<\/p>\n<p>You need a Kubernetes ingress controller to manage all the ingress traffic for the cluster. With direct DNS or a wildcard DNS mapping, you can route traffic to backend kubernetes services.<\/p>\n<p>Also you can have multiple DNS attached to a single ingress Loadbalancer and route to different service backends using the Ingress controller.<\/p>\n<p>Also, you can have path-based routing rules in the ingress resources to different kubernetes services.<\/p>\n<p>The good thing is, GKE comes with an <strong>inbuilt GKE ingress controller<\/strong>. So you don&#8217;t have to do any extra configurations to set up an ingress controller.<\/p>\n<p>You can also set up other ingress controllers like the <a href=\"https:\/\/devopscube.com\/setup-ingress-kubernetes-nginx-controller\/\" rel=\"noreferrer noopener\">Nginx ingress controller<\/a>. It depends upon the project requirements and the features supported by each controller implementation.<\/p>\n<p>For this tutorial, we will just look at how to create an ingress object with the GKE ingress controllers.<\/p>\n<h2 id=\"how-does-gke-ingress-work\">How Does GKE Ingress Work?<\/h2>\n<p>As you probably know, for Kubernetes ingress to work, you need an Ingress controller.<\/p>\n<p>If you are not aware of ingress concepts, please read the<a href=\"https:\/\/devopscube.com\/kubernetes-ingress-tutorial\/\" rel=\"noreferrer noopener\"> ingress tutorial <\/a>to understand how it works.<\/p>\n<p>GKE has its own ingress controller called GKE ingress controller.<\/p>\n<p>When you create an ingress object, GKE launches a Load Balancer (Public or Private) with all the routing rules mentioned in the ingress resource.<\/p>\n<p>Since the Loadbalancer is outside the cluster, the backend service defined in the ingress resources should be of type LoadBalancer.<\/p>\n<p>Whereas in normal ingress controller implementation like Nginx ingress controller, the proxy layer resides inside the cluster and it can talk to services without Nodeport.<\/p>\n<figure class=\"kg-card kg-image-card kg-card-hascaption\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/gke-ingress-1-1.png\" class=\"kg-image\" alt=\"GKE ingress controller architecture\" loading=\"lazy\" width=\"2000\" height=\"1500\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/gke-ingress-1-1.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/gke-ingress-1-1.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1600\/2025\/03\/gke-ingress-1-1.png 1600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/gke-ingress-1-1.png 2224w\" sizes=\"auto, (min-width: 720px) 720px\"><figcaption><span style=\"white-space: pre-wrap;\">Click to view in HD<\/span><\/figcaption><\/figure>\n<p>In GKE, there is a concept of <a href=\"https:\/\/cloud.google.com\/load-balancing\/docs\/negs?ref=devopscube.com\" rel=\"noreferrer noopener\">Network Endpoint Groups<\/a>. Even though the backend service is of type NoePort, GKE doesn&#8217;t randomly send traffic to any node in the cluster to reach the pods. With NEGs, all the traffic will be sent directly to the nodes where the pod resides.<\/p>\n<p>Without NEGs, the traffic from the Loadbalancer can read any node in the cluster and can result in extra network hops to reach the node where the pod resides.<\/p>\n<h2 id=\"setup-ingress-on-gke-using-a-gke-ingress-controller\">Setup Ingress on GKE using a GKE Ingress Controller<\/h2>\n<p>Now, let&#8217;s look at a practical example of setting up ingress using the GKE ingress controller.<\/p>\n<p>To understand the GKE ingress workflow and configurations better, we will do the following.<\/p>\n<ol>\n<li>Deploy an Nginx deployment with  a <code>NodePort<\/code> service (Nodeport is a requirement)<\/li>\n<li>Create an ingress object with static IP that has a rule to route traffic to the Nginx service endpoint.<\/li>\n<li>Validate the ingress deployment by accessing Nginx over the Loadbalancer IP.<\/li>\n<\/ol>\n<p>Let&#8217;s get started with the setup.<\/p>\n<h3 id=\"step-1-deploy-an-nginx-deployment-with-service-type-nodeport\">Step 1: Deploy an Nginx deployment With Service Type NodePort<\/h3>\n<p>Save the following manifest as <code>nginx.yaml<\/code>. We are adding a custom index.html using a <code>configmap<\/code> which replaced the default Nginx <code>index.html<\/code> file.<\/p>\n<div class=\"kg-card kg-callout-card kg-callout-card-grey\">\n<div class=\"kg-callout-text\"><b><strong style=\"white-space: pre-wrap;\">Note:<\/strong><\/b> For GKE ingress to work, the service type has to be NodePort. It is a requirement.<\/div>\n<\/div>\n<pre><code>---\napiVersion: apps\/v1\nkind: Deployment\nmetadata:\n  name: nginx-deployment\n  namespace: default\nspec:\n  selector:\n    matchLabels:\n      app: nginx\n  replicas: 2 \n  template:\n    metadata:\n      labels:\n        app: nginx\n    spec:\n      containers:\n      - name: nginx\n        image: nginx:latest\n        ports:\n        - containerPort: 80\n        readinessProbe:\n          httpGet:\n            scheme: HTTP\n            path: \/index.html\n            port: 80\n          initialDelaySeconds: 10\n          periodSeconds: 5\n        volumeMounts:\n            - name: nginx-public\n              mountPath: \/usr\/share\/nginx\/html\/\n      volumes:\n      - name: nginx-public\n        configMap:\n          name: nginx-index-html-configmap\n---\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: nginx-index-html-configmap\n  namespace: default\ndata:\n  index.html: |\n    &lt;html&gt;\n    &lt;h1&gt;Welcome To Webapp 01&lt;\/h1&gt;\n    &lt;\/br&gt;\n    &lt;h1&gt;Hi! You are Trying to Access Webapp Through GKE Ingress &lt;\/h1&gt;\n    &lt;\/html\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: nginx-service\n  namespace: default\nspec:\n  selector:\n    app: nginx\n  type: NodePort\n  ports:\n    - port: 80\n      targetPort: 80\n<\/code><\/pre>\n<p>Create the deployment.<\/p>\n<pre><code>kubectl apply -f nginx.yaml<\/code><\/pre>\n<p>It gets deployed in the default namespace.<\/p>\n<p>Validate the deployment. You should see two Replicas of Nginx.<\/p>\n<pre><code>kubectl get deployments<\/code><\/pre>\n<p>Validate the Nginx service endpoint. You should be abe able to see the randomly assigned NodePort.<\/p>\n<pre><code>kubectl get svc nginx-service<\/code><\/pre>\n<h3 id=\"step-2-create-ingress-for-the-nginx-deployment\">Step 2: Create Ingress for the Nginx Deployment<\/h3>\n<p>Now that we have a working deployment, we will create an ingress resource.<\/p>\n<p>Let&#8217;s start with a basic setup and then I will address other options in the ingress.<\/p>\n<p>What we are going to do is create an ingress that routes traffic to our Nginx service endpoint.<\/p>\n<p>First, we need to create a Static Public IP address with the name <code>ingress-webapps<\/code> that we can use with the ingress. With static IP you can point the <strong>required domain name<\/strong> to the Ingress IP.<\/p>\n<pre><code>gcloud compute addresses create ingress-webapps --global<\/code><\/pre>\n<p>Save the following manifest as <code>ingress.yaml<\/code><\/p>\n<pre><code>apiVersion: networking.k8s.io\/v1\nkind: Ingress\nmetadata:\n  name: nginx-ingress\n  annotations:\n    kubernetes.io\/ingress.class: \"gce\"\n    kubernetes.io\/ingress.global-static-ip-name: \"ingress-webapps\"\nspec:\n  rules:\n  - http:\n      paths:\n      - path: \"\/*\"\n        pathType: ImplementationSpecific\n        backend:\n          service:\n            name: nginx-service\n            port:\n              number: 80<\/code><\/pre>\n<p>As you can see we have two annotations in the manifest file.<\/p>\n<ol>\n<li><code>kubernetes.io\/ingress.class<\/code> annotation with value <code>gce<\/code> tells GKE to create a public Load Balancer. If you don&#8217;t specify it, it defaults to public only.<\/li>\n<li><code>kubernetes.io\/ingress.global-static-ip-name<\/code> annotation with value <code>ingress-webapps<\/code> tells GKE to attach the static IP we created to the ingress Load Balancer.<\/li>\n<li>We are creating a <code>http<\/code> rule to route all the traffic, ie<code> \/*<\/code> to the <code>nginx-service<\/code> endpoint.<\/li>\n<\/ol>\n<p>Let&#8217;s create the ingress<\/p>\n<pre><code>kubectl apply -f ingress.yaml<\/code><\/pre>\n<p>When you create ingress, it creates a Loadbalancer with the routing rules mentioned in the ingress YAML.<\/p>\n<h3 id=\"step-3-validate-ingress\">Step 3: Validate Ingress<\/h3>\n<p>Let&#8217;s list the ingress and get the Load balancer IP.<\/p>\n<pre><code> kubectl 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-15-39.png\" class=\"kg-image\" alt=\"GKE ingress Load balancer IP\" loading=\"lazy\" width=\"573\" height=\"90\"><\/figure>\n<p>After few minutes you should be able to access the Nginx service running inside the cluster using the<\/p>\n<p>Alternatively, you can check the Google Cloud load balancer dashboard to get more details about the Ingress Loadbalancer.<\/p>\n<figure class=\"kg-card kg-image-card kg-card-hascaption\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-16-43.png\" class=\"kg-image\" alt=\"GKE ingress Controller load balancer details\" loading=\"lazy\" width=\"588\" height=\"519\"><figcaption><span style=\"white-space: pre-wrap;\">Click to view in HD<\/span><\/figcaption><\/figure>\n<h2 id=\"hosting-multiple-domains-on-same-gke-ingress-loadbalancer\">Hosting Multiple Domains on Same GKE Ingress Loadbalancer<\/h2>\n<p>If you have a use case to host multiple applications with DNS on the same Load balancer, you can do it by mapping the same Loadbalancer IP in both the DNS A records.<\/p>\n<p>Now, in the ingress specification, you need to add both the domain names with the respective backend service endpoints as shown below.<\/p>\n<pre><code>apiVersion: networking.k8s.io\/v1\nkind: Ingress\nmetadata:\n  name: nginx-ingress\n  annotations:\n    kubernetes.io\/ingress.class: \"gce\"\n    kubernetes.io\/ingress.global-static-ip-name: \"ingress-webapps\"\nspec:\n  rules:\n  - host: \"www.web01.com\"\n    http:\n      paths:\n      - pathType: ImplementationSpecific\n        path: \"\/\"\n        backend:\n          service:\n            name: web01-service\n            port:\n              number: 8080\n  - host: \"www.web02.com\"\n    http:\n      paths:\n      - pathType: ImplementationSpecific\n        path: \"\/\"\n        backend:\n          service:\n            name: web02-service\n            port:\n              number: 8080\n<\/code><\/pre>\n<h2 id=\"path-based-routing-using-gke-ingress\">Path-Based Routing Using GKE Ingress<\/h2>\n<p>Now, let&#8217;s say you have many backend services that need to be routed based on a specific path. In that case, your ingress would like the following.<\/p>\n<pre><code>apiVersion: networking.k8s.io\/v1\nkind: Ingress\nmetadata:\n  name: nginx-ingress\n  annotations:\n    kubernetes.io\/ingress.class: \"gce\"\n    kubernetes.io\/ingress.global-static-ip-name: \"ingress-webapps\"\nspec:\n  rules:\n  - http:\n      paths:\n      - path: \"\/*\"\n        pathType: ImplementationSpecific\n        backend:\n          service:\n            name: nginx-service\n            port:\n              number: 80\n      - path: \"\/api\"\n        pathType: ImplementationSpecific\n        backend:\n          service:\n            name: api-service\n            port:\n              number: 80\n       - path: \"\/users\"\n        pathType: ImplementationSpecific\n        backend:\n          service:\n            name: user-service\n            port:\n              number: 80<\/code><\/pre>\n<h2 id=\"multiple-ingress-resources-with-single-gke-ingress-controller\">Multiple Ingress Resources with Single GKE Ingress Controller<\/h2>\n<p>When we setup ingress controllers like Nginx, you can have multiple ingress resources mapped to a single Ingress controller.<\/p>\n<p>However, when it comes to GKE Loadbalancer based ingress controllers, you cannot map multiple ingress objects to a single GKE ingress controller.<\/p>\n<p>For each ingress object or a resource, a separate Google Loadbalancer will be provisioned.<\/p>\n<p>Here is what the <a href=\"https:\/\/cloud.google.com\/kubernetes-engine\/docs\/concepts\/ingress?ref=devopscube.com\" rel=\"noreferrer noopener\">google cloud document <\/a>says about the multiple ingress resource mapping limitation.<\/p>\n<div class=\"kg-card kg-callout-card kg-callout-card-grey\">\n<div class=\"kg-callout-text\">Combining multiple Ingress resources into a single Google Cloud load balancer is not supported.<\/div>\n<\/div>\n<p>The one way to circumvent this problem is to have all the ingress rules in a single ingress resource.<\/p>\n<p>There is a limitation of a maximum of 50 paths per backend mapping. See out all the <a href=\"https:\/\/cloud.google.com\/load-balancing\/docs\/quotas?ref=devopscube.com#url_maps\" rel=\"noreferrer noopener\">Quota limitations<\/a>.<\/p>\n<h2 id=\"customizing-gke-ingress-configurations\">Customizing GKE Ingress Configurations<\/h2>\n<p>The example we have seen uses all the default settings of the GKE ingress controller.<\/p>\n<p>But when it comes to production project requirements, you may have to tweak the configurations based on your application.<\/p>\n<p>Few use cases are,<\/p>\n<ol>\n<li><strong>Custom Headers:<\/strong> You might have to add custom HTTP headers to the GKE ingress controller.<\/li>\n<li><strong>Session Affinity: <\/strong>If you want requests from a given user to be served by the same backend.<\/li>\n<\/ol>\n<p>Refer to the <a href=\"https:\/\/cloud.google.com\/kubernetes-engine\/docs\/how-to\/ingress-features?ref=devopscube.com\" rel=\"noreferrer noopener\">GKE ingress controller features<\/a> document to understand all the supported configurations.<\/p>\n<p>To use the extra GKE ingress features, you need to deploy a Backend config with the required features. <code>Backendconfig<\/code> is a custom resource type available as part of GKE ingress controllers.<\/p>\n<p>For, example, to enable session affinity based on a cookie, you have to deploy the following backend config.<\/p>\n<pre><code>apiVersion: cloud.google.com\/v1\nkind: BackendConfig\nmetadata:\n  name: session-cookie-config\nspec:\n  sessionAffinity:\n    affinityType: \"GENERATED_COOKIE\"\n    affinityCookieTtlSec: 50<\/code><\/pre>\n<p>And for setting custom headers in GKE ingress, you have to use the following backend config.<\/p>\n<pre><code>apiVersion: cloud.google.com\/v1\nkind: BackendConfig\nmetadata:\n  name: my-backendconfig\nspec:\n  customRequestHeaders:\n    headers:\n    - \"X-Client-Region:{client_region}\"\n    - \"X-Client-City:{client_city}\"\n    - \"X-Client-CityLatLong:{client_city_lat_long}\"<\/code><\/pre>\n<h2 id=\"conclusion\">Conclusion<\/h2>\n<p>In this tutorial, we have learned to set up Ingress on GKE using a GKE ingress controller and Google cloud load balancer.<\/p>\n<p>Choosing a GKE ingress controller vs. another ingress controller depends on the project requirements and features required in the ingress layer.<\/p>\n<p>You might need more information or you may some issues while setting it up.<\/p>\n<p>Either way, drop a comment below.<\/p>\n<hr>\n<p><strong>Ngu\u1ed3n:<\/strong> <a href=\"https:\/\/devopscube.com\/setup-ingress-gke-ingress-controller\/\" target=\"_blank\" rel=\"noopener noreferrer\">How to Setup Ingress on GKE using GKE Ingress Controller \u2014 DevOpsCube<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Source: https:\/\/devopscube.com\/setup-ingress-gke-ingress-controller\/<\/p>\n","protected":false},"author":1,"featured_media":823,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-822","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\/822","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=822"}],"version-history":[{"count":0,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/posts\/822\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/media\/823"}],"wp:attachment":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=822"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=822"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=822"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}