Meet kubectl
The remote control for your cluster.
kubectl (most people say "kube-control," a few say "kube-cuttle") is the CLI for a Kubernetes cluster. A cluster is a group of nodes that run your apps. You do not SSH to those nodes to start workloads. You run kubectl on your laptop; it sends a request to the cluster and prints the reply. Nearly everything in this course goes through kubectl, so a small set of verbs is the foundation.
Where your commands actually go
kubectl does not start processes on worker nodes itself. Every command is an API request. The API server is the only entrance to the control plane. (API means application programming interface: the doorway one program uses to talk to another.) kubectl talks only to that server. You ask, 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 is running. A Pod is the smallest thing Kubernetes runs, usually one container wrapped so the cluster can schedule and watch it. By default kubectl shows one namespace, a named slice of the cluster. Add -o wide for extra columns, such as which node a Pod landed on and its IP. Add -A to list 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 of kubectl command, and the difference matters later. Imperative gives an order for right now: kubectl run, kubectl create, kubectl scale. That is fine for learning and throwaway experiments. Declarative writes the desired state in a file and uses kubectl apply -f; the cluster makes reality match the file. Real projects run that way because a file can be saved, reviewed, and kept in version control (Git records every change), so there is 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.