A Crash Course in Google Kubernetes Engine (GKE)

Try to container your excitement 🥁

James Collerton
8 min readNov 15, 2022
Modern tech for modern problems.

Audience

This article is aimed at engineers with a reasonable understanding of Kubernetes. A little React might be helpful, but you’ll be able to scrape through without it.

If you need help with Kubernetes, an article I previously wrote on the subject resides here. We will build on the ideas within the article, so it will be worth having a quick flick through.

It will also help to have an appreciation of Google Cloud Platform (GCP) and its use case. However, we will provide enough detail such that hands-on experience is not required.

Argument

To begin, let’s summarise some of the key Kubernetes terms.

Pods

Pods are the atomic units of Kubernetes. They are a group of containers that share their storage, IP address and how they are deployed. The contents of a pod are always run in a shared context.

The most common use case is having a single container running on a pod. However, you may occasionally want multiple containers. For example, one could be generating data to store in a volume, while the other reads from it.

An important thing to note is that as we scale we add more pods. If we want to add more instances of a service we add more pods, not more containers to the pod.

Nodes

A Node is a virtual or physical machine where the pods are run. Multiple Pods can run on a Node. Generally you will have multiple Nodes running in a cluster. This offers some resiliency in case one goes down.

Where and how Pods are run on a cluster is handled by the Control Plane (covered in a later section). Each Node has a container runtime (something we can use to run images, such as Docker), kubelet and a kube-proxy (also covered in a later section).

Control Plane

The Control Plane is responsible for assigning Pods to Nodes. In a physical sense it is a set of services (including an API for interaction) that sit across one or more machines.

Kubelet

Kubelet runs on each Node and is responsible for communicating with the control plane. It looks after all of the pods and containers on the machine.

Kube-Proxy

The kube-proxy tool runs on each Node and maintains its network rules. It’s what allows network communication from inside or outside your cluster.

A visual summary of a Kubernetes Cluster so far

Controllers

Controllers in Kubernetes represent continually running functionality responsible for monitoring your cluster. Each Controller has a desired state (e.g. you have enough Nodes to comfortably serve your traffic). The purpose of the Controller is to adjust your cluster such that the desired state is achieved.

Notice, as with the sufficient Nodes example, this might require action outside of your cluster (in this case adding more machines).

ReplicaSets

So how do we know how many Pods (and therefore containers) we would like to run? This is the role of ReplicaSets. These guarantee a stable set of Pods running.

However, it’s important to note that we don’t normally deal directly with ReplicaSets. Instead we use Deployments.

Deployments

Deployments bring together our last two concepts: Controllers and ReplicaSets.

Within a Deployment you describe your desired state, and a Deployment Controller attempts to match the actual and desired states.

In reality Deployments instruct Kubernetes how to adjust Pods. They can add or remove them (scaling your service using ReplicaSets) and roll out/ roll back code.

Services

A Kubernetes Service is a way of grouping and exposing a set of Pods as a network service.

For example, we may be running a backend service using three Pods. We don’t want to have to individually expose each Pod, instead we want a way of making them look and behave like a single instance.

Kubectl

Although not necessarily a direct part of the Kubernetes cluster, kubectl is a vital part of the wider ecosystem. It is through this tool that we communicate with our cluster’s control plane and carry out actions.

Some example commands include:

  • kubectl logs: Displays the logs from a container in a Pod.
  • kubectl exec: Executes a command on a container in a Pod.

Immediately we can see how useful this will be.

OK, hopefully at this point we all have a good understanding of some of the core Kubernetes concepts. At least if we reference them in later sections then you have something to look back on.

Introducing GKE

From here we want to clarify what separates the Google Kubernetes Engine from plain old Kubernetes.

Initially, GKE gives you everything the original does. Rolling updates, automatic management, monitoring and scaling.

On top of this, GKE provides a managed environment for scaling, supervising and deploying containers. This means they look after all of the nodes (using Compute Engine instances) so you don’t have to.

Google also supply a smattering of extra tidbits.

  • Load Balancing: As we will see when we expose our container as a service, we will use a GCP load balancer to distribute traffic amongst Pods.
  • Node Pools: This is a group of Nodes within a cluster that have the same configuration. For example we may want to schedule adding a group of more powerful Nodes for certain events.
  • Autoscaling: We can leverage Google’s scaling capabilities to keep our app responsive.
  • Logging and Monitoring: Logs and metrics will be pushed to the GCP dashboard.
  • Automatic Upgrades: Nodes will be kept up to date.
  • Node Auto-Repair: If your Node becomes unhealthy it is taken out of circulation and replaced.

Another thing to note is GKE’s Modes of Operation. There are two flavours:

  • Autopilot: Manages your Cluster and Node infrastructure for you, so you can focus on your application.
  • Standard: You configure your Cluster and Node infrastructure for greater control.

In the following example we will use autopilot.

Worked Example

For the next section I created a free GCP account. Once you’re done you should receive a screen similar to the below.

Introductory splash screen

We will break down our example into the following stages:

  1. Introduce our app: Talk about the app we want to run on GKE.
  2. Create an image to run: Turn the app code into an image and push it up to a registry.
  3. Create the cluster: Create the cluster where we intend to run our image as a container.
  4. Create the Deployment: In this stage we start the container running.
  5. Expose our app: Here we create the Service which will allow us to connect to the app.
  6. Check it’s working: Now we visit and make sure we can see something.
  7. Update: The last thing we want to do is update the app code to show how we can do further Deployments.

Let’s go!

First of all, we will be reusing an existing React app that can be found here. All of the information for building it in the article here. When you get it running you should see the below.

Our example React app

We will know we’ve succeeded when we can access this screen!

Let’s create a new project in GCP. This will let us group our resources and easily remove them when we need to.

Creating a new project

Now we need to create an image to push to our repository. We will need to install the gCloud CLI. Once this is done and initialised (remember to pick your new project in this step) we should be good to go!

The next section will be loosely based around the guide here. First we run:

gcloud config get-value project

If everything is set up correctly this should return gke-example-app.

Now we set up our repository. Use the below command and pick a region from the list.

gcloud compute regions list

Notice how we pick the London region to minimise latency.

gcloud artifacts repositories create gke-example-app \
--project=gke-example-app \
--repository-format=docker \
--location=europe-west2 \
--description="Docker repository"

We may be prompted to enable some functionality, go ahead and do so. Notice how we used artifact registry, not container registry. The reason for doing so is in the article here.

Now we need to tag our local image using the below (and docker image ls to list the images to find the Id).

docker tag <IMAGE_ID> europe-west2-docker.pkg.dev/gke-example-app/gke-example-app/gke-example-image

Let’s push the image to our new registry. First we need to authenticate.

gcloud auth configure-docker europe-west2-docker.pkg.dev

Then we can push.

docker push europe-west2-docker.pkg.dev/gke-example-app/gke-example-app/gke-example-image

Once all of this is done we should be able to see our image in our registry!

Image available in our registry

From here we need to create our own cluster. This can be done fairly easily using the below.

gcloud container clusters create-auto gke-example-app \
--region europe-west2

If at this point you get an error about services not being enabled we may have to run some extra commands (especially with a brand new GCP account).

Once this is done you should see your cluster in the GCP console!

GKE Cluster in the console, notice it is in Autopilot mode

If you’re like me you’ll also be prompted by the CLI to install the gke-gcloud-auth-plugin.

Now we need to define a Deployment (exactly as described before). We do this by creating a deployment.yaml file.

We then enact it using the below:

kubectl apply -f deployment.yaml

We wait a moment until it is up.

Now we need to deploy a Service (again, exactly as described before) in order to expose our application. We write another .yaml file defining what it looks like.

And enact is using:

kubectl apply -f service.yaml

This should create the Service we require. By running

kubectl get services

We can find the external IP address of our application. Visiting it in the browser gives us the below.

Success!

The last thing we want to cover is how to update our application. We alter the code. I’ve added an extra line to the description to form the below.

An update to our application

In order to update what’s running in our cluster we first need to update our image. Rebuild, retag and re-push it using the previous commands. We can now (slightly) cheat and force a redeployment using:

kubectl rollout restart deployment/gke-example-app

Which will force a rolling redeployment using the ‘latest’ tag. Visiting our external IP we now get the same result we did locally!

Conclusion

In conclusion we have discussed Kubernetes, related it to GCP and shown how to deploy a basic application to the platform.

--

--

James Collerton

Senior Software Engineer at Spotify, Ex-Principal Engineer at the BBC