This page requires JavaScript to display.
K
Unpacking...
← DevOps
DevOps

Kubernetes Reference

Cluster architecture, core objects, manifests and kubectl, scaling and health checks, batch jobs, Spark on Kubernetes, troubleshooting, and Helm.

Contents
1. What Kubernetes Is 2. Core Objects 3. A Deployment and Service 4. kubectl Cheat Sheet 5. EKS: Checking Pods & Logs 6. Configuration & Secrets 7. Resources, Scaling & Health Checks 8. Jobs & CronJobs for Data Work 9. Spark on Kubernetes 10. Troubleshooting 11. Helm & Managed Kubernetes

1. What Kubernetes Is

Kubernetes (K8s) runs containers across a cluster of machines. You declare the desired state ("run 3 copies of this image, reachable on port 80") and controllers continuously work to make the actual state match: restarting crashed containers, rescheduling them when a node dies, and scaling them up or down.

            ┌──────────────── CONTROL PLANE ────────────────┐
 kubectl ──►│ API server ◄──► etcd (cluster state)          │
            │ scheduler (picks a node for each new pod)     │
            │ controller manager (reconciles desired state) │
            └───────────────────────┬───────────────────────┘
                 ┌──────────────────┼──────────────────┐
              NODE 1             NODE 2             NODE 3
          kubelet · kube-proxy · container runtime (containerd)
          [pod] [pod]          [pod] [pod]         [pod]
ComponentRole
API serverFront door for every request (kubectl, controllers, CI); validates and stores objects
etcdDistributed key-value store holding all cluster state
SchedulerAssigns new pods to nodes based on resource requests, affinity and taints
Controller managerRuns control loops (Deployments, ReplicaSets, Jobs, nodes) that reconcile state
kubeletAgent on each node; starts and monitors the pod's containers
kube-proxyPrograms node networking so Services route to the right pods

2. Core Objects

Pod
Smallest unit: one or more containers sharing network and storage. Disposable; never edited in place.
Deployment
Keeps N identical pods running via a ReplicaSet; handles rolling updates and rollbacks.
Service
Stable virtual IP and DNS name in front of a changing set of pods (ClusterIP, NodePort, LoadBalancer).
Ingress
HTTP(S) routing from outside the cluster to Services by host and path.
ConfigMap / Secret
Configuration and sensitive values injected as environment variables or files.
Namespace
Logical partition for teams or environments, with its own quotas and permissions.
StatefulSet
Pods with stable names and their own persistent volumes (databases, Kafka, ZooKeeper).
DaemonSet
One pod on every node (log shippers, monitoring agents).
Job / CronJob
Run-to-completion pods, once or on a schedule: batch and data jobs.
PersistentVolume / PVC
Storage that outlives pods; a claim requests size and access mode.

3. A Deployment and Service

Manifests are YAML files applied with kubectl apply -f. This one runs three replicas of an API and exposes them inside the cluster:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: fraud-api
  namespace: data
spec:
  replicas: 3
  selector:
    matchLabels: { app: fraud-api }
  template:
    metadata:
      labels: { app: fraud-api }
    spec:
      containers:
        - name: api
          image: myregistry/fraud-api:1.4.2      # pin a version, never :latest
          ports:
            - containerPort: 8080
          envFrom:
            - configMapRef: { name: fraud-api-config }
          resources:
            requests: { cpu: "250m", memory: "512Mi" }
            limits:   { memory: "1Gi" }
          readinessProbe:
            httpGet: { path: /health, port: 8080 }
            periodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
  name: fraud-api
  namespace: data
spec:
  selector: { app: fraud-api }       # routes to pods with this label
  ports:
    - port: 80
      targetPort: 8080

Other pods reach it at http://fraud-api.data.svc.cluster.local (or just fraud-api from the same namespace). Labels and selectors are how Deployments find their pods and Services find their endpoints.

4. kubectl Cheat Sheet

kubectl config get-contexts / use-context prod      # which cluster am I talking to?
kubectl get pods -n data -o wide                    # pods with node and IP
kubectl get deploy,svc,ingress -n data
kubectl describe pod fraud-api-7d9f -n data         # events: scheduling, pulls, probe failures
kubectl logs fraud-api-7d9f -n data -f              # follow logs (add -c <container>, --previous)
kubectl exec -it fraud-api-7d9f -n data -- sh       # shell inside the container
kubectl apply -f k8s/                               # create or update from manifests
kubectl diff -f k8s/                                # preview changes before applying
kubectl rollout status deploy/fraud-api -n data
kubectl rollout undo deploy/fraud-api -n data       # roll back to the previous version
kubectl scale deploy/fraud-api --replicas=5 -n data
kubectl port-forward svc/fraud-api 8080:80 -n data  # test a service from your laptop
kubectl top pods -n data                            # CPU / memory (needs metrics-server)
kubectl get events -n data --sort-by=.lastTimestamp

5. EKS: Checking Pods & Logs

1. Connect kubectl to the EKS cluster

aws sts get-caller-identity                          # which IAM user/role am I?
aws eks list-clusters --region ap-south-1
aws eks update-kubeconfig --region ap-south-1 --name data-platform-prod --alias prod
kubectl config current-context                       # confirm you are on the right cluster
kubectl get nodes -o wide                            # nodes, status, versions, IPs

If kubectl says "You must be logged in to the server (Unauthorized)", your IAM identity has no access to the cluster. An admin must add it as an access entry (aws eks list-access-entries --cluster-name data-platform-prod) or, on older clusters, to the aws-auth ConfigMap.

2. Check pods

kubectl get pods -A                                   # all namespaces
kubectl get pods -n data -o wide                      # + node and pod IP
kubectl get pods -n data -l app=fraud-api             # filter by label
kubectl get pods -n data --field-selector=status.phase!=Running   # anything not running
kubectl get pods -n data -w                           # watch status changes live
kubectl get pods -n data --sort-by='.status.containerStatuses[0].restartCount'
kubectl describe pod fraud-api-7d9f8-x2k4p -n data    # events at the bottom explain most failures
kubectl get pod fraud-api-7d9f8-x2k4p -n data -o yaml # full spec and status
kubectl get events -n data --sort-by=.lastTimestamp
kubectl top pods -n data --containers                 # CPU/memory (needs the metrics-server add-on)
kubectl top nodes

3. Read pod logs

kubectl logs fraud-api-7d9f8-x2k4p -n data                    # current logs
kubectl logs fraud-api-7d9f8-x2k4p -n data -f                 # follow (stream) new lines
kubectl logs fraud-api-7d9f8-x2k4p -n data --tail=200 --timestamps
kubectl logs fraud-api-7d9f8-x2k4p -n data --since=1h         # or --since-time=2026-10-25T02:00:00Z
kubectl logs fraud-api-7d9f8-x2k4p -n data --previous         # the crashed container before a restart
kubectl logs fraud-api-7d9f8-x2k4p -n data -c sidecar         # one container in a multi-container pod
kubectl logs fraud-api-7d9f8-x2k4p -n data --all-containers
kubectl logs fraud-api-7d9f8-x2k4p -n data -c init-db         # init container logs

kubectl logs deploy/fraud-api -n data                         # logs from one pod of a deployment
kubectl logs job/nightly-export -n data                       # logs of a Job's pod
kubectl logs -l app=fraud-api -n data --prefix --tail=100     # all matching pods, lines prefixed with pod name

kubectl logs fraud-api-7d9f8-x2k4p -n data > fraud-api.log    # save to a file

4. Get inside a pod

kubectl exec -it fraud-api-7d9f8-x2k4p -n data -- sh                  # shell (bash if the image has it)
kubectl exec -it fraud-api-7d9f8-x2k4p -n data -c api -- env          # check environment variables
kubectl exec fraud-api-7d9f8-x2k4p -n data -- cat /app/logs/app.log   # app logs written to a file
kubectl debug -it fraud-api-7d9f8-x2k4p -n data --image=busybox --target=api   # debug container for minimal images
kubectl port-forward pod/fraud-api-7d9f8-x2k4p 8080:8080 -n data       # call the pod from your laptop

5. Spark jobs on EKS

kubectl get pods -n spark-jobs -l spark-role=driver               # driver pods
kubectl logs -f <driver-pod> -n spark-jobs                         # job progress and errors
kubectl get pods -n spark-jobs -l spark-role=executor
kubectl logs <executor-pod> -n spark-jobs --previous               # an executor that was OOMKilled
kubectl port-forward <driver-pod> 4040:4040 -n spark-jobs          # open the Spark UI at localhost:4040

Executor pods are deleted when the job ends, and their logs go with them. Set spark.kubernetes.executor.deleteOnTermination=false while debugging, and ship logs to CloudWatch or S3 for production.

6. Logs after the pod is gone: CloudWatch

kubectl only reads logs from pods that still exist. For history, install the Amazon CloudWatch Observability EKS add-on (Container Insights with Fluent Bit), which ships container logs to CloudWatch Logs:

aws logs tail /aws/containerinsights/data-platform-prod/application --follow
aws logs tail /aws/containerinsights/data-platform-prod/application \
    --since 2h --filter-pattern "ERROR"

# control-plane logs (API server, authenticator, audit) must be enabled first
aws eks update-cluster-config --region ap-south-1 --name data-platform-prod \
    --logging '{"clusterLogging":[{"types":["api","audit","authenticator"],"enabled":true}]}'
aws logs tail /aws/eks/data-platform-prod/cluster --since 30m
What you seeCommand to run first
Pod stuck Pendingkubectl describe pod → events (insufficient CPU/memory, no matching node, PVC not bound)
CrashLoopBackOffkubectl logs <pod> --previous
ImagePullBackOffkubectl describe pod → image name/tag; ECR permissions on the node role
OOMKilledkubectl describe pod → Last State: Terminated, Reason: OOMKilled, exit code 137
Many restartskubectl get pods RESTARTS column, then --previous logs
Node problemskubectl describe node <node> → conditions (MemoryPressure, DiskPressure), allocated resources

6. Configuration & Secrets

apiVersion: v1
kind: ConfigMap
metadata: { name: fraud-api-config, namespace: data }
data:
  KAFKA_BOOTSTRAP: "kafka:9092"
  LOG_LEVEL: "INFO"
---
apiVersion: v1
kind: Secret
metadata: { name: mongo-credentials, namespace: data }
type: Opaque
stringData:                     # plain text here; stored base64-encoded
  MONGO_USER: app
  MONGO_PASSWORD: change-me

7. Resources, Scaling & Health Checks

SettingMeaningEffect
requestsGuaranteed amount, used for schedulingA pod stays Pending if no node has this much free
limits.cpuMaximum CPUThe container is throttled, not killed
limits.memoryMaximum memoryExceeding it gets the container OOMKilled (exit code 137)

Pods whose requests equal their limits get the Guaranteed QoS class and are evicted last under node pressure; pods with no requests are BestEffort and evicted first.

ProbeQuestion it answersOn failure
LivenessIs the process stuck?Container restarted
ReadinessCan it serve traffic now?Removed from Service endpoints, not restarted
StartupHas a slow app finished starting?Liveness checks wait until it passes
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata: { name: fraud-api, namespace: data }
spec:
  scaleTargetRef: { apiVersion: apps/v1, kind: Deployment, name: fraud-api }
  minReplicas: 3
  maxReplicas: 20
  metrics:
    - type: Resource
      resource:
        name: cpu
        target: { type: Utilization, averageUtilization: 70 }   # % of the CPU request

The HPA adds pods; the Cluster Autoscaler or Karpenter adds nodes when pods cannot be scheduled. For Kafka consumers, KEDA can scale on consumer lag instead of CPU.

8. Jobs & CronJobs for Data Work

apiVersion: batch/v1
kind: CronJob
metadata: { name: nightly-export, namespace: data }
spec:
  schedule: "0 2 * * *"            # 02:00 daily, in the controller's time zone
  timeZone: "Asia/Kolkata"         # supported in Kubernetes 1.27+
  concurrencyPolicy: Forbid        # don't start a run while the previous one is still going
  jobTemplate:
    spec:
      backoffLimit: 2              # retries before the Job is marked failed
      activeDeadlineSeconds: 7200
      template:
        spec:
          restartPolicy: Never
          containers:
            - name: export
              image: myregistry/exporter:2.0.1
              args: ["--lookback-days", "1"]
              envFrom:
                - secretRef: { name: warehouse-credentials }

Make jobs idempotent: a pod can be retried, or (rarely) run twice. For multi-step pipelines with dependencies, use an orchestrator (Airflow's KubernetesPodOperator, Argo Workflows) rather than chaining CronJobs by time.

9. Spark on Kubernetes

Kubernetes can replace YARN as Spark's cluster manager. spark-submit creates a driver pod, and the driver asks the API server for executor pods, deleting them when the job finishes.

spark-submit \
  --master k8s://https://<api-server>:443 \
  --deploy-mode cluster \
  --name txn-enrichment \
  --conf spark.kubernetes.namespace=spark-jobs \
  --conf spark.kubernetes.container.image=myregistry/spark-py:3.5.1 \
  --conf spark.kubernetes.authenticate.driver.serviceAccountName=spark \
  --conf spark.executor.instances=10 \
  --conf spark.executor.cores=4 \
  --conf spark.executor.memory=12g \
  --conf spark.dynamicAllocation.enabled=true \
  --conf spark.dynamicAllocation.shuffleTracking.enabled=true \
  local:///opt/app/jobs/enrich_txn.py --run-date 2026-10-25

10. Troubleshooting

SymptomLikely causeFirst check
PendingNo node has the requested CPU/memory, or no PVC/node matcheskubectl describe pod events; node capacity; autoscaler
ImagePullBackOffWrong image name/tag, or missing registry credentialsImage path, imagePullSecrets, registry access from nodes
CrashLoopBackOffContainer starts then exits repeatedly (bad config, missing env, app error)kubectl logs --previous
OOMKilled (exit 137)Memory limit exceededRaise the limit or reduce memory use; for Spark, raise memoryOverhead
EvictedNode ran out of memory or diskRequests/limits, ephemeral storage, log volume
Service not reachableSelector does not match pod labels, wrong targetPort, pod not readykubectl get endpoints <svc> (empty means no matching ready pods)

11. Helm & Managed Kubernetes

Helm packages manifests into versioned, parameterised charts. One chart plus a values file per environment replaces copies of near-identical YAML:

helm repo add bitnami https://charts.bitnami.com/bitnami
helm install kafka bitnami/kafka -n streaming -f values-dev.yaml
helm upgrade --install fraud-api ./charts/fraud-api -f values-prod.yaml --set image.tag=1.4.3
helm rollback fraud-api 3
helm list -n data

In a chart template, values are referenced with Go templating, e.g. image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}".

ServiceCloudNotes
EKSAWSManaged control plane; Karpenter or managed node groups; IRSA / Pod Identity for AWS permissions
AKSAzureManaged control plane at no charge (Free tier); Entra ID integration
GKEGoogle CloudAutopilot mode manages nodes for you

Common GitOps setup: manifests or Helm values live in Git, and Argo CD or Flux continuously syncs the cluster to match, so Git is the source of truth and every change is reviewed.