kubectl, day to day
The kubectl subset you will actually use, the output formats that make it useful, and how Kustomize and Helm fit in once raw YAML stops scaling.
Looking at things
kubectl get pods
kubectl get pods -o wide # node, IP, and more
kubectl get pods -w # watch for changes
kubectl get pods -A # every namespace
kubectl get all # the common types in this namespace
kubectl get pods -l app=web # filter by label
kubectl get pods --sort-by=.status.startTime
kubectl describe is where you go when get is not enough:
kubectl describe pod web-7d4b9c8f5-x2k9p
Logs
kubectl logs web-7d4b9c8f5-x2k9p
kubectl logs -f deployment/web # follow, across the deployment
kubectl logs --tail=100 --timestamps pod/web-...
kubectl logs pod/web-... --previous # the container before the last restart
kubectl logs -l app=web --all-containers # every pod with this label
--previous is the one people forget. When a pod is crash-looping, the logs you want are from
the previous instance, because the current one has barely started.
stern web # tail every matching pod, colour-coded
Getting inside
kubectl exec -it deployment/web -- sh
kubectl exec pod/web-... -- env
kubectl debug pod/web-... -it --image=nicolaka/netshoot # for distroless images
kubectl debug attaches an ephemeral container with debugging tools into an existing pod’s
namespaces — the answer for images with no shell.
Port forwarding
kubectl port-forward svc/web 8080:80
kubectl port-forward pod/postgres-0 5432:5432
This is how you reach an internal service from your laptop without exposing it. It is the right tool for debugging a database, and the wrong tool for anything permanent.
Applying and deleting
kubectl apply -f deployment.yaml
kubectl apply -f ./manifests/ # a whole directory
kubectl apply -k ./overlays/prod # a Kustomize overlay
kubectl diff -f deployment.yaml # what would change — run this first
kubectl delete -f deployment.yaml
Output formats worth knowing
kubectl get pod web-... -o yaml # the full object
kubectl get pods -o json | jq '.items[].metadata.name'
kubectl get pods -o jsonpath='{.items[*].spec.containers[*].image}'
kubectl get pods -o custom-columns=NAME:.metadata.name,STATUS:.status.phase
-o yaml on a live object is the fastest way to learn the API: create something with kubectl create, then read what the server filled in.
Rollouts
kubectl rollout status deployment/web
kubectl rollout history deployment/web
kubectl rollout undo deployment/web
kubectl rollout undo deployment/web --to-revision=3
kubectl rollout restart deployment/web # recreate every pod, same spec
rollout restart is the polite way to force a restart — useful after changing a ConfigMap, since
pods do not automatically restart when one changes.
Resource usage
kubectl top nodes
kubectl top pods
kubectl top pods --containers
Requires metrics-server. These numbers are what you size requests and limits from.
When raw YAML stops scaling
Three files per service, times three environments, is nine files that are 90% identical. Two tools solve it.
Kustomize — built into kubectl
base/
├── kustomization.yaml
├── deployment.yaml
└── service.yaml
overlays/
├── staging/
│ └── kustomization.yaml
└── prod/
└── kustomization.yaml
base/kustomization.yaml:
resources:
- deployment.yaml
- service.yaml
overlays/prod/kustomization.yaml:
resources:
- ../../base
namespace: prod
replicas:
- name: web
count: 6
images:
- name: myapp
newTag: 1.4.0
kubectl apply -k overlays/prod
kubectl kustomize overlays/prod # render without applying
No templating language — it patches YAML with YAML. Start here.
Helm — packages and templating
helm repo add bitnami https://charts.bitnami.com/bitnami
helm install postgres bitnami/postgresql --set auth.database=app
helm list
helm upgrade postgres bitnami/postgresql --set auth.database=app
helm rollback postgres 1
helm uninstall postgres
Helm’s real strength is installing other people’s software. Postgres, Prometheus, cert-manager, ingress controllers — all one command.
Contexts and namespaces
kubectx # switch cluster
kubens demo # switch default namespace
kubectl config current-context
alias k=kubectl
alias kgp='kubectl get pods'
alias kgs='kubectl get svc'
alias kl='kubectl logs -f'
alias kd='kubectl describe'
k9s
k9s
:pods, :deploy, :svc to navigate. l for logs, d to describe, s for a shell, ctrl-d
to delete. It replaces most of the commands above and makes cluster exploration actually
pleasant.
Next: the mistakes that cause outages.