iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Pod Spec Deep Dive

A Pod is the smallest unit Kubernetes schedules — one or more containers sharing a network namespace and storage. Understanding the spec (containers, volumes, probes, resources, security context) is the foundation for every workload kind: Deployments, Jobs, StatefulSets, DaemonSets.

containers, volumes, probes, resources

EXAMPLE
# 1) Minimal Pod
apiVersion: v1
kind: Pod
metadata:
    name: my-pod
    labels: { app: web }
spec:
    containers:
        - name: web
            image: nginx:1.27-alpine
            ports:
                - containerPort: 80

# 2) Multi-container — sidecar pattern
apiVersion: v1
kind: Pod
metadata: { name: web-with-logs }
spec:
    containers:
        - name: web
            image: nginx:1.27-alpine
            volumeMounts:
                - { name: logs, mountPath: /var/log/nginx }
        - name: log-shipper
            image: fluent/fluent-bit:3.0
            volumeMounts:
                - { name: logs, mountPath: /logs, readOnly: true }
    volumes:
        - name: logs
            emptyDir: {}

# Containers in a Pod SHARE: network (localhost), IPC, and any mounted volumes.

# 3) Resources — requests + limits
spec:
    containers:
        - name: web
            image: nginx
            resources:
                requests:                        # scheduler reserves this
                    cpu:    100m                  # 0.1 CPU
                    memory: 128Mi
                limits:                            # enforced cap; OOMKill or throttle past this
                    cpu:    500m
                    memory: 256Mi

# Memory limit exceeded → OOMKilled.  CPU limit exceeded → throttled.
# Always set requests; consider setting limits.

# 4) Probes — liveness, readiness, startup
spec:
    containers:
        - name: web
            image: nginx
            startupProbe:
                httpGet: { path: /healthz, port: 80 }
                failureThreshold: 30
                periodSeconds: 5
            readinessProbe:
                httpGet: { path: /ready, port: 80 }
                periodSeconds: 5
                failureThreshold: 3
            livenessProbe:
                httpGet: { path: /live, port: 80 }
                periodSeconds: 10
                failureThreshold: 3

# startupProbe   — gates other probes until startup completes (slow boots)
# readinessProbe — controls whether Service traffic is routed
# livenessProbe  — restarts the container if it fails

# 5) Environment variables
spec:
    containers:
        - env:
                - { name: NODE_ENV, value: production }
                - name: DATABASE_URL
                    valueFrom:
                        secretKeyRef: { name: app-secrets, key: DATABASE_URL }
                - name: LOG_LEVEL
                    valueFrom:
                        configMapKeyRef: { name: app-config, key: LOG_LEVEL }
                - name: POD_IP
                    valueFrom: { fieldRef: { fieldPath: status.podIP } }
            envFrom:
                - configMapRef: { name: app-config }
                - secretRef:    { name: app-secrets }

# 6) Volumes — emptyDir, configMap, secret, hostPath, persistentVolumeClaim
spec:
    containers:
        - volumeMounts:
                - { name: cache,    mountPath: /cache }
                - { name: config,   mountPath: /etc/app, readOnly: true }
                - { name: secret,   mountPath: /etc/keys, readOnly: true }
                - { name: persistent, mountPath: /data }
    volumes:
        - name: cache
            emptyDir: { sizeLimit: 1Gi }
        - name: config
            configMap: { name: app-config, defaultMode: 0444 }
        - name: secret
            secret: { secretName: app-secrets, defaultMode: 0400 }
        - name: persistent
            persistentVolumeClaim: { claimName: app-data }

# 7) Security context — least-privilege containers
spec:
    securityContext:
        runAsUser:  1000
        runAsGroup: 1000
        fsGroup:    1000
        runAsNonRoot: true
        seccompProfile: { type: RuntimeDefault }
    containers:
        - name: web
            image: nginx
            securityContext:
                allowPrivilegeEscalation: false
                readOnlyRootFilesystem: true
                capabilities:
                    drop: ['ALL']
                    add:  ['NET_BIND_SERVICE']
            volumeMounts:
                - { name: tmp, mountPath: /tmp }
                - { name: cache, mountPath: /var/cache/nginx }
                - { name: run, mountPath: /var/run }
    volumes:
        - { name: tmp,   emptyDir: {} }
        - { name: cache, emptyDir: {} }
        - { name: run,   emptyDir: {} }

# 8) Init containers — run BEFORE app containers, must complete successfully
spec:
    initContainers:
        - name: migrate
            image: my-app:1.2
            command: ['npm', 'run', 'migrate']
    containers:
        - { name: app, image: my-app:1.2 }

# 9) Scheduling — node selection
spec:
    nodeSelector:
        disktype: ssd
    affinity:
        podAntiAffinity:
            requiredDuringSchedulingIgnoredDuringExecution:
                - labelSelector: { matchLabels: { app: web } }
                    topologyKey: kubernetes.io/hostname
    tolerations:
        - key: 'dedicated'
            operator: 'Equal'
            value:    'workload'
            effect:   'NoSchedule'
    priorityClassName: high-priority

# 10) Lifecycle hooks — graceful shutdown
spec:
    containers:
        - lifecycle:
                preStop:
                    exec:
                        command: ['sh', '-c', 'sleep 5 && nginx -s quit']
    terminationGracePeriodSeconds: 30

# Pod entering Termination: preStop runs → SIGTERM → grace period → SIGKILL if still alive.

# 11) Ephemeral debug — sidecar at runtime
kubectl debug -it my-pod --image=busybox:1.36 --target=web
# Attaches a temporary debug container sharing the same namespaces. No edit to spec.

# 12) Pod status — what to check when things fail
kubectl describe pod my-pod
kubectl get events --sort-by=.lastTimestamp
kubectl logs my-pod -c web --previous
kubectl exec -it my-pod -c web -- sh

# Conditions to watch:
#   PodScheduled       — does it have a node?
#   ContainersReady    — all containers passing readiness?
#   Initialized        — init containers complete?
#   Ready              — endpoint visible to Services?

# 13) Common bugs
# • requests too high → Pending: 0/N nodes available; insufficient cpu/memory
# • Missing resources.requests → noisy-neighbour evictions under pressure
# • Liveness probe too aggressive → restart loop on slow boots
# • Readiness probe missing → Service routes traffic before app is ready
# • Mount path conflicts (two volumes at /data) → silent override
# • configMap mounted as defaultMode 0644 but expects 0400 — perms wrong, secret hint
# • root user (runAsUser: 0) — fails Pod Security Admission
# • Containers can't write to /tmp because readOnlyRootFilesystem: true → mount emptyDir at /tmp
# • Image pull errors — check imagePullSecrets, registry auth, image tag exists
# • Mounted Secret in env var loaded once — restart Pod when secret rotates

Why it matters

A Pod is one or more containers sharing network and volumes. Always set resources.requests, configure readinessProbe + livenessProbe + startupProbe distinctly, run non-root with a tight securityContext, and use initContainers for ordered startup tasks. Production workloads come from Deployments/StatefulSets/Jobs, but the Pod spec inside them is what matters.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
# Key fields: resources (req/limits), readinessProbe, livenessProbe,
# env, volumeMounts, securityContext.
Try it Yourself »

Discussion

Loading…