How to Monitor Docker Container Health and Auto-Restart on Failure
Your container is running but not actually working. It's accepting connections but returning 500s. Or it started but hasn't finished initializing.
Docker's built-in health checks handle all of this.
The Basic Health Check
FROM node:20-alpine
WORKDIR /app
COPY . .
RUN npm ci
# Health check: runs every 30s, fails after 3 attempts
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 CMD curl -f http://localhost:3000/health || exit 1
CMD ["node", "server.js"]
Or in docker-compose.yml:
services:
app:
image: your-app
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s # Grace period on startup
Check Container Health Status
# See health status
docker ps
# Detailed health info
docker inspect --format='{{json .State.Health}}' <container> | python3 -m json.tool
# Watch health checks in real time
watch -n 5 'docker inspect --format="{{.State.Health.Status}}" <container>'
Possible statuses: starting, healthy, unhealthy
The /health Endpoint (Node.js)
// Simple health endpoint
app.get('/health', (req, res) => {
res.status(200).json({
status: 'ok',
uptime: process.uptime(),
timestamp: new Date().toISOString()
});
});
// With dependency checks
app.get('/health', async (req, res) => {
const checks = {};
try {
await db.query('SELECT 1');
checks.database = 'ok';
} catch {
checks.database = 'failed';
}
try {
await redis.ping();
checks.redis = 'ok';
} catch {
checks.redis = 'failed';
}
const allOk = Object.values(checks).every(v => v === 'ok');
res.status(allOk ? 200 : 503).json({ status: allOk ? 'ok' : 'degraded', checks });
});
Auto-Restart on Unhealthy
services:
app:
image: your-app
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
With restart: unless-stopped, Docker automatically restarts an unhealthy container.
Alert on Unhealthy Containers
#!/bin/bash
# health-monitor.sh — run via cron every minute
for container in $(docker ps --format '{{.Names}}'); do
STATUS=$(docker inspect --format='{{.State.Health.Status}}' "$container" 2>/dev/null)
if [ "$STATUS" = "unhealthy" ]; then
echo "UNHEALTHY: $container at $(date)" | mail -s "Container Unhealthy: $container" you@email.com
# Optionally restart it
# docker restart "$container"
fi
done
chmod +x /usr/local/bin/health-monitor.sh
# Add to cron
* * * * * /usr/local/bin/health-monitor.sh
I built ARIA to solve exactly this.
Try it free at step2dev.com — no credit card needed.
Top comments (0)