Skip to content

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+ — kubectl is pre-configured, sudo required 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.