The Kubernetes commands and YAML patterns you reach for every day — Pods, Deployments, Services, ConfigMaps, namespaces, scaling, and debugging — all in one place.
Quick reference
The 25 kubectl commands that cover 90% of daily k8s work.
| Command | What it does |
|---|---|
kubectl get pods |
List Pods in current namespace |
kubectl get pods -A |
List Pods in ALL namespaces |
kubectl get pods -o wide |
Show Pod IPs and node names |
kubectl describe pod <name> |
Full Pod details + events |
kubectl logs <pod> |
Print Pod logs |
kubectl logs -f <pod> |
Follow live logs |
kubectl logs <pod> -c <container> |
Logs from specific container |
kubectl exec -it <pod> -- bash |
Open shell inside Pod |
kubectl apply -f manifest.yaml |
Create or update resources |
kubectl delete -f manifest.yaml |
Delete resources from file |
kubectl delete pod <name> |
Delete a Pod |
kubectl get deployments |
List Deployments |
kubectl scale deploy <name> --replicas=3 |
Scale a Deployment |
kubectl rollout status deploy/<name> |
Watch rollout progress |
kubectl rollout undo deploy/<name> |
Roll back to previous version |
kubectl get services |
List Services |
kubectl port-forward pod/<name> 8080:80 |
Forward local port to Pod |
kubectl get configmaps |
List ConfigMaps |
kubectl get secrets |
List Secrets |
kubectl get namespaces |
List all namespaces |
kubectl config get-contexts |
List cluster contexts |
kubectl config use-context <ctx> |
Switch cluster/context |
kubectl top pods |
CPU + memory usage (needs metrics-server) |
kubectl get events --sort-by=.lastTimestamp |
Recent cluster events |
kubectl explain pod.spec |
In-terminal YAML field docs |
Core resource types
| Resource | Short | What it is |
|---|---|---|
Pod |
po |
Smallest deployable unit — one or more containers |
Deployment |
deploy |
Manages ReplicaSets; rolling updates + rollback |
ReplicaSet |
rs |
Keeps N Pod replicas running |
StatefulSet |
sts |
Like Deployment but for stateful apps (ordered, stable names) |
DaemonSet |
ds |
One Pod per node (logging agents, node exporters) |
Job |
— | Runs to completion; restarts on failure |
CronJob |
cj |
Runs Job on a schedule |
Service |
svc |
Stable network endpoint for Pods |
Ingress |
— | HTTP routing rules into the cluster |
ConfigMap |
cm |
Key-value config injected into Pods |
Secret |
— | Like ConfigMap but base64-encoded (use a vault in prod) |
PersistentVolumeClaim |
pvc |
Request for storage |
Namespace |
ns |
Virtual cluster / isolation boundary |
ServiceAccount |
sa |
Pod identity for RBAC |
HorizontalPodAutoscaler |
hpa |
Auto-scale based on CPU/memory |
Pod YAML
Minimal Pod — useful for debugging:
apiVersion: v1
kind: Pod
metadata:
name: debug-pod
namespace: default
labels:
app: debug
spec:
containers:
- name: app
image: busybox:1.36
command: ["sleep", "3600"]
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
restartPolicy: Never
Run a one-off debug pod then delete it:
kubectl run debug --image=busybox:1.36 --rm -it --restart=Never -- sh
Deployment YAML
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: app
image: my-registry/my-app:1.2.3
ports:
- containerPort: 8080
env:
- name: PORT
value: "8080"
- name: DB_HOST
valueFrom:
secretKeyRef:
name: db-secret
key: host
readinessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
Service YAML
# ClusterIP — internal only (default)
apiVersion: v1
kind: Service
metadata:
name: my-app-svc
spec:
selector:
app: my-app
ports:
- protocol: TCP
port: 80 # port on the Service
targetPort: 8080 # port on the Pod
type: ClusterIP
| Service type | When to use |
|---|---|
ClusterIP |
Internal communication only (default) |
NodePort |
Expose on each node's IP:port (dev/testing) |
LoadBalancer |
Cloud load balancer (AWS ELB, GCP LB) |
ExternalName |
DNS alias to an external hostname |
Ingress YAML
Requires an ingress controller (nginx, traefik, etc.):
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app-svc
port:
number: 80
tls:
- hosts:
- myapp.example.com
secretName: myapp-tls
ConfigMap and Secret
# ConfigMap — non-sensitive config
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
LOG_LEVEL: "info"
MAX_CONNECTIONS: "100"
config.json: |
{ "debug": false, "timeout": 30 }
# Secret — base64-encoded values
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
data:
# echo -n 'mypassword' | base64
password: bXlwYXNzd29yZA==
host: ZGIuZXhhbXBsZS5jb20=
Inject into a Pod as env vars:
envFrom:
- configMapRef:
name: app-config
- secretRef:
name: db-secret
Mount as files:
volumes:
- name: config-vol
configMap:
name: app-config
volumeMounts:
- name: config-vol
mountPath: /etc/config
readOnly: true
Namespaces
# Create namespace
kubectl create namespace staging
# Run commands in a namespace
kubectl get pods -n staging
kubectl apply -f deploy.yaml -n staging
# Set default namespace for current context
kubectl config set-context --current --namespace=staging
# Delete everything in a namespace (careful!)
kubectl delete all --all -n staging
Scaling and rollouts
# Scale manually
kubectl scale deployment my-app --replicas=5
# Auto-scale on CPU (HPA)
kubectl autoscale deployment my-app --cpu-percent=70 --min=2 --max=10
# Check HPA status
kubectl get hpa
# Update image (triggers rolling update)
kubectl set image deployment/my-app app=my-registry/my-app:1.3.0
# Watch rollout
kubectl rollout status deployment/my-app
# Pause and resume rollout
kubectl rollout pause deployment/my-app
kubectl rollout resume deployment/my-app
# Roll back
kubectl rollout undo deployment/my-app
# Roll back to specific revision
kubectl rollout history deployment/my-app
kubectl rollout undo deployment/my-app --to-revision=2
Debugging
# Describe shows events — check here first
kubectl describe pod my-pod
# Logs (last 100 lines)
kubectl logs my-pod --tail=100
# Previous container logs (after crash)
kubectl logs my-pod --previous
# All containers in pod
kubectl logs my-pod --all-containers
# Shell into running pod
kubectl exec -it my-pod -- bash
kubectl exec -it my-pod -- sh # if no bash
# Specific container in multi-container pod
kubectl exec -it my-pod -c sidecar -- bash
# Copy files to/from pod
kubectl cp my-pod:/etc/config/file.txt ./file.txt
kubectl cp ./local-file.txt my-pod:/tmp/
# Port forward to test locally
kubectl port-forward pod/my-pod 8080:80
kubectl port-forward service/my-app-svc 8080:80
# Get raw YAML of any resource
kubectl get pod my-pod -o yaml
# Watch pods update in real time
kubectl get pods -w
# Check resource usage
kubectl top pods
kubectl top nodes
# Cluster info
kubectl cluster-info
kubectl get nodes -o wide
Common Pod status meanings:
| Status | Meaning |
|---|---|
Pending |
Waiting for node scheduling or image pull |
ContainerCreating |
Pulling image or mounting volumes |
Running |
At least one container is running |
CrashLoopBackOff |
Container crashing repeatedly — check logs |
OOMKilled |
Container exceeded memory limit |
ImagePullBackOff |
Can't pull image (wrong tag, no auth) |
Terminating |
Being deleted — stuck? check finalizers |
Evicted |
Node ran out of resources |
PersistentVolumeClaim
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: standard # cloud-specific: gp2, premium-rwo, etc.
Mount in Pod:
volumes:
- name: data-vol
persistentVolumeClaim:
claimName: data-pvc
volumeMounts:
- name: data-vol
mountPath: /data
RBAC
# ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-app-sa
namespace: default
---
# Role (namespace-scoped)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
namespace: default
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
---
# Bind role to service account
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pod-reader-binding
namespace: default
subjects:
- kind: ServiceAccount
name: my-app-sa
namespace: default
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
Use ClusterRole + ClusterRoleBinding for cluster-wide permissions.
Helm basics
# Add a chart repo
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
# Search for charts
helm search repo nginx
# Install a chart
helm install my-nginx bitnami/nginx
# Install with custom values
helm install my-app ./my-chart -f values.yaml
# Override values inline
helm install my-app ./my-chart --set image.tag=1.3.0,replicas=3
# List releases
helm list
# Upgrade a release
helm upgrade my-app ./my-chart -f values.yaml
# Roll back Helm release
helm rollback my-app 1
# Uninstall
helm uninstall my-app
# Render YAML without installing (dry run)
helm template my-app ./my-chart -f values.yaml
Common mistakes
| Mistake | Fix |
|---|---|
Pod stuck in Pending |
Check kubectl describe pod — usually resource limits or no node with space |
ImagePullBackOff |
Wrong image name/tag or missing imagePullSecret |
| Service not reaching Pods | Check selector labels match Pod labels exactly |
CrashLoopBackOff |
kubectl logs --previous to see crash reason |
| Deployment not updating | Check rollout status; verify image tag actually changed |
| Env var not appearing | envFrom vs env, check secret/configmap name and key spelling |
| HPA stuck at 0/0 | metrics-server not installed or no resources.requests on container |
Evicted pods |
Pods evicted under memory/disk pressure — add resource requests |
Useful one-liners
# Get all resources in a namespace
kubectl get all -n my-namespace
# Delete all completed/failed pods
kubectl delete pods --field-selector=status.phase=Succeeded
kubectl delete pods --field-selector=status.phase=Failed
# Force delete stuck pod
kubectl delete pod my-pod --grace-period=0 --force
# Watch events in real time
kubectl get events -w --sort-by=.lastTimestamp
# Get all pod IPs
kubectl get pods -o custom-columns="NAME:.metadata.name,IP:.status.podIP"
# Find which pods are consuming most CPU
kubectl top pods --sort-by=cpu -A
# Get all images running in the cluster
kubectl get pods -A -o jsonpath='{range .items[*]}{.spec.containers[*].image}{"\n"}{end}' | sort | uniq
# Check which nodes are under pressure
kubectl describe nodes | grep -A5 "Conditions:"
# Dry run apply (validate without applying)
kubectl apply -f manifest.yaml --dry-run=client
# Generate YAML without applying
kubectl create deployment test --image=nginx --dry-run=client -o yaml
6 FAQ
Q: What is the difference between a Deployment and a StatefulSet?
Deployments treat Pods as interchangeable — they get random names and no stable storage. StatefulSets give each Pod a stable hostname (app-0, app-1) and a dedicated PVC that survives restarts. Use StatefulSets for databases, message queues, and anything that needs stable identity.
Q: When should I use a Job instead of a Deployment?
Use a Job for one-off or batch tasks that need to run to completion — database migrations, data import scripts, report generation. Deployments are for long-running services. For recurring batch tasks, use a CronJob.
Q: How do I pass secrets safely into Pods?
Kubernetes Secrets are only base64-encoded (not encrypted at rest by default). For production, enable etcd encryption at rest, or better: use an external secret manager (HashiCorp Vault, AWS Secrets Manager, GCP Secret Manager) via an operator like External Secrets Operator.
Q: What's the difference between requests and limits in resources?requests is the minimum reserved — the scheduler uses this to decide which node to place the Pod on. limits is the hard cap — exceed it and CPU is throttled (not killed), but exceed memory limits and the container is OOMKilled. Always set both; omitting requests leads to poor scheduling decisions.
Q: How do I update a Deployment without downtime?
Use RollingUpdate strategy (the default). Set maxUnavailable: 0 and maxSurge: 1 so a new Pod starts before an old one stops. Add a readinessProbe so traffic only routes to a Pod after it's actually ready — this is the key to zero-downtime deploys.
Q: What is a namespace and when should I use one?
A namespace is a virtual cluster inside a Kubernetes cluster. Use namespaces to isolate environments (dev, staging, production), separate teams, or apply different resource quotas and RBAC policies. The default namespace is fine for small projects; anything larger benefits from explicit namespaces.