Meet kubectl
The remote control for your cluster.
A television remote lets you change the channel from the couch, without walking over and poking the TV. kubectl (most people say "kube-control," a few say "kube-cuttle") is that remote for a Kubernetes cluster. A cluster is just a group of computers, called nodes, that run your apps together. You never log into those nodes and poke at them by hand. You sit at your own laptop, type one command, and kubectl carries your request over to the cluster and shows you what came back. Nearly everything in this course happens through kubectl, so getting comfortable with a small handful of commands is the foundation for all of it.
Where your commands actually go
This is the part that trips people up early on. kubectl doesn't run anything on those computers itself. Every command is a request for something. Think of the cluster as a busy restaurant. You don't march into the kitchen and start cooking. You tell the person at the front counter what you want, and they pass it back to the cooks. In a cluster, that front counter is the API server. (API stands for application programming interface, which is a fancy name for a doorway one program uses to talk to another.) The API server is the single entrance to the control plane, the group of programs that make the cluster's decisions. kubectl only ever talks to that one doorway. You ask a question, and the answer comes back to your screen. That one rule explains a lot of how kubectl behaves.
The five commands you'll use every day
You can get surprisingly far with five verbs. get lists things ("show me the pods"). describe prints the full details of one thing, including a running list of recent events. logs shows what a container printed out while it ran. apply creates or updates things from a file. delete removes them. After the verb you name a resource type, like pods or nodes or deployments, and often a specific name after that. Learn those five and you can handle most of a normal day.
Start simple. Ask the cluster which machines it's built from:
kubectl get nodes
NAME STATUS ROLES AGE VERSIONkind-control-plane Ready control-plane 9d v1.31.0kind-worker Ready <none> 9d v1.31.0kind-worker2 Ready <none> 9d v1.31.0
Now list what's actually running. A Pod is the smallest thing Kubernetes runs. It's usually a single container wrapped up so the cluster can schedule it and keep an eye on it. By default kubectl shows you only one slice of the cluster, called a namespace. (Think of namespaces as separate apartments inside one building, each with its own stuff, all under one roof.) Add -o wide for extra columns, like which node a Pod landed on and its IP address. Add -A when you want to see across every namespace at once:
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODEweb-7c9fd8b6f5-2xk9q 1/1 Running 0 12m 10.244.1.7 kind-workerweb-7c9fd8b6f5-lp8vt 1/1 Running 0 12m 10.244.2.3 kind-worker2
You'll mistype one of these before long, and it helps to have already seen what that looks like so it doesn't throw you. Ask for a resource type that doesn't exist, and kubectl stops you with this:
kubectl get pdos
error: the server doesn't have a resource type "pdos"
Ask for a Pod that simply isn't there, and the message reads differently:
kubectl get pod web-old
Error from server (NotFound): pods "web-old" not found
Read the two apart. The first says the kind of thing you asked for, pdos, isn't a word Kubernetes knows, so it's nearly always a spelling slip (pods, not pdos). The second is the opposite: pods is a real kind, the cluster understood you and went looking, and there just isn't a Pod named web-old. One error means "I don't know that word"; the other means "I know the word, but that thing isn't here." That second line, Error from server, is the API server answering you back through the same front door from earlier. Telling those two apart is half of learning to read Kubernetes errors, and you'll meet both in your first hour.
When a Pod is genuinely stuck rather than just misspelled, describe is the command that tells you why. It prints a lot of detail. Scroll down to the Events section at the bottom, which reads in plain sentences:
kubectl describe pod web-7c9fd8b6f5-2xk9q
Name: web-7c9fd8b6f5-2xk9qNamespace: defaultNode: kind-worker/172.18.0.3Status: RunningContainers:web:Image: nginx:1.27State: RunningEvents:Type Reason Age From Message---- ------ ---- ---- -------Normal Scheduled 12m default-scheduler Successfully assigned default/web-7c9fd8b6f5-2xk9q to kind-workerNormal Pulled 12m kubelet Successfully pulled image "nginx:1.27"Normal Started 12m kubelet Started container web
Those Events are gold. Each line names who did what. The scheduler (the part of the control plane that picks which node each Pod should run on) placed the Pod, and then the kubelet on that node pulled the image and started the container. (The kubelet is the small agent Kubernetes runs on every node to start containers and watch over them.) When a Pod is stuck, this is where the reason turns up, in words you can actually read, long before you need to open the logs.
Two ways to tell kubectl what you want
There are two styles here, and knowing the difference saves a lot of confusion later. The imperative style gives a direct order for right now: kubectl run, kubectl create, kubectl scale. It's like getting in a taxi and giving the driver turn-by-turn directions. Quick, and great for learning or for throwaway experiments. The declarative style works the other way around. You write down what you want in a file and hand it over with kubectl apply -f, and the cluster figures out how to make reality match your file. That's like giving the driver an address and letting them find the route. Real projects run this way, because a file can be saved, shared with teammates, and kept in version control (a system like Git that records every change you make to your files), so there's one agreed record of what the cluster should look like.
That file is written in YAML, a plain-text format for settings that's meant to be easy for people to read. A complete Kubernetes file always has four parts: apiVersion (which version of the Kubernetes API to speak), kind (what type of object this is), metadata (its name and any labels, which are simple tags you attach so you can find things later), and spec (what you actually want). Here's a whole, applyable file that describes one Pod:
apiVersion: v1kind: Podmetadata:name: weblabels:app: webspec:containers:- name: webimage: nginx:1.27ports:- containerPort: 80
Apply it, and kubectl tells you plainly what changed:
kubectl apply -f web-pod.yaml
pod/web created
From here you'd run kubectl get pods again to watch it come up, and if it misbehaves, kubectl describe pod web to see why. Same five verbs, over and over. That loop, apply then check then fix, is most of what working with Kubernetes feels like day to day.
kubectl is a remote control aimed at the API server using a kubeconfig. Contexts pick cluster + user + namespace defaults. Most "wrong cluster" outages are a context mistake, not a mysterious bug. Make a habit of printing the current context before destructive commands.
Imperative commands (kubectl run, kubectl create) are fine for learning and break-glass. Declarative apply of YAML is what you want for anything that should survive the next engineer. Prefer apply for shared environments rather than a pile of one-off imperative edits nobody can replay.
On-call, the trio get / describe / logs covers most first-pass triage. Events on describe often explain a failure faster than staring at STATUS alone.
Try this
Confirm who you are talking to (context), list namespaces, and practice get + describe on a short-lived pod.
$ kubectl config current-contextkind-kind$ kubectl get nsNAME STATUS AGEdefault Active 12dkube-system Active 12dkube-public Active 12d$ kubectl run tip --image=busybox:1.36 --restart=Never --command -- sleep 120pod/tip created$ kubectl get pod tipNAME READY STATUS RESTARTS AGEtip 1/1 Running 0 5s$ kubectl describe pod tip | Select-String -Pattern 'Status:|Node:|Events:' -Context 0,8Status: RunningNode: kind-worker/172.18.0.3Events:Normal Scheduled ... Successfully assigned default/tip ...$ kubectl delete pod tippod "tip" deleted
Takeaway
Always know your context, prefer declarative apply for lasting objects, and triage with get → describe → logs. kubectl is how you read the API the controllers already trust.