Kubernetes Fundamentals

kubectl & the API

18 min Lesson 4 of 32

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 to API Server flow kubectl HTTP client HTTPS / REST API Server Authn / Authz Admission Webhooks Validation persist etcd cluster state Controllers / Scheduler Watch & Reconcile watch events
Every cluster action is an API call. kubectl, controllers, and the scheduler all talk exclusively through the API Server — etcd is never accessed directly.

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 yaml or -o json for 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).
Idempotency matters at scale. In GitOps pipelines (Argo CD, Flux), 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:

# minimal-pod.yaml apiVersion: v1 # API group + version. v1 = core group. apps/v1 for Deployments. kind: Pod # Resource type (case-sensitive) metadata: name: api-server-pod # Unique name within the namespace namespace: production # Defaults to "default" if omitted labels: app: api-server # Arbitrary key/value — Selectors and Services use these version: "2.1.3" spec: # Desired state — the "what you want" containers: - name: api image: myorg/api-server:2.1.3 ports: - containerPort: 8080 resources: requests: cpu: "250m" memory: "256Mi" limits: cpu: "500m" memory: "512Mi"

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 with AlreadyExists if 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.
Do not mix apply and manual edits. If someone runs 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.

# View all contexts kubectl config get-contexts # Switch to the production context kubectl config use-context gke_myproject_us-central1_prod # Run a single command against a different context without switching kubectl --context=staging get pods -n payments # View and change the default namespace for the current context kubectl config set-context --current --namespace=payments # Merge a new cluster kubeconfig (e.g. after eksctl creates a cluster) KUBECONFIG=~/.kube/config:~/Downloads/new-cluster.yaml \ kubectl config view --flatten > ~/.kube/config
kubectx + kubens. These two tiny open-source tools (from Ahmet Alp Balkan at Google) replace 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.

# List all pods in all namespaces (essential for cluster-wide debugging) kubectl get pods --all-namespaces kubectl get pods -A # shorthand # Resources that span namespaces (cluster-scoped) kubectl get nodes kubectl get persistentvolumes kubectl get clusterroles # Quickly see which namespace objects are cluster-scoped vs namespaced kubectl api-resources --namespaced=true kubectl api-resources --namespaced=false

Essential Everyday Workflow

A realistic sequence for deploying and inspecting a workload looks like this:

# 1. Write your manifest, then dry-run it against the server (validates admission webhooks too) kubectl apply -f deployment.yaml --dry-run=server # 2. Apply it kubectl apply -f deployment.yaml # 3. Watch the rollout converge kubectl rollout status deployment/api-server -n production # 4. Inspect a misbehaving pod kubectl describe pod api-server-7d9f8b6c5-xk2pq -n production # 5. Check its logs (last 100 lines, follow new output) kubectl logs api-server-7d9f8b6c5-xk2pq -n production --tail=100 -f # 6. If needed, open a shell inside the container kubectl exec -it api-server-7d9f8b6c5-xk2pq -n production -- /bin/sh # 7. Roll back a broken deployment kubectl rollout undo deployment/api-server -n production

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.