9 min read

GKE: command-line tools

If you're starting using Google Cloud Platform, maybe after following my guide on deploying your first service to GKE, you'll probably want to setup a few command-line tools to be able to access your Kubernetes cluster from your terminal.

The usual tool to do that is kubectl, but as we're in the context of GCP/GKE here, we'll use the gcloud utility to set everything up.

Install gcloud and init

Google provides an interactive installer which makes this step easy.
Answers to the installation questions are obvious enough that we don't have to detail them here.

Once gcloud installed, start a new terminal session to load the new $PATH and the command completion.

Init  gcloud

Run gcloud init in your new terminal to initialize the tool.
It will send you to a Google login page so that you can choose the Google account you want to connect with when using gcloud. Once you've selected and authorized the correct account, go back to your terminal.

It will ask you to pick the GCP project you'd like to use: choose the one that holds the GCP resources you want to work with.
If you have several projects you'd like to be able to access, you can run gcloud init again and choose to create a new configuration for those projects (connecting to a different Google account if necessary).
You will then be able to switch between configurations using gcloud configurations activate <config name>.

Your project might have a randomly generated name, something like proud-dolphin-461842. If you don't know which to choose, head over to your Cloud Console home: your project ID is there:

You're then asked whether you'd like to configure a default Compute Region and Zone. You should say yes. I'm not sure which use case makes it less practical to do it, but if you don't you'll have to add a --region or --zone argument to all your gcloud calls.
Choose the region/zone where your resources are hosted. If you came from my GKE deployment guide, that would be the region you chose to create your cluster in.

Install the interactive CLI

gcloud comes with a very handy interactive CLI to help you discover commands and their parameters. It's a beta feature that you can access using gcloud beta interactive.

The first run of this command will install the component for you. Then, it'll run it:

Auto-completion and command's help built in!

Personally, I have added an alias to my zsh profile so that ig will open this interactive CLI:

alias ig="gcloud beta interactive"
In ~/.zshrc or ~/.bashrc

Install kubectl component

Run the following to install kubectl on your machine:

gcloud components install kubectl

You might a warning at the end of the installation, letting you know another version of kubectl has been found on your computer. It can happen if you've installed Docker for Mac for instance.

To make sure you're using gcloud's version of kubectl, use which kubectl; the tool's path should look like this: /Users/olance/google-cloud-sdk/bin/kubectl.
If it doesn't, tweak your $PATH variable or remove the other version you've got.

Configure kubectl for your GKE cluster

Once again, gcloud will help you configure things properly.
Just run this command to have a kubectl config generated for your GKE cluster:

$ gcloud container clusters get-credentials test-cluster
Fetching cluster endpoint and auth data.
kubeconfig entry generated for test-cluster.
Replace test-cluster with your own cluster's name

If you're not sure what the name of your cluster is, gcloud can tell you:

$ gcloud container clusters list
NAME          LOCATION        MASTER_VERSION  MASTER_IP       MACHINE_TYPE   NODE_VERSION   NUM_NODES  STATUS
test-cluster  europe-west1-b  1.12.8-gke.10   35.195.214.142  n1-standard-1  1.12.8-gke.10  1          RUNNING

Finally, if you've got a single cluster, or at least one main cluster you want to be working with, I highly encourage you to set it default in your config:

$ gcloud config set container/cluster test-cluster
Updated property [container/cluster].

This will automatically fill in the --cluster argument in commands that require it.

Explore your Kubernetes resources

Now that everything is set up, you can start playing!

gcloud vs. kubectl

Since you are on GKE, you have to keep in mind that it brings its own concepts on top of those from Kubernetes. This will help you know which tool to use when you want to get detailed information about a resource.
I covered the subject in my introduction to deploying to GKE.

As a result, you'll use kubectl to get information on your nodes, pods, deployments, services, config maps and secrets (kubectl api-resources will give you a full list), whereas gcloud can be used to get information on your cluster, node pools, and the VM instances that are used to concretize your k8s nodes.

kubectl: get & describe

Your best friends to learn more about your k8s resources are kubectl get <type> and kubectl describe <type>/<name>.

To get started, you can try kubectl get all:

$ kubectl get all
NAME                            READY   STATUS    RESTARTS   AGE
pod/wordpress-d74bfbbc4-qg6fl   1/1     Running   0          3d

NAME                      TYPE           CLUSTER-IP      EXTERNAL-IP    PORT(S)        AGE
service/kubernetes        ClusterIP      10.119.0.1      <none>         443/TCP        3d
service/wordpress-dq858   LoadBalancer   10.119.13.142   34.76.216.33   80:32647/TCP   3d

NAME                        DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/wordpress   1         1         1            1           3d

NAME                                  DESIRED   CURRENT   READY   AGE
replicaset.apps/wordpress-d74bfbbc4   1         1         1       3d
replicaset.apps/wordpress-ff54c57ff   0         0         0       3d

NAME                                                REFERENCE              TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
horizontalpodautoscaler.autoscaling/wordpress-hpa   Deployment/wordpress   1%/80%    1         1         1          3d

Here I can see I've got one pod running, two services, one deployment, two replicasets (including an obsolete one) and one horizontal pod autoscaler, which is used to automatically spin up new pods for the wordpress deployment.

Let's delete the useless replicaset:

$ kubectl delete replicaset.apps/wordpress-ff54c57ff
replicaset.apps "wordpress-ff54c57ff" deleted

I want to learn more about the pod:

$ kubectl describe pod/wordpress-d74bfbbc4-qg6fl
Name:               wordpress-d74bfbbc4-qg6fl
Namespace:          default
Priority:           0
PriorityClassName:  <none>
Node:               gke-test-cluster-default-pool-7fa0b2b7-pdqm/10.132.0.2
Start Time:         Sun, 26 Sep 2019 11:20:21 +0200
Labels:             app=wordpress
                    pod-template-hash=d74bfbbc4
Annotations:        kubernetes.io/limit-ranger: LimitRanger plugin set: cpu request for container wordpress
Status:             Running
IP:                 10.52.0.10
Controlled By:      ReplicaSet/wordpress-d74bfbbc4
Containers:
  wordpress:
    Container ID:   docker://f8732ac0514ddc25c11625941f619b3d98dbddef4a57eb6f33a37147d3a82c21
    Image:          wordpress:latest
    Image ID:       docker-pullable://wordpress@sha256:0524b6843bd9a310c8e7201fd2d624b9db84baf57e65abf6c22426cd09b55426
    Port:           <none>
    Host Port:      <none>
    State:          Running
      Started:      Sun, 26 Sep 2019 11:20:43 +0200
    Ready:          True
    Restart Count:  0
    Requests:
      cpu:  100m
    Environment:
      WORDPRESS_DB_HOST:      <set to the key 'WORDPRESS_DB_HOST' of config map 'wordpress-config'>  Optional: false
      WORDPRESS_DB_USER:      <set to the key 'WORDPRESS_DB_USER' of config map 'wordpress-config'>  Optional: false
      WORDPRESS_DB_NAME:      <set to the key 'WORDPRESS_DB_NAME' of config map 'wordpress-config'>  Optional: false
      WORDPRESS_DB_PASSWORD:  <set to the key 'DB_PASSWD' in secret 'wordpress-db'>                  Optional: false
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-pz6ww (ro)
Conditions:
  Type              Status
  Initialized       True
  Ready             True
  ContainersReady   True
  PodScheduled      True
Volumes:
  default-token-pz6ww:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-pz6ww
    Optional:    false
QoS Class:       Burstable
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:          <none>

If you've followed my deploy guide to GKE, you will probably recognize some of the information here!

Note that nodes aren't listed by kubectl get all, so let's list them specifically:

$ kubectl get nodes
NAME                                          STATUS   ROLES    AGE   VERSION
gke-test-cluster-default-pool-7fa0b2b7-pdqm   Ready    <none>   3d   v1.12.8-gke.10

If you describe a node, you get interesting information about the pods it's hosting and the resources currently in use:

$ kubectl describe node/gke-test-cluster-default-pool-7fa0b2b7-pdqm
... redacted for your brain's sake ...
Non-terminated Pods:         (7 in total)
  Namespace                  Name                                                      CPU Requests  CPU Limits  Memory Requests  Memory Limits  AGE
  ---------                  ----                                                      ------------  ----------  ---------------  -------------  ---
  default                    wordpress-d74bfbbc4-qg6fl                                 100m (10%)    0 (0%)      0 (0%)           0 (0%)         3d
  kube-system                heapster-v1.6.1-6bf7c45b48-qxvz5                          63m (6%)      63m (6%)    215840Ki (7%)    215840Ki (7%)  2d
  kube-system                kube-dns-564d97dc9c-vsvxr                                 260m (27%)    0 (0%)      110Mi (4%)       170Mi (6%)     3d
  kube-system                kube-dns-autoscaler-76fcd5f658-xbxnt                      20m (2%)      0 (0%)      10Mi (0%)        0 (0%)         2d
  kube-system                kube-proxy-gke-test-cluster-default-pool-7fa0b2b7-pdqm    100m (10%)    0 (0%)      0 (0%)           0 (0%)         3d
  kube-system                l7-default-backend-6f8697844f-7sfd5                       10m (1%)      10m (1%)    20Mi (0%)        20Mi (0%)      2d
  kube-system                metrics-server-v0.3.1-5b4d6d8d98-hk2pw                    48m (5%)      143m (15%)  105Mi (3%)       355Mi (13%)    2d
Allocated resources:
  (Total limits may be over 100 percent, i.e., overcommitted.)
  Resource                   Requests        Limits
  --------                   --------        ------
  cpu                        601m (63%)      216m (22%)
  memory                     466720Ki (17%)  773920Ki (28%)

You can see I've got 7 pods running on that node: 6 are from the kube-system namespace, meaning they're not my own pods but services required by Kubernetes or GKE: heapster and metrics-server are used for monitoring, kube-dns* for networking purposes and l7-default-backend, which is an HTTP load balancing service.
In the default namespace, there's my wordpress pod.

In terms of resource, you can see that I'm requesting 63% of my node's CPU capacity, and 17% of its memory capacity.
To get a better understanding of requests and limits, check out this post on Google Cloud's blog.

gcloud: list & describe

The syntax for gcloud commands is similar to the kubectl ones: gcloud <module> <type> <list> and gcloud <module> <type> <describe> <name>.
The one thing that can be tricky at first, is figuring out what module you should look into. There are many, so here's a quick rule of thumb: if the resource is specific to GKE, it's going to be container; else, you should try compute.

Resource type Module List command
Cluster container gcloud container clusters list
Node pool container gcloud container node-pools list
Node (the VM instance) compute gcloud compute instances list

With what we've covered so far on this blog, compute might not seem so important, but that's also where you'll find forwarding-rules, backend-services, backend-buckets and the other resources related to HTTP(S) Load Balancers.

Access your pods

Port forwarding

If you've got a running pod, but it's not exposed via a service, you can still access whatever's running on it using port forwarding.

Let's take the example of my wordpress pod:

$ kubectl get pods
NAME                        READY   STATUS    RESTARTS   AGE
wordpress-d74bfbbc4-qg6fl   1/1     Running   0          3d

$ kubectl port-forward wordpress-d74bfbbc4-qg6fl 8888:80
Forwarding from 127.0.0.1:8888 -> 80
Forwarding from [::1]:8888 -> 80

I can now access my Wordpress instance listening to the port 80 of this pod, by connecting to http://localhost:8888!

Please just take a second to think about what's going on behind the scene of this very simple command 🤯

Note that you can do the same with a deployment instead of a single pod:

$ kubectl port-forward deployment/wordpress 8888:80

SSH into your pod's containers

It might be handy sometimes to get into a running container of your pod, for debug purposes for instance.

Once again kubectl makes this super easy. You need to know your pod's name, and the name of the container you want to enter. Then it's very similar to what you'd do with Docker:

$ kubectl describe pod/wordpress-d74bfbbc4-qg6fl
Name:               wordpress-d74bfbbc4-qg6fl
Namespace:          default
...
Containers:
  wordpress:    <- this is the container's name
    ...
    
$ kubectl exec -it wordpress-d74bfbbc4-qg6fl -c wordpress bash
root@wordpress-d74bfbbc4-qg6fl:/var/www/html#

Note that you can omit the container argument (-c wordpress here): exec will then run the specified command within the first container in the pod. When it's a single-container pod, that makes things even easier!

Wrapping up

I hope this little tour of gcloud and kubectl will help you get started with managing your Kubernetes cluster from the command line!

And if you're into automation, you should know that both commands allow you to get YAML or JSON output, which will be easily processable within your scripts.
Simply add --output=json or --format=json to your kubectl/gcloud commands!

btn secont