Skip to content

Instantly share code, notes, and snippets.

@pavelfomin
Created June 5, 2026 19:37
Show Gist options
  • Select an option

  • Save pavelfomin/04a31c9729dd314b95d4f8ff88349cd8 to your computer and use it in GitHub Desktop.

Select an option

Save pavelfomin/04a31c9729dd314b95d4f8ff88349cd8 to your computer and use it in GitHub Desktop.
kube probes

Kubernetes Probes: Readiness, Liveness, Startup

Probe Question it answers Failure action Endpoint here
startup Has the app finished booting? Kill & restart the container (only after the budget is exhausted) /actuator/health/liveness
liveness Is the app wedged and unrecoverable? Kill & restart the container /actuator/health/liveness
readiness Can the app serve traffic right now? Remove pod from Service endpoints (no restart) /actuator/health/readiness

Key rule: only liveness and startup restart the container. Readiness never does — it only gates traffic.

The three probes

Readiness

Answers "can this pod serve requests?" When it fails, Kubernetes removes the pod from the Service's endpoints, so traffic is withheld until it passes again. It does not restart anything.

Because failing readiness is cheap (no restart), it is legitimate — often desirable — to include external dependencies here (e.g. the database), so a pod stops receiving traffic when it can't actually fulfil requests.

Liveness

Answers "is the app broken beyond recovery and in need of a restart?" When it fails failureThreshold times, Kubernetes SIGKILLs and restarts the container (you'll see exit code 137).

A restart only helps for internal faults (deadlock, broken application context). It does not fix an external dependency outage. Therefore liveness must depend only on internal app state, never on the DB or downstream services — otherwise a transient dependency blip makes every pod fail liveness at once and restart in a storm that can't fix the problem.

Startup

Answers "has the app finished starting up?" It exists to protect a slow-booting container from the liveness probe. While the startup probe is still failing, liveness and readiness are suspended; the container gets up to failureThreshold × periodSeconds to start. The first time the startup probe succeeds, Kubernetes stops running it and hands off to liveness + readiness. If it never succeeds within the budget, the container is killed.

Endpoint choice: dedicated groups vs aggregated /actuator/health

Spring Boot Actuator exposes:

  • /actuator/health — aggregated: rolls up every indicator (db, diskSpace, downstream clients, custom checks, plus liveness/readiness state). Any one indicator DOWN makes the whole endpoint DOWN.
  • /actuator/health/liveness — the liveness group; by default only livenessState (internal "is the context alive" signal). No DB.
  • /actuator/health/readiness — the readiness group; readinessState, and may include dependency checks like db.

Requires management.endpoint.health.probes.enabled=true, which Spring Boot auto-enables when it detects it's running on Kubernetes.

Use the dedicated groups for liveness and startup — not aggregated

Pointing startup at aggregated /actuator/health relocates the same anti-pattern to boot time: if the DB is slow or unavailable during startup, the aggregated endpoint never reports UP, the startup budget is exhausted, and Kubernetes kills a container whose application actually started fine. The startup probe should mirror liveness (same livenessState check, longer budget) so "startup is done" means "the app is up", and dependency availability is delegated to readiness (where failing only withholds traffic).

Probe Recommended endpoint Why
startup /actuator/health/liveness Mirrors liveness; "app booted", not "deps reachable"
liveness /actuator/health/liveness Restart only on internal fault, never on dependency blips
readiness /actuator/health/readiness Safe to include DB/deps — failing just stops traffic

Configuration

helm/templates/deployment.yaml:

startupProbe:
  httpGet:
    port: 8080
    path: /actuator/health/liveness
  failureThreshold: 12      # 12 × 5s = ~60s startup budget
  periodSeconds: 5
readinessProbe:
  httpGet:
    port: 8080
    path: /actuator/health/readiness
livenessProbe:
  httpGet:
    port: 8080
    path: /actuator/health/liveness
  initialDelaySeconds: 10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment