Files
MajorWiki/02-selfhosting/docker/docker-healthchecks.md
MajorLinux 6592eb4fea wiki: audit fixes — broken links, wikilinks, frontmatter, stale content (66 files)
- Fixed 4 broken markdown links (bad relative paths in See Also sections)
- Corrected n8n port binding to 127.0.0.1:5678 (matches actual deployment)
- Updated SnapRAID article with actual majorhome paths (/majorRAID, disk1-3)
- Converted 67 Obsidian wikilinks to relative markdown links or plain text
- Added YAML frontmatter to 35 articles missing it entirely
- Completed frontmatter on 8 articles with missing fields

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 11:16:29 -04:00

158 lines
4.0 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](debugging-broken-docker-containers.md)
- [netdata-docker-health-alarm-tuning](../monitoring/netdata-docker-health-alarm-tuning.md)