In this lab, we will explore our GKE cluster and get a feel for all the pieces that it’s comprised of. Additionally, we will get familiar with the Google Cloud CLI (gcloud) and the Kubernetes client (kubectl).
Cluster Creation #
Before we start looking around inside our GKE cluster, let’s quickly discuss how we can go about deploying a cluster. As our clusters have already been created, we’ll be going through a mock setup of a GKE cluster using the gcloud CLI (tool to create/manage Google Cloud resources).
At a bare minimum you can create a GKE cluster with the following command:
Note: Do not run the command below - this is simply a walkthrough of what the process would entail.
gcloud container clusters create my-gke-cluster
This will create a GKE cluster called my-gke-cluster with the default configuration. From there you can connect to it and start deploying your workloads!
Cluster Creation Flags #
There are many different components of your cluster you can implement and configure, which in turns means there are numerous flags we can add to our command to customize our cluster. We can choose to enable extra security features, to set it up for high-availability, to configure auto-scaling, etc. There are countless ways to configure your cluster depending on your needs.
Below are some of the flags we can add during cluster creation:
# Compute zone or region for the cluster
--location us-central1-a / us-central1
# The number of nodes to be created
--num-nodes==3
# The machine type to use for our worker nodes.
# Useful if we have more CPU or memory intensive workloads
--machine-type=e2-highcpu-4
# Size for node VM boot disks in GB
--disk-size=100
# Cluster is managed via a private API endpoint versus making it public
# This is how your GKE cluster is currently configured
--enable-private-endpoint
The documentation here covers the additional flags you can specify.
Interact with our Cluster using gcloud #
As mentioned previously, we have already deployed a GKE cluster for you to use. Let’s quickly walk through how we can inspect our cluster, before we start looking inside it.
Let’s get a list of what cluster(s) we currently have deployed:
gcloud container clusters list
You will see an output similar to below:
NAME LOCATION MASTER_VERSION MASTER_IP MACHINE_TYPE NODE_VERSION NUM_NODES STATUS
tenant us-central1-a 1.26.3-gke.1000 192.168.0.2 e2-highcpu-4 1.26.3-gke.1000 1 RUNNING
From here we can get a quick overview of the cluster(s) that currently exist in our Google Cloud project, as well as some useful information about them.
To get even more information about a specific cluster let’s run the following:
gcloud container clusters describe <YOUR_GKE_CLUSTER_NAME> --zone us-central1-a
This will describe our current cluster in a lot greater detail - useful for knowing what features and settings currently exist for your cluster.
Interact with our Cluster using kubectl #
Now let’s switch to looking at our cluster with the kubectl command-line tool. The gcloud CLI is primarily used for managing Google Cloud resources (like our GKE cluster) while the kubectl client allows us to run commands against our GKE cluster and manage Kubernetes specific resources. This is all done by interacting with the Kubernetes API, which in turns allows us to interact with our GKE cluster.
For starters, let’s get some information out of our cluster:
kubectl cluster-info
You will see an output similar to below:
Kubernetes control plane is running at https://192.168.0.2
GLBCDefaultBackend is running at https://192.168.0.2/api/v1/namespaces/kube-system/services/default-http-backend:http/proxy
KubeDNS is running at https://192.168.0.2/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
Metrics-server is running at https://192.168.0.2/api/v1/namespaces/kube-system/services/https:metrics-server:/proxy
For now we do not need to worry about understanding everything we’re looking at, let’s focus on the control plane piece.
Our control plane is what oversees our GKE cluster. It hosts the kube-apiserver component which exposes our control plane and is what allows us to interact with it using kubectl. The path listed is essentially where all our commands are being sent to.
Now let’s dig into what worker nodes we have in our cluster. Remember, worker nodes are where our containerized applications will run.
Run the following to list the nodes in our cluster:
kubectl get nodes
You will see an output similar to below:
NAME STATUS ROLES AGE VERSION
gke-tenant-tenant-nodepool-1-e3f0a87d-c6km Ready <none> 3h16m v1.26.3-gke.1000
From this output we can see what nodes exist in our cluster, what their status is, their uptime, and also what version of Kubernetes they’re running. This information is helpful in numerous ways, for knowing what nodes exist to getting a quick glance at their health.
Note: It should be noted that in a GKE cluster our control-plane nodes are managed by Google, therefore they don’t show up when running the kubectl get nodes command like they would in vanilla Kubernetes.
Let’s get a little more information from one of our nodes by using the describe command:
kubectl describe nodes <YOUR_GKE_WORKER_NODE_NAME>
After running the command we should get back a large amount of data. The describe command is useful for showing details of a specific resource - like a node.
From the information provided we can see lots of information about our node. We can see its IP address, what sort of CPU and memory capacity it has, what OS it’s running - pretty much any information we would need about our node.
Feel free to poke around the output and see what other information is provided.
Cluster Components #
Now let’s look at some of the components running on our nodes in our cluster.
First we’ll look at kube-dns, which acts as the DNS server for our cluster. We will dive deeper into DNS and the role it plays later, but for now let’s see if our resource responsible for DNS exists:
kubectl get deployments kube-dns --namespace=kube-system
With this command we’ve asked to return any deployment resources, that exist in the kube-system namespace, that match the name kube-dns. We won’t focus too much on what a deployment or a namespace is at this time, just looking to confirm that our kube-dns component exists.
You will see an output similar to below:
NAME READY UP-TO-DATE AVAILABLE AGE
kube-dns 1/1 1 1 10d
From here we can see our kube-dns exists as an output has been returned. We can also see some other useful information about it, like it’s up to date and available.
Let’s see if we can get a bit more information out of it using the describe command:
kubectl describe deployments kube-dns --namespace=kube-system
Similar to when we ran that command earlier we will be presented with a large amount of data about our kube-dns deployment object.
Extracting Specific Fields #
Let’s look at seeing if we can grab some specific fields from the data we got back from the last command we ran.
First, let’s run the following command:
Note: -n and -o are shorthands for --namespace and --output, respectively.
kubectl get deployments kube-dns -n kube-system -o json
This command outputs the contents of our kube-dns deployment resource in JSON format. Useful for when you want to inspect a resource in JSON.
Even more useful is being able to select a specific field from our returned output. To accomplish this we can use the JSONPath query language. We don’t need to understand the complete details of JSONPath, but just know that it allows us to filter on specific fields in the JSON object and format the output.
Let’s try seeing when our kube-dns deployment resource was created:
kubectl get deployments -n kube-system kube-dns -o=jsonpath='{.metadata.creationTimestamp}'
This should output a date for us when our resource was created.
Next let’s try the following:
kubectl get pods -n kube-system -o=jsonpath='{.items[*].metadata.name}'
This will output the name of every Pod resource that exists in the kube-system namespace. Let’s see if we can clean up the formatting:
kubectl get pods -n kube-system -o=jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}'
The JSONPath range function iterates over our list of items and then we add a newline after each element with {\n}.
Challenge #1 #
For our first challenge, let’s see if you can modify the following to only output the first Pod in the items list:
kubectl get pods -n kube-system -o=jsonpath='{.items[*].metadata.name}'
Challenge #2 #
For our second challenge let’s see if you can modify the following to output both the metadata.name and status.podIP fields, and make them comma (,) separated.
kubectl get pods -n kube-system -o=jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}'