Skip to content
← All posts

Health Checks and Kubernetes Probes for Laravel

Liveness, readiness, and startup probes are how Kubernetes decides if your pod is healthy. Laravel Health gives you a clean API for all three, plus Prometheus metrics.

· 6 min read · Sylvester Damgaard
Health Checks and Kubernetes Probes for Laravel

Kubernetes probes are deceptively simple. You define an HTTP endpoint, Kubernetes hits it periodically, and if it returns a non-200 status code enough times, the container gets restarted (liveness) or removed from the service (readiness). Most teams start with a route that returns 200 OK and call it done.

The problem is that a process being alive isn't the same as being healthy. PHP-FPM can be running while the database connection pool is exhausted. Redis can be reachable but out of memory. The queue can be processing but the failure rate is 80%. A simple 200 OK tells Kubernetes nothing useful about the actual state of your application.

Three probe types, three purposes

Liveness probes answer: "Is the process stuck?" If the liveness probe fails, Kubernetes kills and restarts the container. This should be fast, cheap, and only check if the PHP process is responsive. Do not check external dependencies here. If your database is down, restarting your PHP container won't fix it.

Readiness probes answer: "Can this pod handle requests?" If the readiness probe fails, the pod is removed from the Service endpoints but not restarted. This is where you check dependencies: database connectivity, Redis availability, cache warmth.

Startup probes answer: "Has the application finished initializing?" This gives slow-starting applications time to warm up caches, run migrations, or build indexes.

Laravel Health implementation

Laravel Health provides three endpoints out of the box:

  • GET /health/liveness - Am I alive?

  • GET /health/readiness - Can I handle requests?

  • GET /health/startup - Am I done initializing?

Each endpoint runs a configurable set of checks and returns a structured JSON response with individual check results and an overall status.

Built-in checks

The package ships with checks for the most common dependencies:

  • Database - Runs a simple SELECT 1 query with configurable timeout

  • Redis - Pings the Redis connection, tests both default and named connections

  • Queue - Checks if the queue connection is reachable and workers are processing

  • Disk - Verifies that configured storage disks are writable with free space above a threshold

  • Memory - Uses System Metrics for container-aware memory checks against cgroup limits

  • CPU - Container-aware CPU utilization via System Metrics

Custom checks

Adding a custom check is a single class implementing HealthCheck. Register it in your config and assign it to the appropriate probe type. A search index check belongs on the readiness probe (not liveness), because a missing search index means the app can't serve search results, but the process itself isn't stuck.

Prometheus integration

Every check result is also exposed as a Prometheus gauge at /health/metrics. This gives you historical visibility into check results over time. If the database check starts taking 500ms instead of 3ms, your Prometheus alerts fire before the probe actually fails.

Deployment

A typical Kubernetes deployment uses the startup probe with a generous failure threshold (30 attempts at 2-second intervals = 60 seconds to initialize), the liveness probe at 10-second intervals for basic process health, and the readiness probe at 5-second intervals for dependency checks.

Install with composer require cboxdk/laravel-health and the endpoints are available immediately with sensible defaults. Customize checks per probe type in the published config file.