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.
  • kubectl installed 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 the KUBECONFIG environment 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}}'

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

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

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

TaskCommand
Current contextkubectl config current-context
Change default namespacekubectl config set-context --current --namespace=NAME
Everything not Runningkubectl get pods -A --field-selector status.phase!=Running
Why a Pod failskubectl describe pod NAME
Logs of a crashed containerkubectl logs NAME --previous
Shell in a containerkubectl exec -it NAME -- sh
Preview changeskubectl diff -f FILE
Apply changeskubectl apply -f FILE
Roll backkubectl rollout undo deployment/NAME
Reach an internal servicekubectl 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.