158 lines
3.9 KiB
Markdown
158 lines
3.9 KiB
Markdown
---
|
|
title: "Docker Healthchecks"
|
|
domain: selfhosting
|
|
category: docker
|
|
tags: [docker, healthcheck, monitoring, uptime-kuma, compose]
|
|
status: published
|
|
created: 2026-03-23
|
|
updated: 2026-03-23
|
|
---
|
|
|
|
# Docker Healthchecks
|
|
|
|
A Docker healthcheck tells the daemon (and any monitoring tool) whether a container is actually working — not just running. Without one, a container shows as `Up` even if the app inside is crashed, deadlocked, or waiting on a dependency.
|
|
|
|
## Why It Matters
|
|
|
|
Tools like Uptime Kuma report containers without healthchecks as:
|
|
|
|
> Container has not reported health and is currently running. As it is running, it is considered UP. Consider adding a health check for better service visibility.
|
|
|
|
A healthcheck upgrades that to a real `(healthy)` or `(unhealthy)` status, making monitoring meaningful.
|
|
|
|
## Basic Syntax (docker-compose)
|
|
|
|
```yaml
|
|
healthcheck:
|
|
test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080/health"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 30s
|
|
```
|
|
|
|
| Field | Description |
|
|
|---|---|
|
|
| `test` | Command to run. Exit 0 = healthy, non-zero = unhealthy. |
|
|
| `interval` | How often to run the check. |
|
|
| `timeout` | How long to wait before marking as failed. |
|
|
| `retries` | Failures before marking `unhealthy`. |
|
|
| `start_period` | Grace period on startup before failures count. |
|
|
|
|
## Common Patterns
|
|
|
|
### HTTP service (wget — available in Alpine)
|
|
```yaml
|
|
healthcheck:
|
|
test: ["CMD", "wget", "-q", "--spider", "http://localhost:2368/"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 30s
|
|
```
|
|
|
|
### HTTP service (curl)
|
|
```yaml
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 30s
|
|
```
|
|
|
|
### MySQL / MariaDB
|
|
```yaml
|
|
healthcheck:
|
|
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-psecret"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 3
|
|
start_period: 20s
|
|
```
|
|
|
|
### PostgreSQL
|
|
```yaml
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
```
|
|
|
|
### Redis
|
|
```yaml
|
|
healthcheck:
|
|
test: ["CMD", "redis-cli", "ping"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 3
|
|
```
|
|
|
|
### TCP port check (no curl/wget available)
|
|
```yaml
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "nc -z localhost 8080 || exit 1"]
|
|
interval: 30s
|
|
timeout: 5s
|
|
retries: 3
|
|
```
|
|
|
|
## Using Healthchecks with `depends_on`
|
|
|
|
Healthchecks enable proper startup ordering. Instead of a fixed sleep, a dependent container waits until its dependency is actually ready:
|
|
|
|
```yaml
|
|
services:
|
|
app:
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
|
|
db:
|
|
image: mysql:8.0
|
|
healthcheck:
|
|
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 3
|
|
start_period: 20s
|
|
```
|
|
|
|
This prevents the classic race condition where the app starts before the database is ready to accept connections.
|
|
|
|
## Checking Health Status
|
|
|
|
```bash
|
|
# See health status in container list
|
|
docker ps
|
|
|
|
# Get detailed health info including last check output
|
|
docker inspect --format='{{json .State.Health}}' <container> | jq
|
|
```
|
|
|
|
## Ghost Example
|
|
|
|
Ghost (Alpine-based) uses `wget` rather than `curl`:
|
|
|
|
```yaml
|
|
healthcheck:
|
|
test: ["CMD", "wget", "-q", "--spider", "http://localhost:2368/ghost/api/v4/admin/site/"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 30s
|
|
```
|
|
|
|
## Gotchas & Notes
|
|
|
|
- **Alpine images** don't have `curl` by default — use `wget` or install curl in the image.
|
|
- **`start_period`** is critical for slow-starting apps (databases, JVM services). Failures during this window don't count toward `retries`.
|
|
- **`CMD` vs `CMD-SHELL`** — use `CMD` for direct exec (no shell needed), `CMD-SHELL` when you need pipes, `&&`, or shell builtins.
|
|
- **Uptime Kuma** will pick up Docker healthcheck status automatically when monitoring via the Docker socket — no extra config needed.
|
|
|
|
## See Also
|
|
|
|
- [[debugging-broken-docker-containers]]
|
|
- [[netdata-docker-health-alarm-tuning]]
|