You have deployed your stack with Docker Compose. Your containers are running. Everything seems to be working. But what happens when something breaks at 3 AM?

This checklist covers the six things worth monitoring in a Compose stack, whatever tool you use to do it.

1. Containers

The most basic level: are your containers running?

  • Container state: running, stopped, restarting, exited
  • Restart loops: a container stuck in a restart loop is often worse than one that has stopped entirely
  • Docker health checks: the native HEALTHCHECK is underused but extremely valuable
  • Exit codes: a non-zero exit code indicates a crash, not a clean shutdown

A health check in your docker-compose.yml:

services: api: image: myapp:latest healthcheck: test: ["CMD", "curl", "-f", "http://localhost:3000/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s 

Your monitoring should alert when a container transitions to unhealthy, not only when it stops.

2. Endpoints

Check that your services respond correctly to requests.

HTTP checks

Beyond "does it respond", a proper HTTP check verifies:

  • The status code (200, 201, etc.)
  • The response time (latency)
  • SSL certificate validity

As one example, Maintenant reads this from Docker labels on the service, so the check lives next to the code:

labels: maintenant.endpoint.http: "https://api.example.com/health" maintenant.endpoint.interval: "30s" maintenant.endpoint.http.expected-status: "200" 

HTTP/TCP endpoint monitoring: latency, status codes

TCP checks

For services that do not speak HTTP (databases, Redis, MQTT), a TCP check verifies that the port is open and accepting connections.

3. SSL certificates

Expired certificates are one of the most common causes of preventable downtime. With Let's Encrypt and automatic renewal, it is tempting to assume everything just works, but renewals can fail silently. Alert well ahead of expiry (for example at 30, 14, 7, 3 and 1 day) so a failed renewal is noticed while there is still time to fix it.

4. Cron jobs

Scheduled tasks are the most overlooked services. Is your nightly backup actually running? Did your cleanup job finish successfully?

Use the heartbeat pattern: the job sends a ping to a URL after each execution, and you get alerted if the ping does not arrive within the expected window. Report the exit code and send the ping whether the job succeeded or not:

# crontab: ';' not '&&', so the ping is sent even when backup.sh fails 0 3 * * * /usr/local/bin/backup.sh; curl -fsS -o /dev/null https://monitor.example.com/ping/{uuid}/$? 

5. System resources

  • Disk space: a full disk can crash your database
  • Memory usage: per container and per host
  • CPU: to detect abnormal spikes
  • Network I/O: to identify congestion

Set thresholds with some margin (for example warn at 80% disk, not at 100%), and keep history so you can tell a spike from a trend. The Docker stats API gives per-container CPU, memory, network and block I/O.

System resources: CPU, memory, disk, network per container

6. Image updates

Knowing that a security update is available for your PostgreSQL or Redis image matters. Comparing the digest of the image you run with the one in the registry tells you when a newer build exists for the tag you use.

Originally published on maintenant.dev.

Maintenant is an open-source, self-hosted monitoring tool for Docker and Kubernetes: containers, endpoints, cron heartbeats, TLS certificates and alerts, in one container that discovers your stack on its own. Install it in a minute: https://maintenant.dev

This project was funded by the French Government as part of the France 2030 plan operated by Bpifrance.

France 2030 and Cap Digital