Foundations tooling

kubectl — The Control Plane CLI

● Beginner ⏱ 12 min read tooling

kubectl (pronounced "kube-control" or "kube-cuddle") is the official command-line interface for interacting with a Kubernetes cluster. Every operation you perform — creating workloads, inspecting logs, rolling back deployments — goes through kubectl, which translates your commands into API calls to the Kubernetes API server.

📚
Official Reference

Based on kubernetes.io/docs/reference/kubectl/.

Installation & kubeconfig

Install kubectl with your package manager or download the binary directly:

# macOS (Homebrew)
brew install kubectl

# Linux — latest stable
curl -LO "https://dl.k8s.io/release/$(curl -Ls https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x kubectl
sudo mv kubectl /usr/local/bin/

# Windows (winget)
winget install Kubernetes.kubectl

kubectl reads cluster connection details from a file called kubeconfig, found by default at ~/.kube/config. You can override this with the KUBECONFIG environment variable or the --kubeconfig flag.

The kubeconfig file contains three sections:

Section What it stores
clusters API server URL and TLS certificate authority for each cluster
users Credentials (client cert, token, or exec plugin) per user
contexts Named binding of a cluster + user + default namespace

Contexts & Clusters

A context is a shortcut that binds a cluster, a user, and a default namespace. Switching contexts lets you point kubectl at a different cluster without retyping credentials.

# list all contexts
kubectl config get-contexts

# show current context
kubectl config current-context

# switch to a different context
kubectl config use-context my-prod-cluster

# set a default namespace for the current context
kubectl config set-context --current --namespace=payments

# merge two kubeconfig files into one
KUBECONFIG=~/.kube/config:~/Downloads/new-cluster.yaml \
  kubectl config view --flatten > ~/.kube/merged-config
💡
Use kubectx + kubens

kubectx and kubens are small tools that make switching contexts and namespaces much faster than the full kubectl config commands.

Core Commands

get — list resources

# list all pods in current namespace
kubectl get pods

# list pods in a specific namespace
kubectl get pods -n kube-system

# list pods across all namespaces
kubectl get pods -A

# list multiple resource types at once
kubectl get pods,services,deployments

# include extra columns (node, IP, etc.)
kubectl get pods -o wide

describe — detailed information

kubectl describe shows full details including events, which is the first place to look when something isn't working:

kubectl describe pod payments-api-7d4f8b9-xk2lm
kubectl describe node worker-1
kubectl describe deployment payments-api

apply — declarative updates

# apply a single manifest
kubectl apply -f pod.yaml

# apply all manifests in a directory
kubectl apply -f ./k8s/

# apply recursively
kubectl apply -R -f ./k8s/

# dry-run — preview changes without applying
kubectl apply -f deployment.yaml --dry-run=client

delete — remove resources

# delete by manifest (recommended — mirrors apply)
kubectl delete -f pod.yaml

# delete by name
kubectl delete pod payments-api-7d4f8b9-xk2lm

# delete all pods matching a label selector
kubectl delete pods -l app=payments-api

# delete a namespace (and everything inside it)
kubectl delete namespace staging

create vs apply

Command Behaviour Use when
kubectl create Creates resource; fails if it already exists One-off imperative creation
kubectl apply Creates or updates resource; idempotent GitOps / CI/CD workflows

Logs & Exec

# stream logs from a pod (single container)
kubectl logs -f payments-api-7d4f8b9-xk2lm

# logs from a specific container in a multi-container pod
kubectl logs payments-api-7d4f8b9-xk2lm -c sidecar

# logs from all pods matching a label
kubectl logs -l app=payments-api --all-containers

# previous container logs (after a crash/restart)
kubectl logs payments-api-7d4f8b9-xk2lm --previous

Open an interactive shell inside a running container:

# interactive shell
kubectl exec -it payments-api-7d4f8b9-xk2lm -- /bin/sh

# run a one-off command without TTY
kubectl exec payments-api-7d4f8b9-xk2lm -- env

# specify container in multi-container pod
kubectl exec -it payments-api-7d4f8b9-xk2lm -c api -- /bin/bash

Port-forward & Proxy

kubectl port-forward tunnels traffic from your local machine to a pod or service — without exposing anything publicly. Essential for testing internal services:

# local port 8080 → pod port 8080
kubectl port-forward pod/payments-api-7d4f8b9-xk2lm 8080:8080

# port-forward to a service (picks a random pod)
kubectl port-forward svc/payments-api 8080:80

# background the process; kill with: kill $(lsof -ti:8080)
kubectl port-forward svc/payments-api 8080:80 &

Output Formats

The -o flag controls output format:

Flag Output Use case
-o wide Extra columns (node, IP, nominated node) Inspect scheduling
-o yaml Full YAML of the live resource Inspect or save current state
-o json Full JSON Pipe to jq
-o name Resource name only (e.g. pod/my-pod) Scripts and loops
-o jsonpath='{...}' Extract specific fields via JSONPath Automation
-o custom-columns=... Define your own column headers Custom summaries
# get the image of every container in every pod
kubectl get pods -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[*].image}{"\n"}{end}'

# all node names, one per line
kubectl get nodes -o name

Power-user Patterns

Watch mode

# refresh the pod list every 2 seconds
kubectl get pods -w

Rollout management

# watch a rollout in progress
kubectl rollout status deployment/payments-api

# view rollout history
kubectl rollout history deployment/payments-api

# roll back to the previous version
kubectl rollout undo deployment/payments-api

# roll back to a specific revision
kubectl rollout undo deployment/payments-api --to-revision=3

Editing live resources

# open resource YAML in your $EDITOR
kubectl edit deployment/payments-api

# patch a specific field without opening an editor
kubectl patch deployment/payments-api \
  -p '{"spec":{"replicas":5}}'

Copying files

# copy from pod to local
kubectl cp payments-api-7d4f8b9-xk2lm:/app/logs/error.log ./error.log

# copy from local to pod
kubectl cp ./config.json payments-api-7d4f8b9-xk2lm:/app/config.json

Generate YAML stubs with --dry-run

Instead of writing manifests from scratch, let kubectl generate the boilerplate:

# generate a Deployment manifest without applying it
kubectl create deployment payments-api \
  --image=payments-api:2.4.1 \
  --replicas=3 \
  --dry-run=client -o yaml > deployment.yaml

# generate a Service manifest
kubectl expose deployment payments-api \
  --port=80 --target-port=8080 \
  --dry-run=client -o yaml > service.yaml