This is the baseline I use in lab and reference environments when I want a Kubernetes workload to behave predictably. It is not a story about a production incident, and the numbers are not universal defaults. The useful part is the sequence: define what healthy means, make shutdowns graceful, limit blast radius, and test the assumptions.

Start with the failure contract.

Before writing YAML, I want four questions answered. How does Kubernetes know the process has started? When is it ready for traffic? When should it be restarted? How long does it need to stop accepting work and finish in-flight requests?

A startup probe protects a slow boot from an impatient liveness probe. A readiness probe controls traffic. A liveness probe is only for a process that cannot recover without a restart. Using the same endpoint for all three hides important differences.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: catalog-api
spec:
  replicas: 3
  selector:
    matchLabels:
      app: catalog-api
  strategy:
    rollingUpdate:
      maxUnavailable: 0
      maxSurge: 1
  template:
    metadata:
      labels:
        app: catalog-api
    spec:
      terminationGracePeriodSeconds: 30
      containers:
        - name: api
          image: ghcr.io/example/catalog-api:1.8.2
          lifecycle:
            preStop:
              exec:
                command: ["sh", "-c", "sleep 5"]
          startupProbe:
            httpGet: {path: /startup, port: 8080}
            periodSeconds: 2
            failureThreshold: 30
          readinessProbe:
            httpGet: {path: /ready, port: 8080}
            periodSeconds: 5
          livenessProbe:
            httpGet: {path: /live, port: 8080}
            periodSeconds: 10
          resources:
            requests: {cpu: 200m, memory: 256Mi}
            limits: {memory: 512Mi}

The short preStop delay gives endpoint changes time to propagate, but it is not the shutdown mechanism. The application must handle SIGTERM, stop accepting new work, and finish requests within the grace period.

Protect capacity, not just pods.

Three replicas only help when the scheduler can place them across meaningful failure domains. I add topology spread constraints across nodes, and across zones when the cluster really has multiple zones. For small clusters I usually prefer a soft constraint so one unavailable zone does not make every new pod unschedulable.

A PodDisruptionBudget protects against voluntary disruption such as a node drain. It does not create capacity, protect against a node crash, or fix an application that cannot become ready. For three replicas, minAvailable: 2 is understandable, but it still needs enough spare cluster capacity during maintenance.

CPU limits need deliberate testing because throttling can increase tail latency. Memory limits are more direct: exceeding one produces an OOM kill. I begin with measured requests, load-test the service, and alert on throttling, OOM kills, restarts, and sustained saturation before changing values.

Make rollout checks part of delivery.

kubectl apply -f k8s/
kubectl rollout status deployment/catalog-api --timeout=5m
kubectl get pods -l app=catalog-api -o wide
kubectl get events --sort-by=.lastTimestamp
kubectl top pods -l app=catalog-api

A successful apply only means the API accepted the objects. The delivery job should wait for the rollout and fail if the new replicas do not become ready. For a higher-risk change, I also watch error rate and latency during a canary or staged rollout.

Verify the design with small failure drills.

In a non-production environment, I delete one pod while sending traffic, restart a node, and deploy a version with a deliberately failing readiness check. The expected result is specific: traffic stays on ready pods, replacement capacity appears, the rollout stops safely, and the alert explains what failed.

The final baseline is intentionally unexciting: separate health signals, graceful termination, realistic resources, distributed replicas, protected disruptions, observable rollouts, and rehearsed recovery. “Boring” infrastructure is usually infrastructure whose failure modes have already been made visible.