How to configure Prometheus inside Dockerswarm to scrape necessary metrics for Applications Manager?

How to configure Prometheus inside Dockerswarm to scrape necessary metrics for Applications Manager?


STEP 1 — Ensure Overlay Network Exists
The monitoring overlay network must exist before deploying any services.
Check if it already exists:
                       docker network ls
Expected output:
      NETWORK ID     NAME         DRIVER    SCOPE
      m91dq75djyhc   monitoring   overlay   swarm

If the `monitoring` network does not exist, create it:
        docker network create --driver overlay --attachable monitoring 
Note: The `--attachable` flag allows standalone containers to join the network if needed.

STEP 2 — Deploy Node Exporter (Global)
Node Exporter collects host-level metrics (CPU, memory, disk, network) from every Swarm node.
Deploy it in global mode so it runs on all nodes automatically.
Execute the below on the Manager Node:

docker service create \
  --name node-exporter \
  --mode global \
  --hostname "{{.Node.Hostname}}" \
  --network monitoring \
  --mount type=bind,source=/proc,target=/host/proc,readonly \
  --mount type=bind,source=/sys,target=/host/sys,readonly \
  --mount type=bind,source=/,target=/rootfs,readonly \
  prom/node-exporter \
  --path.procfs=/host/proc \
  --path.sysfs=/host/sys \
  --path.rootfs=/rootfs

Verify:
         docker service ls
Should show:
        node-exporter   global   n/n

STEP 3 — Deploy cAdvisor (Global)
cAdvisor collects container-level metrics (CPU, memory, network per container).
Deploy it in global mode so it runs on all nodes automatically.
Execute the below on the Manager Node:
docker service create \
  --name cadvisor \
  --mode global \
  --network monitoring \
  --mount type=bind,source=/,target=/rootfs,readonly \
  --mount type=bind,source=/var/run,target=/var/run \
  --mount type=bind,source=/sys,target=/sys,readonly \
  --mount type=bind,source=/var/lib/docker/,target=/var/lib/docker,readonly \
  --constraint 'node.platform.os == linux' \
  --cap-add SYS_ADMIN \
  gcr.io/cadvisor/cadvisor:latest

Verify:
       docker service ls

Should show:
     cadvisor   global   2/2

STEP 4 — Deploy Docker Swarm Exporter

Docker Swarm Exporter collects Swarm-level metrics (services, tasks, nodes, replicas).
It must run on a Manager Node as it needs access to the Docker socket.
Execute the below on the Manager Node:
docker service create \
  --name docker-swarm-exporter \
  --network monitoring \
  --mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock,readonly \
  --constraint 'node.role == manager' \
  --publish 9000:9000 \
  nicholasjackson/swarm-exporter:latest

Verify:
     docker service ls
Should show:
    docker-swarm-exporter   replicated   1/1
Verify metrics endpoint:
> Note: Look for metrics like `swarm_services_running`, `swarm_nodes_total` in the output.

STEP 5 — Enable Docker Engine Metrics (On ALL Nodes)

Perform the following steps on every node (Manager + Workers):
Edit Docker daemon config:
  sudo vi /etc/docker/daemon.json

Add the following:
{
  "metrics-addr": "127.0.0.1:9323",
  "experimental": true
}

> Note: Use `"metrics-addr": "0.0.0.0:9323"` only if you need to access metrics
> from a remote host. For security, restrict to internal IP in production.

Restart Docker:
sudo systemctl restart docker
Verify the metrics endpoint:
> Verify: Look for `engine_daemon_engine_info` in the output to confirm it is working.

 STEP 6 — Create Prometheus Configuration

On the Manager Node:

mkdir -p ~/prometheus
cd ~/prometheus
vi prometheus.yml

add the below configuration:
global:
  scrape_interval: 15s

scrape_configs:

  - job_name: 'dockerswarm'
    dns_sd_configs:
      - names:
          - 'tasks.cadvisor'
        type: 'A'
        port: 8080
      - names:
          - 'tasks.node-exporter'
        type: 'A'
        port: 9100
      - names:
          - 'tasks.docker-swarm-exporter'
        type: 'A'
        port: 9000
    static_configs:
      - targets:
          - '<manager-ip>:9323'    # Replace with actual Manager Node IP
          - '<worker-ip>:9323'     # Replace with actual Worker Node IP
        labels:
          exporter: docker-engine

    relabel_configs:
      # Tag each target by exporter type
      - source_labels: [__address__]
        regex: '.*:8080'
        target_label: exporter
        replacement: cadvisor

      - source_labels: [__address__]
        regex: '.*:9100'
        target_label: exporter
        replacement: node-exporter

      - source_labels: [__address__]
        regex: '.*:9000'
        target_label: exporter
        replacement: docker-swarm-exporter

      # Force instance = "crc" for ALL targets
      - source_labels: [__address__]
        regex: '.+'
        target_label: instance
        replacement: 'crc'

    metric_relabel_configs:
      # Ensure instance stays "crc" after scrape
      - target_label: instance
        replacement: 'crc'

> Note: Replace `<manager-ip>` and `<worker-ip>` with your actual node IPs.

STEP 7 — Deploy Prometheus

Execute the below on the Manager Node:
docker service create \
  --name prometheus \
  --network monitoring \
  --publish 9090:9090 \
  --constraint 'node.role == manager' \
  --mount type=bind,source=$HOME/prometheus/prometheus.yml,target=/etc/prometheus/prometheus.yml \
  prom/prometheus \
  --config.file=/etc/prometheus/prometheus.yml \
  --web.enable-lifecycle

Verify:
docker service ls
Should show:
Example Numbers:
prometheus              replicated   1/1
cadvisor                global       n/n
node-exporter           global       n/n
docker-swarm-exporter   replicated   1/1
STEP 8 — Verify in Browser
Open: `http://<manager-ip>:9090`
Go to: Status → Targets

You should see all targets as UP:

cadvisor                         n/n   UP
node-exporter              n/n   UP
docker-swarm-exporter   n/n   UP
docker-engine           n/n   UP

All targets will carry the unified labels:

instance="crc"   job="dockerswarm"   exporter="<exporter-type>"



Troubleshooting

| Issue                                           | Command                                                                                   | What to Look For |

| Service not starting                   | `docker service logs prometheus`                                            | `error loading config` |
| Target showing DOWN             | `http://<ip>:9090/targets`                                                        | Error message next to target |
| DNS not resolving tasks            | `docker exec -it <prometheus_id> nslookup tasks.cadvisor` | Should return IP |
| Wrong instance label                 | `http://<ip>:9090/targets`                                                         | Check labels column |
| Docker Engine metrics missing | `curl http://localhost:9323/metrics`                                         | Should return metric lines |
| Swarm Exporter unreachable    | `curl http://localhost:9000/metrics`                                         | Should return swarm metrics |

----------------------------------------------------------------------------------------------------
How to Configure it in External Prometheus: 
 Step 1 – Enable Docker Engine Metrics
Docker does NOT expose metrics by default.
Edit daemon.json on every swarm node:
  1. sudo vi /etc/docker/daemon.json
Add:
  1. {
  2.   "metrics-addr": "0.0.0.0:9323",
  3.   "experimental": true
  4. }

Test:
http://<node-ip>:9323/metrics

Step 2 – Deploy Node Exporter (for Node Metrics)
Deploy globally in swarm:
  1. docker service create \
  2.   --name node-exporter \
  3.   --mode global \
  4.   --mount type=bind,source=/proc,target=/host/proc \
  5.   --mount type=bind,source=/sys,target=/host/sys \
  6.   --mount type=bind,source=/,target=/rootfs \
  7.   --publish 9100:9100 \
  8.   prom/node-exporter:latest \
  9.   --path.procfs=/host/proc \
  10.   --path.sysfs=/host/sys \
  11.   --path.rootfs=/rootfs
Now accessible at:
  1. http://<node-ip>:9100/metrics

Step 3 – Deploy cAdvisor (Container Metrics)
  1. docker service create \
  2.   --name cadvisor \
  3.   --mode global \
  4.   --mount type=bind,source=/,target=/rootfs,readonly \
  5.   --mount type=bind,source=/var/run,target=/var/run \
  6.   --mount type=bind,source=/sys,target=/sys,readonly \
  7.   --mount type=bind,source=/var/lib/docker,target=/var/lib/docker,readonly \
  8.   --publish 8080:8080 \
  9.   gcr.io/cadvisor/cadvisor:latest
Metrics:
  1. http://<node-ip>:8080/metrics
Step 4 – Configure External Prometheus
Now in your external Prometheus server, edit:
  1. vi prometheus.yml

Example config:

  1. global:
  2.   scrape_interval: 15s

  3. scrape_configs:

  4.   - job_name: 'docker-engine'
  5.     static_configs:
  6.       - targets:
  7.           - 'NODE1_IP:9323'
  8.           - 'NODE2_IP:9323'

  9.   - job_name: 'node-exporter'
  10.     static_configs:
  11.       - targets:
  12.           - 'NODE1_IP:9100'
  13.           - 'NODE2_IP:9100'

  14.   - job_name: 'cadvisor'
  15.     static_configs:
  16.       - targets:
  17.           - 'NODE1_IP:8080'
  18.           - 'NODE2_IP:8080'

Restart Prometheus. and check in port 9090.

Check:

  • Status → Targets
  • All should be UP ✅
Step 5 – Useful PromQL Queries (Check all these queries in PromQL)

  1. engine_daemon_engine_info
  2. container_last_seen
  3. engine_swarm_service_tasks_running
  4. 100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
  5. container_memory_usage_bytes