kubectl is the command-line client for the Kubernetes API. Almost everything you do on a cluster, from deploying an application to reading its logs, goes through it. This guide collects the commands you will use every day, grouped by task, with what each one is for and what to look at in the output.
Prerequisites
To use the commands in this guide you need:
- Access to a Kubernetes cluster, for example one you built on a CubePath VPS with kubeadm.
kubectlinstalled on your workstation or on the control plane node, within one minor version of the cluster.- A kubeconfig file in
~/.kube/config, or referenced by theKUBECONFIGenvironment variable.
Check that the client can reach the cluster:
kubectl version
kubectl cluster-info
Kubernetes control plane is running at https://10.0.0.10:6443
CoreDNS is running at https://10.0.0.10:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
Command structure and built-in help
Every command follows the same pattern:
kubectl <verb> <resource type> [name] [flags]
For example kubectl get pods web-1 -n shop -o yaml. Resource types accept short names (po for pods, svc for services, deploy for deployments, ns for namespaces). List all types with their short names and API groups:
kubectl api-resources
kubectl explain documents every field of a resource straight from the cluster's API schema, which is faster and more accurate than searching the web when writing YAML:
kubectl explain deployment.spec.strategy
kubectl explain pod.spec.containers.readinessProbe --recursive
Contexts and namespaces
A context combines a cluster, a user and a default namespace. If you manage more than one cluster, always check which one you are talking to before changing anything:
kubectl config get-contexts
kubectl config current-context
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* prod-admin prod prod-admin default
staging-admin staging staging-admin default
Switch context:
kubectl config use-context staging-admin
Set the default namespace for the current context, so you do not need -n on every command:
kubectl config set-context --current --namespace=shop
To use several kubeconfig files at once, list them in KUBECONFIG separated by colons. kubectl config view --flatten merges them into a single file:
export KUBECONFIG=~/.kube/config:~/.kube/staging.yaml
kubectl config view --flatten > ~/.kube/merged.yaml
Viewing resources
get lists resources. Add -n <namespace> for a specific namespace or -A for all of them:
kubectl get pods
kubectl get pods -A
kubectl get deploy,svc,pods -n shop
-o wide adds the node and Pod IP; --show-labels shows labels:
kubectl get pods -o wide --show-labels
Filter by label with -l, and by field with --field-selector:
kubectl get pods -l app=web
kubectl get pods -l 'environment in (staging,prod)'
kubectl get pods -A --field-selector status.phase!=Running
The last command is a quick way to find everything that is not healthy in the cluster.
Watch changes live with -w (press Ctrl+C to stop):
kubectl get pods -w
describe shows the full state of an object plus its recent events. It is the first command to run when something does not work:
kubectl describe pod web-5d4f8c7b9d-8xk2m
kubectl describe node worker-1
Extracting fields
Use -o yaml to see an object exactly as stored, and jsonpath or custom-columns to extract specific values in scripts:
kubectl get deploy web -o yaml
kubectl get pods -o jsonpath='{.items[*].metadata.name}'
kubectl get nodes -o custom-columns=NAME:.metadata.name,IP:.status.addresses[0].address
Sort output by a field, for example to see the most recent events last:
kubectl get events --sort-by=.lastTimestamp
Creating and changing resources
The recommended workflow is declarative: keep YAML files in version control and apply them. apply creates the objects if they do not exist and updates them if they do:
kubectl apply -f deployment.yaml
kubectl apply -f manifests/
Before applying, see exactly what would change on the live cluster:
kubectl diff -f deployment.yaml
kubectl diff prints a unified diff and exits with status 1 when there are differences, so it works in CI pipelines too.
Generate a starting manifest instead of writing it from scratch. --dry-run=client -o yaml prints the object without creating it:
kubectl create deployment web --image=nginx:1.28 --replicas=3 --dry-run=client -o yaml > deployment.yaml
kubectl create service clusterip web --tcp=80:80 --dry-run=client -o yaml > service.yaml
For quick one-off changes, edit opens the live object in your editor and patch changes specific fields:
kubectl edit deployment web
kubectl patch deployment web -p '{"spec":{"replicas":4}}'
Note
edit,patch,scaleandsetchange the live object only. The nextkubectl applyof your file overwrites them, so update the file too.
Labels and annotations:
kubectl label pod web-5d4f8c7b9d-8xk2m tier=frontend
kubectl label pod web-5d4f8c7b9d-8xk2m tier-
kubectl annotate deployment web owner=platform-team
The trailing - in the second command removes the label.
Deleting resources
Delete by file, by name or by label:
kubectl delete -f deployment.yaml
kubectl delete pod web-5d4f8c7b9d-8xk2m
kubectl delete pods -l app=web
Warning
kubectl delete namespace <name>deletes everything inside that namespace, including PersistentVolumeClaims and, depending on the reclaim policy, their data. Check the current context first.
Logs, exec and port forwarding
Read container logs. Add -f to follow, --since to limit the time range and -c to choose a container in multi-container Pods:
kubectl logs web-5d4f8c7b9d-8xk2m
kubectl logs -f web-5d4f8c7b9d-8xk2m --since=10m
kubectl logs web-5d4f8c7b9d-8xk2m -c sidecar
If a container crashed and restarted, the current log is often empty. Read the previous instance's log instead:
kubectl logs web-5d4f8c7b9d-8xk2m --previous
Read logs from all Pods of a Deployment at once:
kubectl logs deployment/web --all-containers --prefix
kubectl logs -l app=web --tail=50
Open a shell inside a running container. Everything after -- is the command to run:
kubectl exec -it web-5d4f8c7b9d-8xk2m -- sh
kubectl exec web-5d4f8c7b9d-8xk2m -- cat /etc/nginx/nginx.conf
Forward a local port to a Pod or Service. This is the safest way to reach an internal service, like an admin UI or database, without exposing it:
kubectl port-forward service/web 8080:80
While it runs, http://localhost:8080 on your machine reaches the Service.
Copy files to or from a container. The container image must include tar for this to work:
kubectl cp web-5d4f8c7b9d-8xk2m:/etc/nginx/nginx.conf ./nginx.conf
kubectl cp ./index.html web-5d4f8c7b9d-8xk2m:/usr/share/nginx/html/index.html
Debugging
Many production images do not contain a shell. kubectl debug attaches an ephemeral container with the tools you need, sharing the process namespace of the target container:
kubectl debug -it web-5d4f8c7b9d-8xk2m --image=busybox:1.36 --target=nginx
Run a throwaway Pod to test DNS or connectivity from inside the cluster. --rm deletes it when you exit:
kubectl run nettest --rm -it --image=busybox:1.36 --restart=Never -- sh
Inside it, nslookup web.shop.svc.cluster.local or wget -qO- http://web.shop check that a Service resolves and answers.
Show events for a single object, or for the whole namespace in time order:
kubectl events --for pod/web-5d4f8c7b9d-8xk2m
kubectl get events -n shop --sort-by=.lastTimestamp
Check resource usage. kubectl top requires the metrics-server add-on to be installed in the cluster:
kubectl top nodes
kubectl top pods -A --sort-by=memory
Check what your current user is allowed to do. This is useful when a command returns Forbidden:
kubectl auth can-i create deployments -n shop
kubectl auth can-i --list -n shop
Deployments, scaling and rollouts
Scale a Deployment:
kubectl scale deployment/web --replicas=5
Change the image of a container and follow the rollout:
kubectl set image deployment/web nginx=nginx:1.29
kubectl rollout status deployment/web
Inspect the history, and roll back to the previous or to a specific revision:
kubectl rollout history deployment/web
kubectl rollout undo deployment/web
kubectl rollout undo deployment/web --to-revision=2
Restart all Pods of a Deployment, for example to pick up a changed Secret mounted as environment variables. Pods are replaced gradually, following the Deployment's update strategy:
kubectl rollout restart deployment/web
Wait for a condition in scripts or CI pipelines instead of using sleep:
kubectl wait --for=condition=Available deployment/web --timeout=120s
ConfigMaps and Secrets
Create a ConfigMap from literal values or from a file:
kubectl create configmap web-config --from-literal=LOG_LEVEL=info --from-file=nginx.conf
Create a Secret. Replace your_strong_password with a real value, and prefer --from-file so the password does not end up in your shell history:
kubectl create secret generic db-credentials --from-literal=username=app --from-literal=password=your_strong_password
Decode a Secret value to check it:
kubectl get secret db-credentials -o jsonpath='{.data.password}' | base64 -d
ImportantSecrets are only base64 encoded, not encrypted. Anyone who can read Secrets in a namespace can read their values, so restrict that permission with RBAC.
Productivity: completion and aliases
Enable Bash completion for kubectl in your shell. On Ubuntu the bash-completion package must be installed:
echo 'source <(kubectl completion bash)' >> ~/.bashrc
Add a short alias and make completion work for it too:
echo 'alias k=kubectl' >> ~/.bashrc
echo 'complete -o default -F __start_kubectl k' >> ~/.bashrc
source ~/.bashrc
Now k get po -n kube-<Tab> completes namespace names. For Zsh, use kubectl completion zsh instead.
Quick reference
| Task | Command |
|---|---|
| Current context | kubectl config current-context |
| Change default namespace | kubectl config set-context --current --namespace=NAME |
| Everything not Running | kubectl get pods -A --field-selector status.phase!=Running |
| Why a Pod fails | kubectl describe pod NAME |
| Logs of a crashed container | kubectl logs NAME --previous |
| Shell in a container | kubectl exec -it NAME -- sh |
| Preview changes | kubectl diff -f FILE |
| Apply changes | kubectl apply -f FILE |
| Roll back | kubectl rollout undo deployment/NAME |
| Reach an internal service | kubectl port-forward svc/NAME 8080:80 |
Conclusion
With these commands you can switch safely between clusters, inspect and change resources, find out why a Pod is failing and roll back a bad release. The two habits that prevent most accidents are checking the current context before any change and running kubectl diff before kubectl apply.
To practise them on a real workload, follow Kubernetes Pods, Services and Deployments, then publish the application with an Ingress.
