kubectl & the API
kubectl & the API
Every action you take in Kubernetes — scheduling a Pod, scaling a Deployment, reading logs — is an HTTP call to the Kubernetes API Server. kubectl is nothing more than a sophisticated HTTP client that speaks the Kubernetes API protocol, formats the JSON responses, and gives you tab completion. Once you understand that model, everything else about the CLI clicks into place.
The API Server as the Source of Truth
The control plane components you met in Lesson 2 — the scheduler, controller manager, etcd — none of them talk directly to each other. They all go through the API server. This means every state change in the cluster is an API call, and every reconciliation loop watches the API for changes. kubectl is just your window into that same API.
When you run kubectl get pods, kubectl issues a GET to /api/v1/namespaces/default/pods. When you run kubectl apply -f deployment.yaml, it issues a server-side apply PATCH to the appropriate endpoint. You can watch this in real time with kubectl --v=8 get pods, which logs every HTTP request and response body.
kubectl Verbs and the Resource Model
Kubernetes exposes resources (Pods, Deployments, Services, ConfigMaps…) and kubectl exposes verbs that map to HTTP methods. Knowing the canonical verb set removes the need to memorize dozens of subcommands:
get— retrieve one or many resources (HTTP GET). Add-o yamlor-o jsonfor the full object.describe— human-readable object detail plus recent events (indispensable for debugging).create— POST a new resource. Errors if the resource already exists.apply— server-side merge/create using a declarative manifest. Idempotent — safe to run repeatedly.delete— DELETE a resource. Kubernetes immediately begins the termination lifecycle.edit— opens the live object in$EDITOR(the API, not a local file).patch— surgically update a field:kubectl patch deployment api --type=json -p '[{"op":"replace","path":"/spec/replicas","value":5}]'rollout— manage Deployment rollouts:status,history,undo.exec— run a command inside a running container (WebSocket upgrade, like SSH but ephemeral).logs— stream stdout/stderr from a container.port-forward— tunnel a local TCP port to a pod port (not for production traffic).top— live CPU/memory usage (requires metrics-server installed).
kubectl apply runs on every git push. Because apply is idempotent it never fails on resources that already exist — it simply diffs and patches. Always prefer apply over create in automation.
YAML Manifests and the Four Required Fields
Every Kubernetes manifest needs exactly four top-level fields. Every object in the cluster — no matter how complex — follows this contract:
Notice status is absent — that field is owned by Kubernetes and populated after creation. You declare the spec (desired state); the cluster fills in status (observed state). This is the reconciliation contract that runs everything.
apply vs create — and When Each Breaks
Both commands can create resources, but their semantics diverge sharply in production:
kubectl create -f manifest.yaml— imperative, one-shot. The API rejects it withAlreadyExistsif the resource is already there. Useful for bootstrapping (Namespaces, Secrets in a setup script), bad for pipelines.kubectl apply -f manifest.yaml— declarative, idempotent. Kubernetes tracks the last-applied-configuration annotation to compute a three-way merge: last applied + current live object + new manifest. Fields you remove from your manifest get pruned. This is the right default for everything CI/CD touches.
kubectl edit deployment/api in production to bump replicas in an emergency, then a CI pipeline runs kubectl apply with the old manifest, the manual change gets reverted silently. The fix: treat your git manifests as the single source of truth and protect live objects with admission webhooks or GitOps pull-request gates.
Contexts and the kubeconfig File
A real engineer manages multiple clusters: dev, staging, production, maybe a DR region. kubectl reads ~/.kube/config (or $KUBECONFIG) to know which cluster to talk to, which credentials to use, and which namespace to default to. The file groups these into contexts.
kubectl config use-context and kubectl config set-context --current --namespace with single short commands: kubectx prod, kubens payments. Every SRE uses them. Install with brew install kubectx or from the GitHub release. They also show the active context and namespace in your shell prompt via the companion kube-ps1 plugin — eliminating the class of production accidents where you run a command in the wrong cluster.
Namespaces as a Scope Boundary
When you pass --namespace (or -n), you are telling kubectl which namespace to scope the API call to. The API path changes from /api/v1/namespaces/default/pods to /api/v1/namespaces/payments/pods. Some resources are cluster-scoped (Nodes, PersistentVolumes, ClusterRoles) and do not accept a namespace flag — querying them at the namespace level returns an error.
Essential Everyday Workflow
A realistic sequence for deploying and inspecting a workload looks like this:
This workflow — apply, status, describe, logs, exec, rollout undo — covers the vast majority of day-to-day operations. Master it before reaching for more specialized tooling. The next lesson covers ReplicaSets and Deployments in depth, where the rollout verb becomes central.