← Knowledge hub
Stacksby Uptime Room· September 24, 2026· 6 min read

Docker Monitoring Tools: Sorted by What They Read

Docker monitoring tools split by data source: engine state, cgroup counters, the log driver, and the one check that runs outside the host.

Most comparisons of docker monitoring tools rank vendors and skip the part that decides the answer: which data source the tool is reading. Three products that read the same cgroup counters will show you the same numbers in different colours. One that reads something else entirely will disagree with all of them, and it is usually the one that was right.

Four questions docker monitoring tools answer

There are only four questions worth asking about a container, and each one has a different source behind it. Is it running. Is it starved of CPU or memory. What did it write to stdout. Can anything outside the host still reach the service it publishes. Pick the tool by the question, not by the feature list.

SourceRead byAnswers
Docker Engine state and eventsdocker ps, Portainer, ctopRunning, exited, restart count, health state
cgroup countersdocker stats, cAdvisor, NetdataCPU, memory, network and block IO per container
The log driverdocker logs, Loki, a hosted agentWhat the process actually said before it died
The published port, from outsideAn external checkWhether a user can reach the service at all

The first three all run on the host. If the host is unreachable, so are they, which is why the fourth row exists.

Is it running, and how many times has it restarted?

Start with state, because it is free and it catches the dumbest failures. docker ps prints a status string per container, and when a HEALTHCHECK is defined the string carries the health state too, as in Up 4 minutes (healthy).

The number that matters more is the restart count, and no dashboard shows it by default.

docker inspect -f '{{.Name}} {{.RestartCount}} {{.State.Status}}' $(docker ps -q)

A container with restart: always and a crash every forty seconds reports Up 12 seconds every time you look. The process is dying constantly and the state view looks fine. We tested this against a deliberately crash-looping Node service and the restart count was the only local signal that moved.

Writing the health probe itself is a separate job with its own gotchas, covered in the Docker HEALTHCHECK reference. Treat the resulting state as an input here, not as the monitoring.

Is it being starved?

Resource numbers come from the kernel's cgroup accounting, and every tool in this category is a different front end over the same files. docker stats streams them directly, and the Docker CLI reference documents what each column means. ctop puts a terminal UI on top. cAdvisor exports them as Prometheus metrics so you get history and alert rules.

One detail decides whether your memory alerts are useful. container_memory_usage_bytes includes reclaimable page cache, so a healthy container that has read a lot of files looks close to its limit. Alert on container_memory_working_set_bytes instead, which is much closer to what gets a container killed.

CPU is the opposite trap. A container pinned at 100 percent of one core is fine if that is its quota. What you want is throttling: if container_cpu_cfs_throttled_seconds_total is climbing, the quota is too tight and requests are queueing behind it.

What did it say?

The log driver is configured per container or per daemon, and the choice has consequences beyond where the text lands. The default json-file driver writes to disk with no limit until you set one, which is the single most common way a Docker host fills its root volume.

services:
  api:
    image: example/api:1.4
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

Set that on day one. The logging driver documentation lists the alternatives, and there is a catch worth knowing. Switching to syslog or gelf can stop docker logs returning anything at all, unless dual logging is enabled, so the command your team reaches for first goes quiet.

Containers that run a job and exit are a different shape again. They produce no metrics to scrape and no port to check, so the only reliable signal is the job reporting its own completion. That pattern is heartbeat monitoring for scheduled jobs.

Can anyone outside actually reach it?

This is the row every listicle leaves out. All three host-side sources agree the container is healthy when the container is healthy. None of them notice that the published port is bound to the wrong interface, that a firewall rule changed, or that the host itself dropped off the network.

An external check answers that by connecting the way a user does. Point an HTTP monitor at the published endpoint. Require more than one region to agree before the state changes, so a container restart during a deploy pages nobody.

{
  "name": "api container",
  "type": "http",
  "target": "https://api.example.com/healthz",
  "intervalSec": 60,
  "regions": ["london", "los-angeles"],
  "alertAfterCycles": 2
}

There are six probe regions available as of September 2026, and the addresses each one connects from are published for firewall allowlists. You will find them on the probe IPs page, and the monitor fields above are documented in the API reference.

The trade runs both ways, and it is worth stating plainly. An outside-in check has no access to cgroup counters, so it cannot tell you that memory is climbing. That needs a collector on the host. Equally, a collector on the host cannot tell you the host is unreachable.

Which combination should you run?

For a single host or a small Compose stack, we prefer the cheapest pair that covers both sides. Run cAdvisor scraped by Prometheus for the resource picture, then one external check per published service. That is two moving parts and no vendor bill.

Once there are several hosts, the aggregation problem outgrows a single Prometheus and the hosted options start earning their cost. The decision at that point is about retention and correlation, not about containers, and it is the same decision described in infrastructure monitoring.

Portainer and Netdata are worth a look if nobody on the team wants to run a metrics stack. Both give you live per-container numbers behind a web UI within minutes. Neither replaces the external check, because both of them live on the machine you are trying to verify.

Common mistakes

Trusting docker ps as an uptime signal. A restart loop shows as Up. Alert on restart count and on an external check, never on state alone.

Alerting on memory usage rather than working set. Page cache makes healthy containers look full, so the threshold gets widened until it never fires.

Leaving the json-file driver unbounded. Logs grow until the disk is full, then everything on the host fails at once and the cause looks unrelated.

Monitoring the container instead of the service. A container is an implementation detail. Users care whether the endpoint answers, which is why the outside check is not optional.

Choosing between docker monitoring tools gets much easier once you sort them by what they read rather than by what they charge.

Pick one source for container state, one for resource counters, and one that checks the published endpoint from somewhere other than the host. The outside-in half costs nothing to try. A free account allows ten checks as of September 2026, enough for every published port on a single host. Current limits are listed on the pricing page.

FAQ

How can I monitor Docker containers?

Combine three sources. Read engine state for running, exited and restart count. Read cgroup counters through docker stats or cAdvisor for CPU, memory and IO. Set a bounded log driver so you still have output after a crash. Then add one check from outside the host against the published port, because the first three all stop reporting if the host goes away.

What are the best container monitoring tools?

There is no single best one, because they read different things. ctop and docker stats give live cgroup numbers with no history. cAdvisor with Prometheus and Grafana adds history and alert rules. Portainer and Netdata give a web UI in minutes. An external HTTP or TCP check is the only one that tells you the service is reachable from outside.

Does a Docker HEALTHCHECK replace monitoring?

No. A HEALTHCHECK runs inside the container and tells the daemon whether to mark it healthy or restart it. Nothing sends you an alert, and the result is unreadable if the host is down or the port is bound wrong. Treat the health state as one input to a monitoring system rather than as the system itself.

Why does my container show as Up when it keeps crashing?

A restart policy of always or unless-stopped brings the process straight back, so the status string resets to Up a few seconds after each crash. Check the restart count with docker inspect instead. A count that climbs between two reads means a crash loop, even though every snapshot of docker ps looks healthy.

How do I stop Docker logs filling the disk?

The default json-file driver writes without a size limit. Set max-size and max-file options on the logging block per service, or set the same defaults on the daemon so new containers inherit them. Ten megabytes across three files is a reasonable starting point for a service that logs normally.

Related reading