Skip to main content

Working with clusters (kubectl)

Exam guide§2.1

Once a cluster exists and kubectl has credentials, you drive it entirely through kubectl. Know how the kubeconfig file and contexts work, the everyday inspect / deploy / introspect commands, and the difference between imperative kubectl create and declarative kubectl apply -f.

The kubeconfig file and contexts

gcloud container clusters get-credentials writes a kubeconfig file (default ~/.kube/config) holding the endpoint + auth details for a cluster, then sets it as the active context. kubectl runs every command against whichever cluster the current-context points to.

~/.kube/configgke_proj_us-central1_autopilot-cluster-1current-contextgke_proj_us-east1_web-clustergke_proj_europe-west1_batchkube-APIserver(active cluster)
One kubeconfig file (~/.kube/config) can hold many contexts; current-context marks the single active cluster kubectl talks to. A context name is gke_PROJECT_LOCATION_NAME.
FactsContexts
  • A single kubeconfig (~/.kube/config) can hold many clusters/contexts; current-context marks the one active cluster.
  • A GKE context name is gke_PROJECT_LOCATION_NAME - the gke prefix, project ID, location, and cluster display name, joined by underscores.
  • kubectl config view prints the file with certificate data replaced by DATA+OMITTED.
CommandsInspect and switch contexts
kubectl config view # print the kubeconfig (sensitive data omitted)
kubectl cluster-info # control plane + add-on service endpoints of active cluster
kubectl config current-context # name of the active cluster
kubectl config get-contexts # list all contexts, marking the active one
 
# switch the active cluster (needs the full gke_PROJECT_LOCATION_NAME)
kubectl config use-context gke_${DEVSHELL_PROJECT_ID}_us-central1_autopilot-cluster-1
 
source <(kubectl completion bash) # enable Tab autocompletion for kubectl
GotchaYou only re-run `get-credentials` for someone else's cluster

Clusters you created in the same context (same user, same environment) already have their kubeconfig entry populated at creation time - no get-credentials needed. You do run it to connect to a cluster created by another user or environment, or as an easy way to switch the active context.

Inspecting a cluster

CommandsEveryday inspection
kubectl get pods # all pods in the active cluster
kubectl top node # CPU / memory usage per node
kubectl top pods # CPU / memory usage per pod
kubectl describe pod POD_NAME # full pod detail: image, QoS, conditions, events
Gotcha`top` and fresh deployments need a moment

kubectl top returns "metrics not available yet" until the metrics-server has data - just re-run it. Likewise a just-created pod may report "server is currently unable to handle the request" until the deployment finishes and becomes Ready. On Autopilot, a new pod can also show a transient FailedScheduling / TriggeredScaleUp event while the cluster autoscales a node in to fit it - this is normal, not an error.

Deploying pods

A Pod groups one or more containers scheduled together as a unit. Deploy one imperatively, or declaratively from a manifest.

Imperative - kubectl create

kubectl create deployment --image nginx nginx-1

With no registry in the image name, the image is pulled from Docker Hub (the default public registry).

Declarative - kubectl apply -f

The preferred way is a manifest (a YAML "config file"), which captures complex options far more readably than a long command line. YAML is more concise than JSON but gives the same hierarchical structure.

apiVersion: v1
kind: Pod
metadata:
name: new-nginx
labels:
name: new-nginx
spec:
containers:
- name: new-nginx
image: nginx
ports:
- containerPort: 80
kubectl apply -f ./new-nginx-pod.yaml
Best practicePrefer manifests over long command lines

kubectl create is imperative and fine for a quick pod; kubectl apply -f with a manifest is declarative - the desired state is documented in a file you can version, review, and re-apply. This mirrors the declarative-first rule: reach for manifests, use imperative commands for quick fixes.

Serving content and exposing a pod

You can copy a file straight into a running container, then expose the pod so external clients can reach it.

CommandsPush a file, expose the pod
# copy a local file into the first container of a pod
# (-c CONTAINER selects a specific container in a multi-container pod)
kubectl cp ~/test.html $my_nginx_pod:/usr/share/nginx/html/test.html
 
# expose a pod externally via a LoadBalancer service
kubectl expose pod $my_nginx_pod --port 80 --type LoadBalancer
 
kubectl get services # watch for the EXTERNAL-IP to populate
curl http://EXTERNAL_IP/test.html
GotchaEXTERNAL-IP starts as `<pending>`

A LoadBalancer service shows <pending> in the EXTERNAL-IP column until GCP provisions the load balancer - re-run kubectl get services a few times until the IP appears. A pod needs a Service to be reachable from outside the cluster at all.

Introspecting a live pod

Use these for troubleshooting or experimenting only - changes made this way are not in the pod's source image, so they won't appear in replicas.

CommandsShell in, forward a port, tail logs
# interactive shell inside a container (-c CONTAINER for a specific one)
kubectl exec -it new-nginx -- /bin/bash
 
# forward local port 10081 -> pod port 80 (foreground; needs a second shell to test)
kubectl port-forward new-nginx 10081:80
curl http://127.0.0.1:10081/test.html
 
# stream logs live, with timestamps
kubectl logs new-nginx -f --timestamps
GotchaLive pod edits don't persist to replicas

Editing files or installing tools inside a running container (via kubectl exec) changes only that one live container, not the image. Any new replica starts from the original image without your changes. Bake changes into the image (or a manifest) to make them durable.

Gotcha`port-forward` is a foreground process

kubectl port-forward blocks the terminal while forwarding, so you need a second Cloud Shell session to curl the pod. It also skips the need for a Service - handy for testing a single pod directly without exposing it.

Recap

Commandskubectl workflow
# connect
gcloud container clusters get-credentials CLUSTER --region REGION
kubectl config current-context
 
# inspect
kubectl get pods
kubectl top node
kubectl describe pod POD
 
# deploy (declarative)
kubectl apply -f pod.yaml
 
# expose + test
kubectl expose pod POD --port 80 --type LoadBalancer
kubectl get services
 
# introspect
kubectl exec -it POD -- /bin/bash
kubectl port-forward POD 10081:80
kubectl logs POD -f --timestamps