NGINX Ingress Controller in GKE

GKE in Production - Part 2

This tutorial is part of a series I am creating on creating, running and managing Kubernetes on GCP the way I do in my day job. In this episode, we are covering how to setup a nginx ingress controller to handle incoming requests.

Note: There may be some things I have skimmed over, if so or you see a glaring hole in my configuration, please drop me a line via the contact page linked at the top of the site.

What we will build

In this second installment, we will be adding an nginx ingress controller to our GKE cluster from part 1. (You can find it here: https://www.ianbrown.id.au/kubenetes_basic_setup)

What you will need

You will need:

  • Everything already running from Part 1.
  • Willingness to learn k8s, helm, let’s encrypt and nginx configurations.

Pre-Requisites

In order to complete this tutorial, we will need to install helm.
Helm is the package manager for kubernetes. It is a simple tool that allows any admin to deploy new applications within a cluster using predictable commands.

Download and Install Helm

The first thing to do is head over to https://github.com/helm/helm/releases and download the latest version of the helm client for your machine.
For me, this is https://get.helm.sh/helm-v3.0.0-linux-amd64.tar.gz

Now we need to unpack it with the following command:
tar -zxvf helm-v3.0.0-linux-amd64.tar.gz

This created a directory called linux-amd64 for me. Yours will be different if you are using a different OS.

Now we need to move the helm exe to a location in my $PATH.
This is simply a case of typing:
sudo mv linux-amd64/helm /usr/local/bin/helm
For Windows users, pick a location in your systems %PATH%, or add the path to the helm.exe to your PATH environment variable.

Confirm helm is working

Again, we should confirm everything is working before proceeding. Type: which helm (where helm on Windows) to should return the location we moved the exe to in the last step. (/usr/local/bin/helm)

And then, to ensure there is nothing missing, get the helm version with:
helm version
Mine shows v3.0.0.

Deploy the NGINX Ingress Controller

  1. Before we start deploying with helm, we need to add the NGINX ingress repo:
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx  
helm repo update
  1. Now we can deploy the ingress controller and service:
    helm install nginx-ingress ingress-nginx/ingress-nginx --set rbac.create=true

Let’s break this one down a bit:
helm install is us calling the install method of the helm executable.
nginx-ingress is the name of the helm chart we want to install.
ingress-nginx/ingress-nginx is a tricky way of installing into a namespace. In this instance, we are installing the chart in the ingress-nginx namespace and calling it ingress-nginx.
--set rbac.create=true enable role based access control. Read more about it here: https://kubernetes.github.io/ingress-nginx/deploy/rbac/

  1. Verify that the ingress controller and service are both deployed with:
kubectl get deployment nginx-ingress-ingress-nginx-controller
kubectl get service nginx-ingress-ingress-nginx-controller

The output should look something like this:

Ingress Controller Deployment Status

  1. Take note of the EXTERNAL-IP provided in the service as we will need to use that later.
    This will also be the IP that all DNS hostnames should point to for the various deployments of your applications.

We will be using 1.2.3.4 as the external IP from this point forward just in case the one I have used is now in use by another customer. :)

Deploy the hello-world app

As we did in the last tutorial, we need to have something to point the ingress resource at. For this we will use the same hello-world app Google provides as a sample.

To deploy the hello-world app, simple type:
kubectl create deployment hello-world --image=gcr.io/google-samples/hello-app:1.0

Then expose the deployment as a service with:
kubectl expose deployment hello-world --port=8080 --target-port=8080

Note here that we are no longer using port 80 on the public side!

Create an Ingress Resource

An Ingress Resource is a collection of Layer 7 rules for routing inbound traffic to services in Kubernetes.
Many rules can be defined in a single Ingress Resource or they can be split into multiple manifests. I generally keep a single Ingress Resource manifest per application to keep things simple.

Create the Ingress Resource YAML

Create a simple Ingress Resource YAML file to use the NGINX Ingress Controller with a single path since our hello-world app only has a single exposed port:

cat <<EOF > ingress-resource.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-resource
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
  rules:
  - host: "1.2.3.4.nip.io"
    http:
      paths:
      - pathType: Prefix
        path: "/hello"
        backend:
          service:
            name: hello-world
            port:
              number: 8080
EOF

There is a lot going on here, so let’s break it down.
kind: Ingress defines the object as an Ingress Resource.

The name value here is what is set in GKE, so if you have many ingress resources, you have full license to get creative with the names. :)

The annotations here are important.
kubernetes.io/ingress.class: "nginx" defines that this is an NGINX Controller ingress.
If you wanted to use GCE instead, simply change it to: kubernetes.io/ingress.class: gce
The ssl-redirect line tells nginx not to redirect all requests to the HTTPS equivilent. This will be important in a future part.
A full list of annotations is available here: https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/

rules defines the rules to be applied as follows:

host sets the FQDN that should be matched to use this Ingress Resource.
In this instance, we use the nip.io service to return the IP we set in the hostname part.
i.e. 1.2.3.4.nip.io will return an IP of 1.2.3.4

path is the path to the backend hello-world pod on port 8080.

Apply the configuration

To apply the configuration to kubernetes, simply run:
kubectl apply -f ingress-resource.yaml

Note that you can update the ingress resource by simply editing the YAML and running the same command again.

Verify the Ingress Resource is created by typing:
kubectl get ingress ingress-resource

Test our work

Now the moment of truth!

Open your favourite web browser and hit up the below url:
http://1.2.3.4.nip.io/hello

If everything went well, you should see that same hello world page from part 1. If not, check to ensure you haven’t missed a step or that the ingress resource is up and running.

Join me in the next part as we install Let’s Encrypt certificate services to the cluster so you never have to pay for an SSL certificate again!