Imperative kubectl
Inspecting and debugging
You've spent the whole course writing YAML, and that's fine: declarative is the right way to define systems. But when something is on fire at three in the morning, nobody opens the editor: you open a terminal and interrogate the cluster. This module trains that other half of the trade, and it does so in mission format: the tienda Namespace of this playground hides data you'll only find with the right commands.
The scenario: an api Deployment with a history (four revisions and counting), a Service, a Secret with credentials, and a Pod called worker-legacy that nobody trusts. Work from the dev-machine tab.
The inspection arsenal
The usual questions and the command that answers each one, straight from the book:
How do I see the main resources of a Namespace at a glance?
kubectl get all -n tienda
Watch out for the white lie in the name: get all does not include ConfigMaps, Secrets, Ingress or PersistentVolumeClaims. Check it: the Secret you'll see later on doesn't show up.
How do I list the Pods with their assigned node and more detail?
kubectl get pods -n tienda -o wide
How do I find Pods by label across all Namespaces?
kubectl get pods -A -l app=api
Labels can be combined (-l app=api,env=prod). It's the same selection mechanism Services and Deployments use, now at your fingertips.
How do I see which image each Pod is using?
kubectl get pods -n tienda -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[*].image}{"\n"}{end}'
The jsonpath format looks cryptic the first time and becomes addictive by the third: it pulls out exactly the field you want, with no noise.
How do I list resources sorted by creation time?
kubectl get all -n tienda --sort-by=.metadata.creationTimestamp
Mission 1: the previous run of worker-legacy
The worker-legacy Pod shows up Running with an innocent look on its face, but notice its RESTARTS column: it has crashed at least once. The team wants to know the failure code it ended with on its first start.
The catch is that kubectl logs has a short memory: it shows the current container. To hear from the previous run:
How do I see the logs of the previous container after the Pod has crashed?
kubectl logs worker-legacy -n tienda --previous
Compare it with the logs without --previous: the current container hasn't said a word. Other variants of the family it helps to keep at hand:
kubectl logs -n tienda deploy/api | grep ERROR
kubectl logs -f -l app=api -n tienda --all-containers=true
The first filters by text (and takes the Deployment name directly, no need to look up the Pod); the second follows in real time the logs of every Pod matching a label.
Mission 2: the planted variable
The Pods of the api Deployment carry a DATABASE_URL environment variable nobody documented. You need its exact value.
A process's variables are read from inside the process, and that's what exec is for:
How do I run a one-off command without opening a shell?
kubectl exec -n tienda deploy/api -- printenv DATABASE_URL
How do I open a shell inside a Pod, to explore at leisure?
kubectl exec -it <pod> -n tienda -- /bin/sh
And the two tools that complete the diagnostic kit for any Pod, which you already know from the course, now with their finer variants:
kubectl describe pod <pod> -n tienda
kubectl get events -n tienda --field-selector involvedObject.name=<pod> --sort-by='.lastTimestamp'
The second pulls the Events of one specific object, sorted: gold when describe falls short because the Events have already rotated out.
The network kit, for when the time comes
Three network debugging commands that need no mission, but do need a place in your memory:
kubectl port-forward svc/api 8080:80 -n tienda
kubectl cp tienda/<pod>:/ruta/al/fichero ./fichero-local
kubectl run debug --image=ghcr.io/iximiuz/labs/nginx:alpine -it --rm -- /bin/sh
The first forwards a local port to the Service (it also works with pod/<name>); try it and you'll see nginx with curl localhost:8080 from another terminal for as long as the tunnel lives. The second copies files between a Pod and your machine (the placeholders read "path/to/file" and "local-file"). The third spins up a temporary Pod (--rm deletes it on exit) to sniff around the network from inside the cluster; the book uses the nicolaka/netshoot image, the Swiss Army knife of networking, when the registry allows it.
In the next unit you go from looking to touching: scaling, surgical rollbacks and the contents of that Secret.
Acting on the cluster
Inspecting was half the job. The other half is intervening: scaling, rolling back, restarting, reading secrets. Same scenario, new missions.
Mission 3: the Secret's password
Someone needs the password stored in the db-credentials Secret of the tienda Namespace, and they need it now. Remember two things from the Configuration module: Secrets store their values in base64, and base64 is not encryption.
How do I extract a Secret and decode it in a single line?
kubectl get secret db-credentials -n tienda -o jsonpath='{.data.password}' | base64 --decode
This question's twin, for non-sensitive configuration:
How do I edit a ConfigMap directly in the cluster?
kubectl edit configmap <nombre> -n tienda
kubectl edit opens the live object in your editor and applies it when you save. Powerful and dangerous in equal measure: the change doesn't land in any file of yours. In the next lesson you'll see the civilized alternative.
Mission 4: traffic spike
Marketing has just launched a campaign without warning (as usual) and the api Deployment needs to go from 3 to 5 replicas right now.
How do I scale a Deployment?
kubectl scale deployment/api --replicas=5 -n tienda
And the tools to check that the cluster is holding up under the change:
kubectl top pods -n tienda --sort-by=memory
kubectl top nodes
kubectl get pods -A --field-selector spec.nodeName=<nodo>
The first two you already know from the Horizontal Pod Autoscaler lesson; the third answers a question you'll ask sooner or later: which Pods are running on a specific node (useful before maintenance).
Mission 5: the good revision was a different one
A message comes in from the team: the current version of api (with APP_MODE=estable, "stable" in Spanish) has a subtle bug, and the last known good version is the one that carried APP_MODE=beta. You have to go back to exactly that one, and guessing isn't allowed: you have to look it up.
How do I see a Deployment's revision history?
kubectl rollout history deployment/api -n tienda
kubectl rollout history deployment/api -n tienda --revision=2
The second form shows the template of one specific revision: that's how you identify which one carried what before you jump.
How do I roll back to a specific revision?
kubectl rollout undo deployment/api --to-revision=<n> -n tienda
And how do I watch the rollback converge?
kubectl rollout status deployment/api -n tienda
The rollout family is completed by a command that reverts nothing but saves whole days:
kubectl rollout restart deployment/api -n tienda
It restarts every Pod of the Deployment gradually, with no downtime. It's Kubernetes's elegant "turn it off and on again": essential when you change a mounted ConfigMap and want the Pods to reread their configuration.
The finishing touch: aliases
No Kubernetes operator types kubectl get pods letter by letter two hundred times a day. In your ~/.bashrc or ~/.zshrc:
alias k='kubectl'
alias kgp='kubectl get pods'
alias kgpa='kubectl get pods -A'
alias kl='kubectl logs -f'
alias kx='kubectl exec -it'
export do='--dry-run=client -o yaml'
💡 That last export is the bridge to the next lesson: k create deploy api --image=nginx $do > deploy.yaml generates the manifest without creating anything. The imperative mode writing YAML for the declarative mode: the best of both worlds.
Summary
- Inspection:
get(with-o wide,-l,-A,jsonpath,--sort-by),describe,events --field-selector. - Debugging:
logs(with--previous,-f,-l,deploy/),exec,port-forward,cp, temporary Pods with--rm. - Action:
scale, the wholerolloutfamily (status, history, undo,--to-revision, restart),edit. - And the elegant way out:
--dry-run=client -o yaml, which turns everything imperative into declarative files.
- Previous lesson
- Devices and Dynamic Resource Allocation
- Next lesson
- Declarative kubectl