Symlach

KEW 3: Running Kubernetes on GKE

“Kubernetes is a platform for building platforms. It's a better place to start; not the endgame.” ― Kelsey Hightower

Last week I familiarised myself with running Kubernetes locally. This week I’m going to take it a step further and deploy my first cluster to the cloud.

I’ve heard from colleagues that Google Kubernetes Engine (GKE) is a bit more foolproof than Amazon Elastic Kubernetes Service (EKS). For that reason, I’m going to start with GKE, although I plan on looking into EKS in the future.

Here were my goals for this week:

Deploying a multi-node cluster to GKE

I’ll be deploying my GKE cluster to Google Cloud using a Pluralsight GCP sandbox. I got grandfathered into a subscription long ago when it was Linux Academy before it got acquired by A Cloud Guru and then A Cloud Guru got acquired by Pluralsight. Anyway, I digress. I best make use of the subscription where I can…

Once I authenticated and configured my Google Cloud project, I was ready to start creating my cluster.

I’ll first set my default region and zone for compute. This is used by the Google Compute Engine (GCE) Virtual Machines (VMs) that are used as the worker nodes within the cluster:

gcloud config set compute/region us-central1
gcloud config set compute/zone us-central1-a

Next, I’ll create the GKE cluster with three worker nodes:

gcloud container clusters create kiada --num-nodes 3

Then, I need to configure kubectl so that I can interact with my cluster:

gcloud container clusters get-credentials kiada --zone us-central1-a

Note: If, like me, you don't already have gke-gcloud-auth-plugin installed, you'll need to install it to be able to configure kubectl. You can find instructions here.

Finally, I can check my cluster information:

kubectl cluster-info

I can also check my worker nodes are running:

kubectl get nodes

kubectl get nodes output showing three GKE worker nodes with status Ready
The three GKE worker nodes, all reporting Ready.

To confirm what type of VMs are being used as my worker nodes, I can run:

gcloud compute instances list

gcloud compute instances list output showing three e2-medium VMs running in us-central1-a
The worker nodes are e2-medium Compute Engine VMs. Because I'm using a cloud sandbox and not footing the bill, they aren't preemptible.

Running an application on a worker node

Now that I have my cluster running, let’s get an application deployed! Because I’m using the example in Chapter 3 of Kubernetes in Action, deploying the application is simple:

kubectl create deployment kiada --image=luksa/kiada:0.1

I can then check the deployment exists:

kubectl get deployments

kubectl get deployments output showing the kiada deployment with 1/1 ready
The kiada deployment, reporting 1/1 pods ready.

But as I’ve learnt already, deployments create pods using the deployment controller (via a ReplicaSet) after which the scheduler assigns them to a worker node. Let’s see if any pods have been created:

kubectl get pods

kubectl get pods output showing a single kiada pod in the Running state
A single kiada pod, up and running.

I can see one pod running the application. I could also verify this by ssh’ing into the worker node and listing the containers running. Let’s do that:

First I need to ssh into the worker node:

gcloud compute ssh gke-kiada-default-pool-28f6eb24-n6b2

Then list the running containers:

crictl ps

There I can see the application container!

crictl ps output on the worker node showing the kiada application container running
The kiada application container running on the worker node, listed with crictl ps.

If I need to debug a pod, I can use the kubectl describe pod command. Here I can see the list of events that occurred for the pod to successfully start:

kubectl describe pod events showing the pod being scheduled, the image pulled, and the container started
The pod's events: scheduled to a node, the image pulled, and the container created and started.

Accessing the application

I now have an application running, but I cannot reach it over the internet. To make that happen, I’m going to need to add a service into the mix!

kubectl expose deployment kiada --type=LoadBalancer --port 8080

This creates a service object that tells the cluster that all the pods belonging to the kiada deployment should be accessible outside of the cluster via a load balancer.

Running kubectl get svc kiada now shows that the load balancer has been created:

kubectl get svc output showing the kiada LoadBalancer service with an external IP
The kiada LoadBalancer service, now with an external IP assigned.

A curl request to the load balancer’s external IP on port 8080 should reveal if I can now reach the application over the internet!

curl to the load balancer returning a response processed by the kiada pod
Success! The request was served from the kiada-8578f776bf-qrppv pod.

Making the application highly available

I have a friend who likes to remind me that my hobby projects need to consider high availability more. As I know he takes great joy in reading my blog, I want to make him happy.

I can scale the application from running on one pod to three, using the following command:

kubectl scale deployment kiada --replicas=3

Now when I run kubectl get deploy kiada, I can see there are three pods running:

kubectl get deploy output showing the kiada deployment with 3/3 ready
The kiada deployment scaled up to 3/3 pods ready.

I can confirm there are two additional pods alongside the original kiada-8578f776bf-qrppv pod by running kubectl get pods.

kubectl get pods output showing three kiada pods in the Running state
Three kiada pods now running, including the original kiada-8578f776bf-qrppv.

Now when I make requests to the application, I can see that they are being served by different pods:

curl response processed by the kiada-8578f776bf-qrppv pod
The first request is handled by the kiada-8578f776bf-qrppv pod.
curl response processed by the kiada-8578f776bf-nl6wc pod
The second, by the kiada-8578f776bf-nl6wc pod.
curl response processed by the kiada-8578f776bf-bq5c6 pod
And the third, by the kiada-8578f776bf-bq5c6 pod.

It’s worth noting here that the requests are actually being distributed across the pods via the Kubernetes service, whereas the external load balancer, which is infrastructure in GCP, funnels requests to the worker nodes running the pods.

That’s all for this week. I wish I had more time to document more of what I’ve learnt, but I’ve had a busy week at work implementing some cross-service observability tracing. I’m hoping I’ll find time to write about it at some point. But for now, I’m happy I’ve managed to keep my weekly Kubernetes streak going!