Skip to main content

Probe antipatterns

4 min read

Pod lifecycle overview · Checklist and references

Probe Antipatterns and Pitfalls​

Antipattern 1: Including External Dependencies in a Liveness Probe​

Problem:

livenessProbe:
httpGet:
path: /health # Includes database and Redis connection checks
port: 8080

Consequences:

  • A database failure causes all Pods to restart simultaneously → Cascading Failure
  • Even transient network delays cause Pods to restart.

Correct configuration:

# Liveness: Application health only
livenessProbe:
httpGet:
path: /healthz # Check internal health only
port: 8080

# Readiness: Include external dependencies
readinessProbe:
httpGet:
path: /ready # Check the database, Redis, and other dependencies
port: 8080

Antipattern 2: A High initialDelaySeconds Without a Startup Probe​

Problem:

livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 120 # Wait 2 minutes
periodSeconds: 10

Consequences:

  • Even if the application starts in 30 seconds, it has no health checks for another 90 seconds.
  • If the process exits outright (a crash), the kubelet restarts the container regardless of the liveness initialDelay; only a process that hangs without exiting goes undetected for up to 2 minutes until the initialDelay elapses.

Correct configuration:

# Protect startup with a Startup Probe
startupProbe:
httpGet:
path: /healthz
port: 8080
failureThreshold: 12 # Wait up to 120 seconds
periodSeconds: 10

# Liveness activates immediately after Startup succeeds
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 0 # Start immediately after Startup succeeds
periodSeconds: 10

Antipattern 3: Sharing an Endpoint That Checks External Dependencies for Liveness and Readiness​

Problem:

livenessProbe:
httpGet:
path: /health
port: 8080

readinessProbe:
httpGet:
path: /health # Same endpoint
port: 8080

Consequences:

  • If /health checks external dependencies, Liveness failures cause unnecessary restarts.
  • Sharing an endpoint that checks only internal health is fine, but the unclear separation of responsibilities makes debugging difficult.

Correct configuration:

livenessProbe:
httpGet:
path: /healthz # Internal health only
port: 8080

readinessProbe:
httpGet:
path: /ready # Include external dependencies
port: 8080

Antipattern 4: An Overly Aggressive failureThreshold​

Problem:

livenessProbe:
httpGet:
path: /healthz
port: 8080
periodSeconds: 5
failureThreshold: 1 # Restart after just 1 failure

Consequences:

  • Transient network delays, GC pauses, and similar events cause unnecessary restarts.
  • Restart loops can occur.

Correct configuration:

livenessProbe:
httpGet:
path: /healthz
port: 8080
periodSeconds: 10
failureThreshold: 3 # Detect failure after ~30s (3 x 10s) of consecutive failures, then restart
timeoutSeconds: 5

Antipattern 5: An Excessively Long timeoutSeconds​

Problem:

livenessProbe:
httpGet:
path: /healthz
port: 8080
timeoutSeconds: 30 # Wait 30 seconds
periodSeconds: 10

Consequences:

  • A healthy probe returns quickly, but a slow or hung target can take up to 30 seconds to time out, slowing failure detection by that much.

Correct configuration:

livenessProbe:
httpGet:
path: /healthz
port: 8080
timeoutSeconds: 5 # A response is required within 5 seconds
periodSeconds: 10
failureThreshold: 3