kubectl Basics
kubectl (pronounced “kube-control” or “kube-cuttle”) is the command-line tool you use to talk to a Kubernetes cluster. Kubernetes is a system that runs and manages your containers (packaged-up apps) across many machines. You almost never click around in a web dashboard — instead you type kubectl commands or apply YAML files (text files that describe what you want running). This page teaches you the handful of commands you will use every single day: looking at what is running, reading logs, getting a shell inside a running app, deploying a manifest, and cleaning up.
How kubectl talks to your cluster
kubectl is just a client. It reads a configuration file (called a kubeconfig) that tells it the address of your cluster and how to log in. By default this file lives at ~/.kube/config on your Ubuntu machine.
When you install a local cluster (like Minikube or kind) or connect to a managed cluster (like Amazon EKS or Google GKE), that tool writes the connection details into this file for you.
Install kubectl on Ubuntu 22.04 / 24.04 LTS:
sudo apt-get update
sudo apt-get install -y ca-certificates curl
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
kubectl version --client
Output:
Client Version: v1.33.1
Kustomize Version: v5.6.0
Treat your
~/.kube/configfile like a password. Anyone who can read it can control your entire cluster. Keep it at permission0600(chmod 600 ~/.kube/config) and never commit it to Git.
Contexts — which cluster am I talking to?
A context is a saved bundle of “which cluster + which user + which default namespace”. If you work with more than one cluster (say a local one and a production one), contexts let you switch between them so you do not accidentally run a command on the wrong cluster.
kubectl config get-contexts # list all contexts
kubectl config current-context # show the active one
kubectl config use-context minikube # switch to a context
Output:
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* minikube minikube minikube default
prod-eks prod-eks prod-eks default
The * marks the active context. When to use this: always run current-context before any destructive command (like delete) so you are sure you are not pointed at production.
Namespaces — folders inside a cluster
A namespace is a way to split one cluster into separate areas, a bit like folders. Teams use them to keep dev, staging, and prod apart, or to give each team its own space. Most commands accept -n <namespace> to target a specific one, or -A / --all-namespaces to look across all of them.
kubectl get namespaces
kubectl get pods -n kube-system # the cluster's own system pods
kubectl get pods -A # pods everywhere
To avoid typing -n every time, set a default namespace on your context:
kubectl config set-context --current --namespace=dev
The four commands you will use constantly
| Command | What it does | When to use it |
|---|---|---|
kubectl get | Lists resources (pods, services, etc.) | Quick “what is running?” check |
kubectl describe | Shows full details and recent events for one resource | Figuring out why something is broken |
kubectl logs | Prints the output (stdout/stderr) of a container | Debugging crashes and app errors |
kubectl exec | Runs a command inside a running container | Poke around a live container |
Listing things with get
kubectl get pods
kubectl get pods -o wide # adds node and IP columns
kubectl get deploy,svc # several kinds at once
kubectl get pods -w # "watch" — live updates as things change
Output:
NAME READY STATUS RESTARTS AGE
web-7d9f8c6b4-2xq9z 1/1 Running 0 3m
web-7d9f8c6b4-lk4mn 1/1 Running 0 3m
READY 1/1 means the container is up. A status of CrashLoopBackOff or ImagePullBackOff means something is wrong — that is your cue to reach for describe and logs.
Investigating with describe and logs
kubectl describe pod web-7d9f8c6b4-2xq9z
kubectl logs web-7d9f8c6b4-2xq9z
kubectl logs -f web-7d9f8c6b4-2xq9z # -f follows live, like tail -f
kubectl logs --previous web-7d9f8c6b4-2xq9z # logs from the last crashed run
The Events section at the bottom of describe output is gold — it tells you things like “failed to pull image” or “out of memory”.
Getting a shell inside a pod with exec
kubectl exec -it web-7d9f8c6b4-2xq9z -- /bin/sh
The -it means interactive terminal, and everything after -- is the command to run inside the container. This drops you into a shell inside the live container so you can check files or test network connectivity.
Deploying a manifest with apply -f
A manifest is a YAML file describing what you want. kubectl apply -f reads that file and makes the cluster match it. The magic of apply is that it is declarative: you describe the desired end state, and you can run the same command again after editing the file — Kubernetes works out the difference and only changes what is needed.
Create a file called web.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 2
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: nginx:1.27
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: web
spec:
selector:
app: web
ports:
- port: 80
targetPort: 80
Apply it and watch the pods come up:
kubectl apply -f web.yaml
kubectl get pods -w
Output:
deployment.apps/web created
service/web created
You can also point apply -f at a whole directory (kubectl apply -f ./manifests/) or even a URL. Use kubectl diff -f web.yaml to preview changes before applying them.
Cleaning up with delete
kubectl delete -f web.yaml # removes exactly what the file created
kubectl delete pod web-7d9f8c6b4-2xq9z # delete one pod (it gets recreated by the Deployment)
When NOT to use delete: do not delete individual pods to “fix” things in production. A Deployment immediately recreates them. Instead, fix the manifest and re-apply, or use kubectl rollout restart deployment/web to cycle pods cleanly.
Best practices
- Always check
kubectl config current-contextbefore runningdelete,apply, orrolloutso you never hit the wrong cluster. - Keep your manifests in Git and deploy with
apply -f, not by typing imperativekubectl createcommands — your repo becomes the source of truth. - Use
kubectl diff -fbeforeapplyto preview exactly what will change. - Set a default namespace per context so you stop typing
-nand stop making namespace mistakes. - Reach for
describe(read the Events) andlogs --previousfirst when a pod is crashing — they almost always reveal the cause. - Add
alias k=kubectlto your~/.bashrcto save thousands of keystrokes. - Never store
~/.kube/configin a repo and keep it atchmod 600.