Essential kubectl Commands
Quick reference for the most common kubectl operations
These commands cover 90% of daily Kubernetes work. Bookmark this page for fast access.
Cluster Management
# Cluster info
kubectl cluster-info
kubectl get nodes
kubectl describe node NODE_NAME
kubectl top nodes
# Context & config
kubectl config view
kubectl config current-context
kubectl config use-context CONTEXT_NAME
kubectl config set-context --current --namespace=NAMESPACE
Resource Management
# Create resources
kubectl create -f FILE.yaml
kubectl apply -f FILE.yaml
kubectl apply -f DIR/
kubectl create deployment NAME --image=IMAGE
# Get resources
kubectl get all
kubectl get pods -o wide
kubectl get svc --all-namespaces
kubectl get pods -l app=nginx
# Update resources
kubectl edit TYPE/NAME
kubectl patch TYPE NAME -p '{"spec":{"replicas":3}}'
kubectl set image deployment/NAME CONTAINER=IMAGE:TAG
kubectl scale deployment NAME --replicas=5
# Delete resources
kubectl delete -f FILE.yaml
kubectl delete TYPE NAME
kubectl delete pods --all
kubectl delete ns NAMESPACE
Pod Operations
# Pod interaction
kubectl exec -it POD_NAME -- /bin/bash
kubectl exec POD_NAME -- COMMAND
kubectl attach POD_NAME -c CONTAINER
kubectl cp POD_NAME:/path/file ./local/path
# Pod logs
kubectl logs POD_NAME
kubectl logs -f POD_NAME
kubectl logs POD_NAME -c CONTAINER
kubectl logs --previous POD_NAME
# Port forwarding
kubectl port-forward POD_NAME 8080:80
kubectl port-forward svc/SERVICE 8080:80
kubectl port-forward deployment/NAME 8080:80
kubectl proxy
# Debug & describe
kubectl describe pod POD_NAME
kubectl get events --sort-by='.lastTimestamp'
kubectl debug POD_NAME -it --image=busybox
kubectl top pod POD_NAME
Deployments and Rollouts
# Deployment management
kubectl create deployment NAME --image=IMAGE
kubectl expose deployment NAME --port=80 --type=LoadBalancer
kubectl autoscale deployment NAME --min=2 --max=10
kubectl rollout status deployment/NAME
# Rollout operations
kubectl rollout history deployment/NAME
kubectl rollout undo deployment/NAME
kubectl rollout undo deployment/NAME --to-revision=2
kubectl rollout pause/resume deployment/NAME
Pro Tips
- Use
-o yamlto get YAML output of any resource - Use
--dry-run=client -o yamlto generate YAML templates - Use
-wto watch resources for changes - Use
--all-namespacesor-Afor cluster-wide operations - Set default namespace:
kubectl config set-context --current --namespace=NAMESPACE
$ kubectl get pods -n production -o wide NAME READY STATUS RESTARTS AGE IP NODE api-7d4f8b-x2k9j 1/1 Running 0 2d 10.0.1.45 node-1 api-7d4f8b-p8m3n 1/1 Running 0 2d 10.0.2.67 node-2 worker-5c6d7e-q4r5t 1/1 Running 0 1d 10.0.1.89 node-1 $ kubectl logs api-7d4f8b-x2k9j --tail=5 2024-03-15T10:23:45Z INFO Server started on :8080 2024-03-15T10:23:46Z INFO Connected to database 2024-03-15T10:23:47Z INFO Health check endpoint ready
kubectl get (list resources), kubectl describe (details + events), kubectl logs (container output), kubectl exec (shell into pod), kubectl apply -f (create/update).
Kubernetes Resources Reference
Workload Resources
| Resource | Short Name | API Group | Namespaced | Kind |
|---|---|---|---|---|
| pods | po |
core/v1 | Yes | Pod |
| deployments | deploy |
apps/v1 | Yes | Deployment |
| replicasets | rs |
apps/v1 | Yes | ReplicaSet |
| statefulsets | sts |
apps/v1 | Yes | StatefulSet |
| daemonsets | ds |
apps/v1 | Yes | DaemonSet |
| jobs | job |
batch/v1 | Yes | Job |
| cronjobs | cj |
batch/v1 | Yes | CronJob |
Service and Networking
| Resource | Short Name | API Group | Namespaced | Kind |
|---|---|---|---|---|
| services | svc |
core/v1 | Yes | Service |
| ingresses | ing |
networking.k8s.io/v1 | Yes | Ingress |
| networkpolicies | netpol |
networking.k8s.io/v1 | Yes | NetworkPolicy |
| endpoints | ep |
core/v1 | Yes | Endpoints |
| ingressclasses | - |
networking.k8s.io/v1 | No | IngressClass |
Config and Storage
| Resource | Short Name | API Group | Namespaced | Kind |
|---|---|---|---|---|
| configmaps | cm |
core/v1 | Yes | ConfigMap |
| secrets | - |
core/v1 | Yes | Secret |
| persistentvolumes | pv |
core/v1 | No | PersistentVolume |
| persistentvolumeclaims | pvc |
core/v1 | Yes | PersistentVolumeClaim |
| storageclasses | sc |
storage.k8s.io/v1 | No | StorageClass |
Cluster Resources
| Resource | Short Name | API Group | Namespaced | Kind |
|---|---|---|---|---|
| nodes | no |
core/v1 | No | Node |
| namespaces | ns |
core/v1 | No | Namespace |
| serviceaccounts | sa |
core/v1 | Yes | ServiceAccount |
| roles | - |
rbac.authorization.k8s.io/v1 | Yes | Role |
| clusterroles | - |
rbac.authorization.k8s.io/v1 | No | ClusterRole |
| rolebindings | - |
rbac.authorization.k8s.io/v1 | Yes | RoleBinding |
| clusterrolebindings | - |
rbac.authorization.k8s.io/v1 | No | ClusterRoleBinding |
Resource Quotas and Limits
| Resource | Short Name | API Group | Namespaced | Kind |
|---|---|---|---|---|
| resourcequotas | quota |
core/v1 | Yes | ResourceQuota |
| limitranges | limits |
core/v1 | Yes | LimitRange |
| horizontalpodautoscalers | hpa |
autoscaling/v2 | Yes | HorizontalPodAutoscaler |
| verticalpodautoscalers | vpa |
autoscaling.k8s.io/v1 | Yes | VerticalPodAutoscaler |
| poddisruptionbudgets | pdb |
policy/v1 | Yes | PodDisruptionBudget |
Common Mistake
Wrong: kubectl delete pod my-pod to restart a pod managed by a Deployment
Why it fails: It works, but the correct approach is kubectl rollout restart deployment/my-app which gracefully rolls out new pods and maintains availability.
Instead: kubectl rollout restart deployment/my-app -n production
YAML Templates
Pod Template
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
labels:
app: nginx
tier: frontend
spec:
containers:
- name: nginx
image: nginx:1.21
ports:
- containerPort: 80
name: http
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
Deployment Template
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-deployment
labels:
app: myapp
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: app
image: myapp:1.0.0
ports:
- containerPort: 8080
env:
- name: ENV_VAR
value: "production"
- name: SECRET_KEY
valueFrom:
secretKeyRef:
name: app-secret
key: api-key
volumeMounts:
- name: config
mountPath: /etc/config
volumes:
- name: config
configMap:
name: app-config
---
apiVersion: v1
kind: Service
metadata:
name: app-service
spec:
selector:
app: myapp
type: ClusterIP
ports:
- port: 80
targetPort: 8080
protocol: TCP
StatefulSet Template
apiVersion: v1
kind: Service
metadata:
name: nginx-headless
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: "nginx-headless"
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.21
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "standard"
resources:
requests:
storage: 1Gi
Job and CronJob Template
# Job
apiVersion: batch/v1
kind: Job
metadata:
name: batch-job
spec:
completions: 3
parallelism: 2
backoffLimit: 4
template:
spec:
containers:
- name: worker
image: busybox
command: ['sh', '-c', 'echo "Processing..." && sleep 30']
restartPolicy: Never
---
# CronJob
apiVersion: batch/v1
kind: CronJob
metadata:
name: scheduled-job
spec:
schedule: "*/5 * * * *" # Every 5 minutes
jobTemplate:
spec:
template:
spec:
containers:
- name: task
image: busybox
command:
- /bin/sh
- -c
- date; echo "Running scheduled task"
restartPolicy: OnFailure
ConfigMap and Secret Template
# ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
database_url: "postgres://localhost:5432/mydb"
app.properties: |
server.port=8080
logging.level=INFO
---
# Secret
apiVersion: v1
kind: Secret
metadata:
name: app-secret
type: Opaque
data:
username: YWRtaW4= # base64 encoded 'admin'
password: cGFzc3dvcmQ= # base64 encoded 'password'
---
# Or using stringData (automatically base64 encoded)
apiVersion: v1
kind: Secret
metadata:
name: app-secret-string
type: Opaque
stringData:
username: admin
password: password
Ingress Template
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: nginx
tls:
- hosts:
- app.example.com
secretName: app-tls
rules:
- host: app.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 8080
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 80
# Quick deployment YAML (copy-paste starter)
$ kubectl create deployment nginx --image=nginx:1.25 --replicas=3 --dry-run=client -o yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx
name: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx:1.25
name: nginx
--dry-run=client -o yaml to generate YAML templates from imperative commands. This is faster than writing YAML from scratch and ensures correct API versions and structure.
Troubleshooting Guide
Systematic Debugging Approach
Always start with kubectl describe and kubectl logs before diving deeper. Most issues are caught at this level.
Pod Not Starting
- Check pod status:
kubectl get pod POD_NAME -o wide - Describe pod for events:
kubectl describe pod POD_NAME - Check logs:
kubectl logs POD_NAME --previous - Check resource availability:
kubectl describe nodes/kubectl top nodes - Check image pull:
kubectl get events --field-selector involvedObject.name=POD_NAME
Service Not Accessible
- Check service endpoints:
kubectl get endpoints SERVICE_NAME - Test service DNS:
kubectl run tmp --image=busybox -it --rm -- nslookup SERVICE_NAME - Check service selector:
kubectl get svc SERVICE_NAME -o yaml - Test connectivity:
kubectl run tmp --image=nicolaka/netshoot -it --rm -- curl SERVICE_NAME:PORT
Common Issues and Solutions
| Issue | Possible Cause | Solution |
|---|---|---|
| ImagePullBackOff | Image not found or auth failed | Check image name, registry auth, imagePullSecrets |
| CrashLoopBackOff | Application crashing | Check logs, fix application error, check resources |
| Pending | No resources or node selector | Check node resources, PVC binding, node affinity |
| OOMKilled | Out of memory | Increase memory limits, optimize application |
| Evicted | Node pressure | Check node disk/memory pressure, clean up |
Debugging Commands
# Resource investigation
kubectl get events --sort-by='.lastTimestamp'
kubectl get pods --all-namespaces -o wide
kubectl describe node NODE_NAME | grep -A 5 "Allocated resources"
kubectl top pods --all-namespaces
# Network debugging
kubectl exec -it POD -- nslookup kubernetes.default
kubectl exec -it POD -- ping SERVICE_NAME
kubectl exec -it POD -- curl -v http://SERVICE:PORT
kubectl get networkpolicies
# Storage issues
kubectl get pv
kubectl get pvc --all-namespaces
kubectl describe pvc PVC_NAME
kubectl get storageclass
# RBAC debugging
kubectl auth can-i VERB RESOURCE
kubectl auth can-i --list
kubectl get rolebindings,clusterrolebindings --all-namespaces
kubectl describe sa SERVICE_ACCOUNT
Deep Dive: Debugging CrashLoopBackOff
CrashLoopBackOff means the container keeps crashing and Kubernetes is backing off restart attempts. Debug steps: (1) kubectl logs pod-name --previous to see crash logs from the last attempt. (2) kubectl describe pod pod-name to check exit codes (137 = OOM killed, 1 = application error). (3) For OOM: increase memory limits. For app errors: check environment variables, config mounts, and dependency availability. (4) kubectl exec -it pod-name -- /bin/sh may work briefly before the crash to inspect the filesystem.
JSONPath and Output Formatting
JSONPath Examples
# Basic JSONPath
kubectl get pods -o jsonpath='{.items[*].metadata.name}'
kubectl get nodes -o jsonpath='{.items[*].status.addresses[?(@.type=="ExternalIP")].address}'
kubectl get pods -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.phase}{"\n"}{end}'
# Custom columns
kubectl get pods -o custom-columns=NAME:.metadata.name,STATUS:.status.phase
kubectl get nodes -o custom-columns=NAME:.metadata.name,CPU:.status.capacity.cpu
kubectl get pv -o custom-columns=NAME:.metadata.name,CAPACITY:.spec.capacity.storage
# Filtering & sorting
kubectl get pods --field-selector status.phase=Running
kubectl get events --sort-by='.metadata.creationTimestamp'
kubectl get pods --sort-by='.status.containerStatuses[0].restartCount'
# Complex queries
kubectl get pods -o jsonpath='{.items[?(@.status.phase!="Running")].metadata.name}'
kubectl get svc -o jsonpath='{.items[?(@.spec.type=="LoadBalancer")].status.loadBalancer.ingress[0].ip}'
kubectl get pods -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[*].image}{"\n"}{end}'
Output Formats
| Format | Flag | Description | Example |
|---|---|---|---|
| Wide | -o wide |
Additional columns | kubectl get pods -o wide |
| YAML | -o yaml |
YAML format | kubectl get pod nginx -o yaml |
| JSON | -o json |
JSON format | kubectl get pods -o json |
| Name only | -o name |
Resource type/name | kubectl get pods -o name |
| Custom columns | -o custom-columns= |
Custom output | kubectl get pods -o custom-columns=NAME:.metadata.name |
| Go template | -o go-template= |
Go template format | kubectl get pods -o go-template='{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}' |
Shortcuts and Productivity Tips
kubectl Aliases
# Basic aliases
alias k='kubectl'
alias kgp='kubectl get pods'
alias kgs='kubectl get svc'
alias kgd='kubectl get deployment'
alias kaf='kubectl apply -f'
alias kdel='kubectl delete'
alias kdes='kubectl describe'
alias klog='kubectl logs'
alias kex='kubectl exec -it'
# Namespace aliases
alias kgpa='kubectl get pods --all-namespaces'
alias kgsw='kubectl get svc --all-namespaces -o wide'
alias kn='kubectl config set-context --current --namespace'
# Quick commands
alias krun='kubectl run tmp --image=busybox -it --rm --restart=Never --'
alias kdebug='kubectl run debug --image=nicolaka/netshoot -it --rm --restart=Never --'
alias kport='kubectl port-forward'
alias ktop='kubectl top'
# Context management
alias kctx='kubectl config current-context'
alias kuse='kubectl config use-context'
# Resource watching
alias kwatch='kubectl get pods -w'
Shell Completion
# Bash
source <(kubectl completion bash)
echo "source <(kubectl completion bash)" >> ~/.bashrc
# Zsh
source <(kubectl completion zsh)
echo "source <(kubectl completion zsh)" >> ~/.zshrc
# Fish
kubectl completion fish | source
echo "kubectl completion fish | source" >> ~/.config/fish/config.fish
# PowerShell
kubectl completion powershell | Out-String | Invoke-Expression
Quick Tips
Dry Run
--dry-run=client -o yaml - Generate YAML without creating
Force Delete
--grace-period=0 --force - Force delete stuck resources
All Namespaces
-A or --all-namespaces - Work across all namespaces
Watch Changes
-w or --watch - Watch for resource changes
Label Selector
-l app=nginx - Filter by labels
Preview Changes
kubectl diff -f FILE.yaml - See what would change before applying
Useful Tools
k9s
Terminal UI for managing Kubernetes clusters interactively
kubectx / kubens
Fast context and namespace switching
stern
Multi-pod and container log tailing
krew
kubectl plugin manager
kustomize
Template-free configuration management
Helm
The package manager for Kubernetes
Power User Tips
- Use
kubectl explain RESOURCEfor inline documentation - Set
KUBE_EDITORenvironment variable for preferred editor - Use
kubectl diff -f FILE.yamlto preview changes - Use
kubectl api-resourcesto list all available resources - Use
kubectl api-versionsto check available API versions
$ kubectl get pods -o jsonpath='{range .items[*]}{.metadata.name}{" "}{.status.phase}{"
"}{end}'
api-7d4f8b-x2k9j Running
api-7d4f8b-p8m3n Running
worker-5c6d7e-q4r5t Running
# Get all images in use
$ kubectl get pods -o jsonpath='{.items[*].spec.containers[*].image}' | tr ' ' '
' | sort -u
myapp/api:v2.3.1
myapp/worker:v1.8.0
nginx:1.25
Practice Problems
Easy Deploy an Nginx Pod
Create a single Nginx pod using kubectl without writing a YAML file, then verify it is running.
Use kubectl run with the --image flag, then check with kubectl get pods.
# Create the pod
kubectl run nginx --image=nginx:1.21
# Verify it is running
kubectl get pods nginx
kubectl describe pod nginx
Easy Generate YAML Without Creating
Generate a Deployment YAML manifest for an app called "web" using the httpd image, with 3 replicas, without actually creating it.
Combine --dry-run=client with -o yaml to output the manifest.
kubectl create deployment web \
--image=httpd \
--replicas=3 \
--dry-run=client -o yaml
Medium Debug a CrashLoopBackOff Pod
A pod named "broken-app" is in CrashLoopBackOff. List the sequence of commands you would use to diagnose and identify the root cause.
Start with describe, then check logs (current and previous), then check events.
# Step 1: Get pod status details
kubectl describe pod broken-app
# Step 2: Check current logs
kubectl logs broken-app
# Step 3: Check previous container logs
kubectl logs broken-app --previous
# Step 4: Check events
kubectl get events --field-selector involvedObject.name=broken-app
# Step 5: If needed, run a debug container
kubectl debug broken-app -it --image=busybox
Hard Extract Specific Data with JSONPath
Write a single kubectl command that lists all pods NOT in Running state, showing their name, namespace, and current phase in a tabular format.
Use -o jsonpath with a filter expression ?(@.status.phase!="Running") and range iteration.
# Using JSONPath with range and filter
kubectl get pods -A -o jsonpath='{range .items[?(@.status.phase!="Running")]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.status.phase}{"\n"}{end}'
# Alternative: using custom-columns with field-selector
kubectl get pods -A \
--field-selector status.phase!=Running \
-o custom-columns=NAMESPACE:.metadata.namespace,NAME:.metadata.name,STATUS:.status.phase