Features Pricing Guides Alternatives Blog Docs My account Français Buy a license GitHub
Guides / Docker Swarm monitoring

Docker Swarm Monitoring: Services, Tasks and Nodes

Swarm replaces containers with services, tasks and nodes — and most Docker monitoring tools never learned the difference. What to watch, why swarmprom stopped being the answer, and how to monitor a Swarm cluster from one container.

· 6 min read

Docker Swarm monitoring breaks most Docker monitoring tools, quietly. They connect, they list containers, everything looks fine — and they never mention that a service has been running two replicas out of five for the past four hours.

The reason is that Swarm changes the unit of work. A tool that only understands containers is reading the shadow of the thing it should be watching.

Services, tasks and nodes

Three objects replace the single container abstraction, and confusing them is the source of most Swarm monitoring gaps.

A service is a declaration: this image, this many replicas, these constraints, this update policy. It is the thing you deploy.

A task is one scheduled instance of that service, bound to exactly one container on exactly one node. Tasks are immutable — when one fails, Swarm does not restart it. It schedules a new task and leaves the old one in a terminal state.

A node is a machine in the cluster, either a manager participating in the Raft quorum or a worker executing tasks.

The consequence is specific and easy to miss. A container-level tool sees three running containers for a service and reports three healthy containers. It cannot tell you that you asked for five. The gap between desired and running is a Swarm-only concept, and it is the single most useful number in a Swarm cluster.

The second consequence: because failed tasks are replaced rather than restarted, a container-level restart counter stays at zero while a service churns. Twenty rescheduled tasks in an hour looks, to a container-aware tool, like a perfectly stable container that happens to be young.

What to watch

Desired versus running replicas, per service. The headline metric. Alert when they diverge for longer than your rollout window.

Manager quorum. Swarm managers use Raft; losing quorum makes the cluster unschedulable while existing tasks keep running. This produces the worst kind of outage — everything appears fine until you try to deploy. Track the manager count, the reachability of each one, and which node is leader.

Node availability and drain state. A node set to drain for maintenance and never set back to active is a permanent capacity loss nobody notices until the next failure has nowhere to go.

Task exit codes and reschedule rate. Not just the count of running tasks but the churn: a service holding its replica count by constantly rescheduling is failing, slowly.

Rollout state. During docker service update, whether the update is progressing, paused or rolled back. A rollout stuck at “paused” after a failed health check will sit there indefinitely.

Per-node resources. CPU, memory and disk per machine, because the scheduler places tasks based on constraints and reservations, not on how loaded a node actually is.

And everything from plain Docker. Endpoint reachability, TLS expiry, cron completion and image drift do not go away because you added an orchestrator. The general Docker monitoring guide covers those six signals.

Why docker service ps is not monitoring

The built-in commands are good diagnostics and not a monitoring system:

docker service ls                    # desired vs running, right now
docker service ps web --no-trunc     # tasks and their errors, right now
docker node ls                       # nodes and manager status, right now
docker events --filter scope=swarm   # a live stream, gone when you close it

Each answers “what is true at this instant, on a machine with a manager connection”. None keeps history, evaluates a threshold, or tells anyone. docker events is the closest to a monitoring primitive and it is an ephemeral stream — nothing consumes it unless you build the consumer.

The swarmprom problem

For years the standard answer to Swarm monitoring was swarmprom: a curated stack of Prometheus, Grafana, cAdvisor, node-exporter, Alertmanager and Docker Swarm dashboards, deployable as one stack file.

It was genuinely good. It is also archived on GitHub, with its last commit in July 2020.

You can still deploy it, and people do. But you are running a five-year-old bundle of pinned images, maintaining the dashboards yourself, and carrying whatever CVEs have accumulated in that pinned set. What it mostly demonstrates today is that assembling six components to monitor Swarm was enough work that people wanted it pre-packaged — and enough work that when the packager stopped, no equivalent replaced it.

If you want the Prometheus model on Swarm in 2026, you are assembling it from current upstream images and writing the Swarm service-discovery configuration yourself. That is a legitimate choice at scale. It is a lot of machinery for a three-node cluster.

Monitoring a Swarm cluster from one container

Maintenant reads the Docker API from a manager node and understands the Swarm object model directly: cluster info, nodes with their roles and availability, services with desired and running replica counts, and the tasks behind each service with their exit codes.

Deploy it as a stack, constrained to a manager:

version: "3.8"

services:
  maintenant:
    image: ghcr.io/kolapsis/maintenant:latest
    ports:
      - "8080:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - maintenant-data:/data
    deploy:
      replicas: 1
      placement:
        constraints:
          - node.role == manager

volumes:
  maintenant-data:
docker stack deploy -c maintenant-stack.yml monitoring

One detail worth knowing, because it bites every socket-reading tool on Swarm: docker stack deploy silently ignores group_add. A container that works under Compose because you granted it the docker group will fail on Swarm with a permission error on the socket, and the stack file gives no indication why. Maintenant resolves the mounted socket’s group in its entrypoint instead, so the mount above is sufficient; if you use a socket proxy or a non-standard socket path, pin the group explicitly with DOCKER_GID (stat -c '%g' /var/run/docker.sock).

For per-node CPU, memory and disk across the cluster, deploy the same binary in agent mode on the other nodes — it detects the local runtime, streams state back to the manager instance, and each monitored entity stays attributed to its origin host.

The same instance also covers the non-Swarm signals from the same dashboard: HTTP and TCP probes against the services your cluster publishes, TLS expiry for the domains you terminate, heartbeat monitoring for scheduled jobs, and image update detection across the services you run.

Ready to switch to Maintenant ?

One container, zero config. Full monitoring in 30 seconds.