CKA Cheat Sheet 2026¶
Exam Domains: Storage 10% | Troubleshooting 30% | Workloads & Scheduling 15% | Cluster Architecture 25% | Services & Networking 20%
Kubernetes version on exam: 1.34+ —
kubectlis pre-configured,sudorequired for node-level tasks. Allowed docs: kubernetes.io/docs, kubernetes.io/blog, helm.sh/docs
Quick Wins — Always Do First¶
# Set alias (saves time on every command)
alias k=kubectl
export do="--dry-run=client -o yaml" # k run pod1 --image=nginx $do > pod.yaml
export now="--force --grace-period=0" # k delete pod pod1 $now
# Autocomplete
source <(kubectl completion bash)
complete -o default -F __start_kubectl k
# Context switching (exam has multiple clusters)
kubectl config get-contexts
kubectl config use-context <context-name>
kubectl config current-context
1. Cluster Architecture, Installation & Configuration (25%)¶
kubeadm — Init & Join¶
# Bootstrap control plane
kubeadm init \
--pod-network-cidr=10.244.0.0/16 \
--kubernetes-version=1.32.0 \
--apiserver-advertise-address=<control-plane-ip>
# Copy kubeconfig after init
mkdir -p $HOME/.kube
sudo cp /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
# Get join command (run on control plane)
kubeadm token create --print-join-command
# Join a worker node
kubeadm join <control-plane-ip>:6443 \
--token <token> \
--discovery-token-ca-cert-hash sha256:<hash>
Upgrade Cluster (kubeadm)¶
# On CONTROL PLANE:
# 1. Upgrade kubeadm
sudo apt-mark unhold kubeadm && \
sudo apt-get update && sudo apt-get install -y kubeadm=1.32.x-* && \
sudo apt-mark hold kubeadm
# 2. Plan and apply upgrade
kubeadm upgrade plan
sudo kubeadm upgrade apply v1.32.x
# 3. Upgrade kubelet & kubectl on control plane
sudo apt-mark unhold kubelet kubectl && \
sudo apt-get install -y kubelet=1.32.x-* kubectl=1.32.x-* && \
sudo apt-mark hold kubelet kubectl
sudo systemctl daemon-reload && sudo systemctl restart kubelet
# On each WORKER NODE:
kubectl drain <node> --ignore-daemonsets --delete-emptydir-data # from control plane
# SSH to worker:
sudo apt-mark unhold kubeadm kubelet kubectl && \
sudo apt-get install -y kubeadm=1.32.x-* kubelet=1.32.x-* kubectl=1.32.x-* && \
sudo apt-mark hold kubeadm kubelet kubectl
sudo kubeadm upgrade node
sudo systemctl daemon-reload && sudo systemctl restart kubelet
# Back on control plane:
kubectl uncordon <node>
etcd Backup & Restore¶
# Backup
ETCDCTL_API=3 etcdctl snapshot save /opt/backup/etcd-snapshot.db \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key
# Verify backup
ETCDCTL_API=3 etcdctl snapshot status /opt/backup/etcd-snapshot.db --write-out=table
# Restore
ETCDCTL_API=3 etcdctl snapshot restore /opt/backup/etcd-snapshot.db \
--data-dir=/var/lib/etcd-restore \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key
# Update etcd manifest to use new data-dir
sudo vi /etc/kubernetes/manifests/etcd.yaml
# Change: --data-dir=/var/lib/etcd → --data-dir=/var/lib/etcd-restore
# Also update volumeMount hostPath accordingly
RBAC¶
# Create Role (namespace-scoped)
kubectl create role pod-reader \
--verb=get,list,watch \
--resource=pods \
-n dev
# Create ClusterRole (cluster-wide)
kubectl create clusterrole node-reader \
--verb=get,list,watch \
--resource=nodes
# Bind Role to ServiceAccount
kubectl create rolebinding dev-pod-reader \
--role=pod-reader \
--serviceaccount=dev:my-sa \
-n dev
# Bind ClusterRole to user
kubectl create clusterrolebinding node-reader-binding \
--clusterrole=node-reader \
--user=jane
# Test permissions
kubectl auth can-i list pods --as=jane -n dev
kubectl auth can-i list nodes --as=system:serviceaccount:dev:my-sa
ServiceAccount¶
# Create SA
kubectl create serviceaccount my-sa -n dev
# Create SA token (short-lived, projected)
kubectl create token my-sa -n dev --duration=1h
# Assign SA to pod
kubectl run mypod --image=nginx --serviceaccount=my-sa -n dev
Static Pods¶
# Static pod manifests location
ls /etc/kubernetes/manifests/
# Create static pod (place yaml in manifests dir)
sudo cp pod.yaml /etc/kubernetes/manifests/
# Kubelet watches directory automatically — pod starts immediately
# Static pod name = <name>-<nodename>
kubectl get pod mypod-controlplane -n kube-system
Certificate Management¶
# Check cert expiry
sudo kubeadm certs check-expiration
# Renew all certs
sudo kubeadm certs renew all
# Approve CSR (Certificate Signing Request)
kubectl get csr
kubectl certificate approve <csr-name>
kubectl certificate deny <csr-name>
# Create CertificateSigningRequest
cat <<EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: jane
spec:
request: $(cat jane.csr | base64 | tr -d '\n')
signerName: kubernetes.io/kube-apiserver-client
expirationSeconds: 86400
usages:
- client auth
EOF
Node Management¶
# Cordon (prevent scheduling)
kubectl cordon <node>
# Drain (evict pods + cordon)
kubectl drain <node> --ignore-daemonsets --delete-emptydir-data
# Uncordon
kubectl uncordon <node>
# Node labels
kubectl label node <node> disktype=ssd
kubectl label node <node> disktype- # remove label
# Node taints
kubectl taint node <node> key=value:NoSchedule
kubectl taint node <node> key=value:NoSchedule- # remove taint
2. Services & Networking (20%)¶
Service Types¶
# ClusterIP (default, internal)
kubectl expose pod mypod --port=80 --target-port=8080 --name=my-svc
# NodePort (external access via node IP)
kubectl expose deployment myapp --type=NodePort --port=80 --target-port=8080
# LoadBalancer
kubectl expose deployment myapp --type=LoadBalancer --port=80
# Headless (for StatefulSets / direct pod DNS)
# clusterIP: None in spec
# Check service endpoints
kubectl get endpoints my-svc
kubectl describe svc my-svc
# DNS resolution inside cluster
# <service>.<namespace>.svc.cluster.local
# Pod DNS: <pod-ip-dashes>.<namespace>.pod.cluster.local
Ingress¶
# Create Ingress (path-based)
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
namespace: web
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: app.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-svc
port:
number: 8080
tls:
- hosts:
- app.example.com
secretName: app-tls
EOF
kubectl get ingress -A
kubectl describe ingress my-ingress -n web
Gateway API (replaces Ingress — exam uses this now)¶
# Check GatewayClass
kubectl get gatewayclass
cat <<EOF | kubectl apply -f -
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: my-gateway
namespace: web
spec:
gatewayClassName: nginx
listeners:
- name: http
protocol: HTTP
port: 80
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: my-route
namespace: web
spec:
parentRefs:
- name: my-gateway
namespace: web
hostnames:
- "app.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /api
backendRefs:
- name: api-svc
port: 8080
EOF
Network Policy¶
# Deny all ingress (default deny)
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all
namespace: dev
spec:
podSelector: {}
policyTypes:
- Ingress
EOF
# Allow ingress from specific namespace + pod
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend
namespace: backend
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: frontend
podSelector:
matchLabels:
app: web
ports:
- protocol: TCP
port: 8080
EOF
# Allow egress to specific CIDR
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-egress-db
namespace: app
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 5432
EOF
CoreDNS & DNS Debugging¶
# Check CoreDNS
kubectl get pods -n kube-system -l k8s-app=kube-dns
kubectl logs -n kube-system -l k8s-app=kube-dns
# Test DNS from a pod
kubectl run dns-test --image=busybox:1.36 --rm -it --restart=Never -- \
nslookup kubernetes.default.svc.cluster.local
# Check DNS config
kubectl get configmap coredns -n kube-system -o yaml
CNI (Calico / Flannel)¶
# Install Calico (after kubeadm init)
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.29/manifests/calico.yaml
# Verify CNI pods
kubectl get pods -n kube-system -l k8s-app=calico-node
kubectl get nodes # should go Ready after CNI installed
3. Workloads & Scheduling (15%)¶
Pod & Deployment Basics¶
# Create pod
kubectl run mypod --image=nginx:1.27 --port=80
# Create deployment
kubectl create deployment myapp --image=nginx:1.27 --replicas=3
# Scale
kubectl scale deployment myapp --replicas=5
# Update image
kubectl set image deployment/myapp nginx=nginx:1.28
# Rollout
kubectl rollout status deployment/myapp
kubectl rollout history deployment/myapp
kubectl rollout undo deployment/myapp
kubectl rollout undo deployment/myapp --to-revision=2
# Pause/Resume rollout
kubectl rollout pause deployment/myapp
kubectl rollout resume deployment/myapp
Resource Requests & Limits¶
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: resource-pod
spec:
containers:
- name: app
image: nginx
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
EOF
HPA (Horizontal Pod Autoscaler)¶
# CPU-based HPA
kubectl autoscale deployment myapp \
--cpu-percent=50 \
--min=2 \
--max=10
kubectl get hpa
kubectl describe hpa myapp
# HPA v2 with memory metric
cat <<EOF | kubectl apply -f -
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: myapp-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: myapp
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
EOF
Scheduling: NodeSelector / Affinity / Taints¶
# NodeSelector (simple)
spec:
nodeSelector:
disktype: ssd
# Node Affinity (required)
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values: [ssd]
# Node Affinity (preferred)
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: zone
operator: In
values: [us-east-1a]
# Pod Anti-Affinity (spread across nodes)
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: myapp
topologyKey: kubernetes.io/hostname
# Toleration (allow pod on tainted node)
spec:
tolerations:
- key: "gpu"
operator: "Equal"
value: "true"
effect: "NoSchedule"
PriorityClass¶
cat <<EOF | kubectl apply -f -
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: high-priority
value: 1000000
globalDefault: false
description: "High priority workloads"
EOF
# Use in pod
spec:
priorityClassName: high-priority
Jobs & CronJobs¶
# Job
kubectl create job myjob --image=busybox -- sh -c "echo hello"
cat <<EOF | kubectl apply -f -
apiVersion: batch/v1
kind: Job
metadata:
name: batch-job
spec:
completions: 5 # total successful pods needed
parallelism: 2 # run 2 at a time
backoffLimit: 3
template:
spec:
restartPolicy: Never
containers:
- name: worker
image: busybox
command: ["sh", "-c", "echo done"]
EOF
# CronJob
kubectl create cronjob mycron \
--image=busybox \
--schedule="*/5 * * * *" \
-- sh -c "date"
kubectl get cronjob
kubectl get jobs --watch
Multi-Container Patterns¶
# Sidecar / Init container
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: multi-pod
spec:
initContainers:
- name: init-setup
image: busybox
command: ['sh', '-c', 'echo init > /data/init.txt']
volumeMounts:
- name: shared
mountPath: /data
containers:
- name: main
image: nginx
volumeMounts:
- name: shared
mountPath: /usr/share/nginx/html
- name: sidecar
image: busybox
command: ['sh', '-c', 'while true; do date >> /data/log.txt; sleep 5; done']
volumeMounts:
- name: shared
mountPath: /data
volumes:
- name: shared
emptyDir: {}
EOF
ConfigMap & Secret¶
# ConfigMap
kubectl create configmap myconfig \
--from-literal=key1=value1 \
--from-literal=key2=value2
kubectl create configmap myconfig --from-file=app.properties
# Secret
kubectl create secret generic mysecret \
--from-literal=password=mypassword
kubectl create secret tls tls-secret \
--cert=tls.crt --key=tls.key
# Use in pod (env)
spec:
containers:
- name: app
envFrom:
- configMapRef:
name: myconfig
- secretRef:
name: mysecret
# Single key env var
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: mysecret
key: password
# Mount as volume
volumes:
- name: config-vol
configMap:
name: myconfig
containers:
- volumeMounts:
- name: config-vol
mountPath: /etc/config
4. Storage (10%)¶
StorageClass, PV, PVC¶
# StorageClass (local path — common in exam)
cat <<EOF | kubectl apply -f -
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Retain
EOF
# PersistentVolume (hostPath — exam/local clusters)
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolume
metadata:
name: my-pv
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: local-storage
hostPath:
path: /data/pv1
EOF
# PersistentVolumeClaim
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 500Mi
storageClassName: local-storage
EOF
# Mount PVC in pod
spec:
volumes:
- name: storage
persistentVolumeClaim:
claimName: my-pvc
containers:
- name: app
image: nginx
volumeMounts:
- name: storage
mountPath: /data
Access Modes¶
| Mode | Short | Meaning |
|---|---|---|
| ReadWriteOnce | RWO | One node R/W |
| ReadOnlyMany | ROX | Many nodes read-only |
| ReadWriteMany | RWX | Many nodes R/W |
| ReadWriteOncePod | RWOP | One pod R/W (k8s 1.22+) |
Volume Types Quick Ref¶
# emptyDir — temporary, lost on pod delete
volumes:
- name: tmp
emptyDir: {}
# hostPath — mounts node path (use with care)
volumes:
- name: host-data
hostPath:
path: /var/data
type: DirectoryOrCreate
# configMap / secret — mount as files (see Workloads section)
# projected — combine multiple sources
volumes:
- name: projected-vol
projected:
sources:
- configMap:
name: myconfig
- secret:
name: mysecret
StatefulSet with VolumeClaimTemplate¶
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mydb
spec:
serviceName: mydb
replicas: 3
selector:
matchLabels:
app: mydb
template:
metadata:
labels:
app: mydb
spec:
containers:
- name: db
image: mysql:8.0
env:
- name: MYSQL_ROOT_PASSWORD
value: "rootpass"
volumeMounts:
- name: data
mountPath: /var/lib/mysql
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: [ReadWriteOnce]
resources:
requests:
storage: 1Gi
EOF
5. Troubleshooting (30%)¶
Pod Failures — Decision Tree¶
Pod not starting?
├── Pending → kubectl describe pod → check Events
│ ├── Insufficient CPU/memory → check node resources: kubectl top nodes
│ ├── No nodes match nodeSelector/affinity → fix selector or label node
│ └── PVC not bound → kubectl get pvc
├── ImagePullBackOff / ErrImagePull
│ ├── Wrong image name/tag → kubectl set image ...
│ └── Private registry → check imagePullSecrets
├── CrashLoopBackOff → kubectl logs <pod> --previous
│ ├── App crash → fix app or command
│ ├── Missing env/config → check configmap/secret mounts
│ └── Permission error → check securityContext
├── OOMKilled → increase memory limit
└── Running but not ready → check readinessProbe
kubectl describe pod | grep -A5 Readiness
# Core troubleshooting commands
kubectl get pods -A -o wide # all pods, all namespaces
kubectl describe pod <pod> -n <ns> # events + config
kubectl logs <pod> -n <ns> # current logs
kubectl logs <pod> -n <ns> --previous # logs from crashed container
kubectl logs <pod> -n <ns> -c <container> # specific container
kubectl get events -n <ns> --sort-by='.lastTimestamp'
kubectl get events -A --field-selector reason=BackOff
# Resource usage
kubectl top nodes
kubectl top pods -A --sort-by=memory
kubectl top pods -A --sort-by=cpu
# Execute into pod for debugging
kubectl exec -it <pod> -n <ns> -- sh
kubectl exec -it <pod> -n <ns> -- curl http://service-name/health
# Run ephemeral debug container (k8s 1.23+)
kubectl debug -it <pod> --image=busybox --target=<container> -n <ns>
# Copy files
kubectl cp <pod>:/path/file ./local-file -n <ns>
Node Troubleshooting¶
# Check node status
kubectl get nodes
kubectl describe node <node> # check Conditions, Capacity, Allocatable
kubectl top node <node>
# SSH to node, then:
# Check kubelet
sudo systemctl status kubelet
sudo journalctl -u kubelet -n 50 --no-pager
sudo systemctl restart kubelet
# Check container runtime
sudo systemctl status containerd
sudo crictl ps # list containers (crictl replaces docker)
sudo crictl pods
sudo crictl logs <container-id>
sudo crictl inspect <container-id>
# Check disk pressure
df -h
du -sh /var/lib/containerd
# Check node conditions
kubectl describe node <node> | grep -A10 Conditions
# Look for: MemoryPressure, DiskPressure, PIDPressure, Ready
Control Plane Troubleshooting¶
# Check all control plane pods
kubectl get pods -n kube-system
kubectl describe pod kube-apiserver-controlplane -n kube-system
# Static pod logs (when apiserver is down)
sudo crictl ps | grep kube-apiserver
sudo crictl logs <container-id>
# Check manifests
ls /etc/kubernetes/manifests/
sudo cat /etc/kubernetes/manifests/kube-apiserver.yaml
# Common fixes:
# Wrong flag → edit manifest, kubelet restarts pod automatically
sudo vi /etc/kubernetes/manifests/kube-apiserver.yaml
# etcd not reachable → check etcd pod + certs
kubectl get pods -n kube-system | grep etcd
kubectl logs etcd-controlplane -n kube-system
# Kubelet config location
sudo cat /var/lib/kubelet/config.yaml
sudo cat /etc/kubernetes/kubelet.conf
Service & Network Troubleshooting¶
# Service not routing traffic
kubectl get svc <svc> -n <ns>
kubectl get endpoints <svc> -n <ns> # empty = no pods match selector
kubectl describe svc <svc> -n <ns> # check selector vs pod labels
# Compare service selector with pod labels
kubectl get svc <svc> -n <ns> -o jsonpath='{.spec.selector}'
kubectl get pods -n <ns> --show-labels
# Test connectivity from inside cluster
kubectl run curl-test --image=curlimages/curl --rm -it --restart=Never -- \
curl http://<service>.<namespace>.svc.cluster.local
# DNS troubleshooting
kubectl run dns-test --image=busybox:1.36 --rm -it --restart=Never -- \
nslookup <service>.<namespace>.svc.cluster.local
# Check CoreDNS
kubectl get pods -n kube-system -l k8s-app=kube-dns
kubectl logs -n kube-system -l k8s-app=kube-dns
kubectl describe configmap coredns -n kube-system
# NetworkPolicy blocking traffic?
kubectl get networkpolicy -A
kubectl describe networkpolicy <name> -n <ns>
# Check kube-proxy
kubectl get pods -n kube-system -l k8s-app=kube-proxy
kubectl logs -n kube-system -l k8s-app=kube-proxy
# iptables rules (on node)
sudo iptables -L -n -t nat | grep <service-name>
Application Troubleshooting¶
# Deployment not rolling out
kubectl rollout status deployment/<name> -n <ns>
kubectl describe deployment <name> -n <ns>
kubectl get rs -n <ns> # check ReplicaSet events
# ConfigMap / Secret not mounting
kubectl get configmap <name> -n <ns> -o yaml
kubectl get secret <name> -n <ns> -o yaml
kubectl describe pod <pod> -n <ns> | grep -A10 Volumes
# Decode secret value
kubectl get secret <name> -n <ns> -o jsonpath='{.data.password}' | base64 -d
# Liveness / Readiness probe failures
kubectl describe pod <pod> -n <ns> | grep -A10 -i probe
kubectl describe pod <pod> -n <ns> | grep -i "liveness\|readiness"
# Resource quota / LimitRange
kubectl get resourcequota -n <ns>
kubectl describe resourcequota -n <ns>
kubectl get limitrange -n <ns>
Cluster-level Quick Checks¶
# Cluster info
kubectl cluster-info
kubectl get componentstatuses # deprecated but still on exam
kubectl get --raw='/readyz?verbose'
kubectl get --raw='/healthz?verbose'
# Version
kubectl version --short
kubeadm version
# API resources
kubectl api-resources
kubectl api-versions | grep rbac
kubectl explain pod.spec.containers.resources
Exam Speed Tips¶
Generate YAML Fast¶
# Pod
kubectl run mypod --image=nginx $do > pod.yaml
# Deployment
kubectl create deployment myapp --image=nginx --replicas=3 $do > deploy.yaml
# Service
kubectl expose deployment myapp --port=80 --target-port=8080 $do > svc.yaml
# Job
kubectl create job myjob --image=busybox $do -- sh -c "echo hi" > job.yaml
# CronJob
kubectl create cronjob mycron --image=busybox --schedule="* * * * *" $do -- date > cron.yaml
# ConfigMap
kubectl create configmap mymap --from-literal=key=val $do > cm.yaml
# Secret
kubectl create secret generic mysec --from-literal=pass=abc $do > sec.yaml
# ServiceAccount
kubectl create sa mysa $do > sa.yaml
# Role
kubectl create role myrole --verb=get,list --resource=pods $do > role.yaml
# ClusterRole
kubectl create clusterrole myclr --verb=get,list --resource=nodes $do > clr.yaml
# RoleBinding
kubectl create rolebinding myrb --role=myrole --serviceaccount=ns:mysa $do > rb.yaml
Useful One-liners¶
# Find all resources in a namespace
kubectl get all -n <ns>
# Watch pods
kubectl get pods -n <ns> -w
# Force delete stuck pod
kubectl delete pod <pod> -n <ns> --force --grace-period=0
# Apply and watch
kubectl apply -f manifest.yaml && kubectl rollout status deployment/myapp
# Get pod's node
kubectl get pod <pod> -o wide
# Get all pod IPs
kubectl get pods -o wide -A | awk '{print $7, $1, $2}'
# Find pods by label
kubectl get pods -l app=myapp -A
# Exec with specific shell
kubectl exec -it <pod> -- /bin/bash
kubectl exec -it <pod> -- /bin/sh
# Quick port-forward to test service
kubectl port-forward svc/myapp 8080:80 &
# Check what's using a node's resources
kubectl describe node <node> | grep -A20 "Non-terminated Pods"
vim Tips (for editing YAML)¶
:set number show line numbers
:set paste paste without auto-indent
gg=G auto-indent entire file
dG delete from cursor to end
/text search
n next match
:%s/old/new/g replace all
u undo
:wq save and quit
:q! quit without saving
Key File Locations¶
| File | Path |
|---|---|
| kubeconfig | ~/.kube/config |
| Static pod manifests | /etc/kubernetes/manifests/ |
| PKI certs | /etc/kubernetes/pki/ |
| etcd certs | /etc/kubernetes/pki/etcd/ |
| Kubelet config | /var/lib/kubelet/config.yaml |
| Kubelet kubeconfig | /etc/kubernetes/kubelet.conf |
| CNI config | /etc/cni/net.d/ |
| CNI binaries | /opt/cni/bin/ |
| containerd config | /etc/containerd/config.toml |
Common Patterns to Memorize¶
# Pattern: Create + Verify
kubectl apply -f resource.yaml
kubectl get <resource> -n <ns>
kubectl describe <resource> <name> -n <ns>
# Pattern: Debug pod failure
kubectl describe pod <pod> -n <ns> # check Events
kubectl logs <pod> -n <ns> # check output
kubectl logs <pod> -n <ns> --previous # if crashed
# Pattern: Fix broken cluster (node level)
ssh <node>
sudo systemctl status kubelet
sudo journalctl -u kubelet --no-pager | tail -30
sudo systemctl restart kubelet
exit
kubectl get nodes
# Pattern: RBAC setup
kubectl create sa <sa> -n <ns>
kubectl create role <role> --verb=<verbs> --resource=<resources> -n <ns>
kubectl create rolebinding <rb> --role=<role> --serviceaccount=<ns>:<sa> -n <ns>
kubectl auth can-i <verb> <resource> --as=system:serviceaccount:<ns>:<sa> -n <ns>
Discussion
Have thoughts on this post? Share them below — questions, corrections, or your own experience are all welcome.