← Back to posts

GCP ACE: Operating a GKE Cluster with kubectl

The last three articles got a cluster built and a workload running behind a public IP. This one closes the GKE module with the commands you reach for once things are already deployed — when a Pod is misbehaving and you need to find out why.

Inspecting the cluster and nodes

kubectl cluster-info                 # control plane and service endpoints
kubectl get nodes -o wide            # node list, with internal/external IPs, OS, container runtime
kubectl describe node NODE_NAME      # capacity, allocatable resources, conditions, recent events
kubectl top node                     # live CPU/memory usage per node (needs metrics-server)

On Autopilot, you can’t SSH into these nodes or change their configuration — but you can still read their status, which matters when you’re diagnosing why a Pod won’t schedule (describe node will show if a node is out of allocatable CPU or memory, for instance).

Listing and inspecting Pods

kubectl get pods                     # Pods in the current namespace
kubectl get pods -A                  # Pods in every namespace (--all-namespaces)
kubectl get pods -o wide             # adds node name and Pod IP
kubectl get pods -l app=web          # filter by label
kubectl describe pod POD_NAME        # full event history: scheduling, pulls, probe failures, restarts

kubectl describe pod is usually the first command to run when a Pod is stuck Pending or crash-looping — the Events section at the bottom shows exactly what’s blocking it (image pull failure, insufficient resources, failed readiness probe, and so on).

Reading logs

kubectl logs POD_NAME                        # logs from the Pod's (single) container
kubectl logs POD_NAME -c CONTAINER_NAME      # a specific container in a multi-container Pod
kubectl logs POD_NAME -f                     # stream logs live (--follow)
kubectl logs POD_NAME --tail=100             # last 100 lines only
kubectl logs POD_NAME -p                     # logs from the PREVIOUS instance of the container

That last one — -p / --previous — is the one people forget and need most: when a container has already crashed and restarted, kubectl logs without -p shows the new (often empty) container’s logs, not the one that actually failed. If a Pod shows CrashLoopBackOff, -p is how you see why it died the first time.

Getting a shell inside a Pod

kubectl exec -it POD_NAME -- /bin/sh
kubectl exec -it POD_NAME -c CONTAINER_NAME -- bash

The -- separates kubectl’s own flags from the command to run inside the container; -i keeps stdin open and -t allocates a terminal, which together is what makes it feel like an interactive shell instead of a one-shot command. If the image has no shell at all (common for minimal production images), this won’t work — in that case, attach an ephemeral debug container instead:

kubectl debug -it POD_NAME --image=busybox --target=CONTAINER_NAME

Port-forwarding for local access

Sometimes you want to hit a Pod or Service directly from your own machine without going through its public load balancer (or when it has none):

kubectl port-forward pod/POD_NAME 8080:80        # local:8080 -> pod port 80
kubectl port-forward svc/SERVICE_NAME 8080:80     # same, but via a Service

The format is always LOCAL_PORT:REMOTE_PORT. The forward stays open in your terminal until you stop it with Ctrl+C, and by default only your own machine (localhost) can reach it.

A diagnostic flow worth memorizing

For the exam, and in practice, this is the order that actually finds the problem fastest:

  1. kubectl get pods — is it Pending, CrashLoopBackOff, ImagePullBackOff, or Running?
  2. kubectl describe pod POD_NAME — read the Events section at the bottom.
  3. kubectl logs POD_NAME (add -p if it already restarted) — read what the application itself said.
  4. kubectl exec -it POD_NAME -- sh — if you need to poke around inside while it’s still alive.

Exam Takeaways

Sources

↗ LinkedIn