Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

A dependable Prometheus Compose stack needs three things wired correctly: a Prometheus service, a YAML configuration mounted at /etc/prometheus/prometheus.yml, and persistent storage mounted at /prometheus. Add exporters such as cAdvisor as additional Compose services, then scrape them by their Compose DNS names—not by localhost. The files and commands below produce a working baseline you can extend without losing time-series data on container restarts.

What the Compose stack does

Docker Compose is a tool for defining and running multi-container applications. In this setup, Compose creates a small monitoring network in which Prometheus collects metrics by scraping HTTP endpoints exposed by itself and by exporters. Prometheus provides the storage and query engine; an exporter exposes metrics about another system or service; Compose supplies repeatable startup, networking, volume, and logging behavior.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The smallest useful deployment has one service:

  • Prometheus, listening on port 9090, reading a configuration file, scraping its configured targets, and writing time-series data under /prometheus.

A fuller container-monitoring deployment adds cAdvisor, which exposes container metrics on port 8080. The official example also includes Redis on port 6379 and demonstrates Compose service dependencies. Grafana can be added as a separate visualization service, but it does not replace Prometheus or change how Prometheus performs scraping.

Recommended project layout

Keep the Compose file and Prometheus configuration together so the bind mount is unambiguous:

prometheus-compose/
├── docker-compose.yml
└── prometheus.yml

Run every Compose command from the directory containing docker-compose.yml. A relative mount such as ./prometheus.yml is resolved from that working directory.

Minimal Prometheus-only docker-compose.yml

Use this baseline when you need Prometheus itself before adding exporters:

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
services:
  prometheus:
    image: prom/prometheus
    command:
      - --config.file=/etc/prometheus/prometheus.yml
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - prometheus-data:/prometheus

volumes:
  prometheus-data:

The official container guidance uses port 9090, mounts the configuration at /etc/prometheus/prometheus.yml, and mounts persistent storage at /prometheus. The :ro suffix makes the configuration mount read-only from inside the container. The named volume is managed by Docker and survives replacement or restart of the Prometheus container.

Why the command explicitly names the configuration file

The command passes --config.file=/etc/prometheus/prometheus.yml, matching the mount target. This removes ambiguity if the image’s default path changes or if you later add more configuration files. The path on the left side of the bind mount is your host file; the path on the right is the path Prometheus reads inside the container.

Why the volume is not optional

Prometheus writes its time-series database beneath /prometheus. Without a named volume or bind mount at that path, data remains in the container’s writable layer and is lost when the container is removed or recreated. A restart that keeps the same container may appear to work, but a routine image update or docker compose up that replaces the container can erase the history.

Write prometheus.yml

Prometheus configuration is YAML. The global block supplies defaults, rule_files loads recording or alerting rules, and scrape_configs defines jobs and their targets.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
global:
  scrape_interval: 15s
  evaluation_interval: 15s

scrape_configs:
  - job_name: prometheus
    static_configs:
      - targets: ['prometheus:9090']

The 15-second values are defaults for this example. A scrape interval is a compromise: shorter intervals show changes sooner and create more samples, while longer intervals reduce collection frequency. Set a job-specific interval only when a target needs a different cadence.

Add cAdvisor as a scrape target

Extend the file with a second job:

global:
  scrape_interval: 15s
  evaluation_interval: 15s

scrape_configs:
  - job_name: prometheus
    static_configs:
      - targets: ['prometheus:9090']

  - job_name: cadvisor
    scrape_interval: 5s
    static_configs:
      - targets: ['cadvisor:8080']

This follows the official cAdvisor pattern: Prometheus is scraped every 15 seconds, while cAdvisor is scraped every 5 seconds. The target is cadvisor:8080 because cadvisor is the Compose service name and Compose supplies DNS for services on the project network.

Load recording and alerting rules

If you create rule files, declare them in the same configuration:

rule_files:
  - /etc/prometheus/rules/*.yml

You would then mount a host rules directory into that container path. Keep rule paths and mount paths consistent; a rule file that exists only on the host is invisible to Prometheus until it is mounted.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Fuller Compose stack with cAdvisor

The following is a practical extension of the official three-service pattern. It publishes Prometheus on 9090, cAdvisor on 8080, and Redis on 6379; mounts the Prometheus configuration read-only; and declares service dependencies. The cAdvisor host mounts allow it to inspect the host’s container and kernel information. Container runtimes and operating systems can impose additional requirements, so verify the cAdvisor image’s current runtime guidance before deploying it on a restricted host.

services:
  prometheus:
    image: prom/prometheus
    command:
      - --config.file=/etc/prometheus/prometheus.yml
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - prometheus-data:/prometheus
    depends_on:
      - cadvisor

  cadvisor:
    image: gcr.io/cadvisor/cadvisor
    ports:
      - "8080:8080"
    volumes:
      - /:/rootfs:ro
      - /var/run:/var/run:ro
      - /sys:/sys:ro
      - /var/lib/docker:/var/lib/docker:ro
    depends_on:
      - redis

  redis:
    image: redis
    ports:
      - "6379:6379"

volumes:
  prometheus-data:

depends_on controls startup ordering; it is not a readiness test. Prometheus may start before an exporter is ready and mark that target down temporarily. Once the endpoint responds, the next scrape can succeed.

Redis appears in the official example as an application container alongside cAdvisor. Prometheus does not automatically scrape every service: only targets listed in scrape_configs are collected. If Redis exposes metrics through a separate exporter, add that exporter as its own service and target its service DNS name.

Adding Grafana without changing Prometheus

Grafana is a consumer of Prometheus data, not a replacement for the scraper. Add it as another Compose service, publish the UI port selected by the Grafana image documentation, and configure a Prometheus data source whose server URL is http://prometheus:9090. That URL must use the Compose service name so Grafana reaches Prometheus over the internal network.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Keep the responsibilities separate:

  • Prometheus owns scraping, rule evaluation, and time-series storage.
  • Grafana queries Prometheus and renders dashboards.
  • Exporters expose metrics; they do not persist Prometheus history.

Pin a Grafana image version that you have validated rather than relying indefinitely on a moving latest tag. The Prometheus service, configuration mount, scrape jobs, and data volume remain unchanged when Grafana is added.

Start, inspect, and operate the stack

  1. Validate the two files. Confirm that docker-compose.yml and prometheus.yml are in the directory from which you will run Compose, and that the YAML indentation is valid.
  2. Start in the background. Run docker compose up -d. The current command uses the Compose v2 plugin; older documentation may show docker-compose up.
  3. Check service state. Run docker compose ps. Prometheus should have a published 9090 port; the fuller example also publishes 8080 and 6379.
  4. Read startup output. Run docker compose logs prometheus or docker compose logs for all services. Configuration parse errors and permission problems normally appear here.
  5. Open the Prometheus interface. Visit http://localhost:9090 on the machine running Docker.
  6. Check target health. In Prometheus, open the targets page. The prometheus job should resolve to prometheus:9090; the cAdvisor job should resolve to cadvisor:8080 when that service is running.
  7. Check an endpoint directly. Open the relevant service’s /metrics endpoint. For cAdvisor, that is http://localhost:8080/metrics when port 8080 is published to the host.

Compose also supports stopping the project, rebuilding or pulling changed services, streaming logs, and running one-off commands. Use the project directory and the same Compose file for those operations so you act on the intended stack.

Reload configuration safely

Prometheus can reload a valid configuration without rebuilding the container. Enable its lifecycle endpoint by adding --web.enable-lifecycle to the service command:

command:
  - --config.file=/etc/prometheus/prometheus.yml
  - --web.enable-lifecycle

After editing the host’s prometheus.yml, request a reload:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -X POST http://localhost:9090/-/reload

Prometheus also accepts SIGHUP. If the new YAML is malformed, Prometheus does not apply the change; the previous valid configuration continues running. Check the service logs and fix the syntax before retrying. A reload changes scrape configuration but does not migrate or recreate the persistent data volume.

Compose DNS versus localhost

localhost always means “this container” from a container’s point of view. Therefore, localhost:9090 in the Prometheus container points back to Prometheus itself; it does not point to cAdvisor, Redis, or your host. Use Compose service names for internal traffic:

Caller Correct destination Reason
Prometheus scraping itself prometheus:9090 Prometheus resolves the service name on the Compose network.
Prometheus scraping cAdvisor cadvisor:8080 cAdvisor is a separate container and service.
Grafana querying Prometheus http://prometheus:9090 Grafana reaches the Prometheus service internally.
Your browser on the Docker host http://localhost:9090 The published host port forwards to the Prometheus container.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Persistence choices and backup implications

Storage method How it appears in Compose When it fits Operational consideration
Named volume prometheus-data:/prometheus plus a top-level volumes entry Most straightforward single-host deployment Docker manages the location; include the volume in your backup plan.
Bind mount ./data:/prometheus You need an explicit host path or host-level backup policy The directory must exist and have permissions compatible with the container.

Changing the storage declaration changes where new writes go; it does not copy existing data automatically. Stop the stack and plan a deliberate data migration before switching from a named volume to a bind mount. Never remove the volume casually: deleting it removes the retained time series.

Minimal versus fuller stack

Characteristic Prometheus-only file Prometheus plus cAdvisor and Redis
Compose services One Three
Targets monitored by the supplied configuration Prometheus itself Prometheus and cAdvisor; Redis is present but requires an exporter or suitable endpoint before it is monitored
Container metrics Not included cAdvisor endpoint on port 8080
Persistence Named volume at /prometheus Same Prometheus named volume; cAdvisor and Redis storage are not specified by this example
Scrape cadence 15-second global default 15-second global default, with cAdvisor at 5 seconds
Published ports 9090 9090, 8080, and 6379
Operational complexity Lowest; useful for validating Prometheus configuration Higher; adds exporter permissions, dependency ordering, and more exposed endpoints

There is no universal performance benchmark in the official setup documentation for choosing between these layouts. Select the smallest stack that covers the metrics you actually need, then add services when a concrete monitoring requirement justifies the extra surface area.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Docker daemon metrics are a separate path

Docker’s own metrics endpoint is configured through the daemon’s metrics-addr setting, commonly 127.0.0.1:9323. Those metrics describe Docker itself, not the applications running in its containers. Docker notes that the available metric names are still in active development.

Do not assume that adding cAdvisor or a Redis container automatically enables Docker-daemon metrics. Treat daemon metrics as a separate target and configuration decision. In particular, a daemon bound only to host loopback is not automatically reachable from a Prometheus container through the container’s own localhost.

Troubleshooting checklist

Prometheus exits immediately

  • Run docker compose logs prometheus and look for a YAML parse error or an unreadable configuration path.
  • Confirm the host file is exactly ./prometheus.yml relative to the directory where Compose runs.
  • Confirm the command path and mount destination both use /etc/prometheus/prometheus.yml.

The targets page shows “down”

  • Check that the exporter service appears in docker compose ps.
  • Use the service DNS name and container port, such as cadvisor:8080, not localhost.
  • Inspect exporter logs and open its published /metrics endpoint from the Docker host.
  • Remember that depends_on controls startup order, not application readiness; retry after the service finishes initializing.

Metrics vanished after an update

  • Check that the Prometheus service still mounts a named volume or bind mount at /prometheus.
  • Verify you did not remove the named volume while cleaning up containers.
  • Check that a changed Compose project name did not create a different volume with a similar name.

A configuration reload has no effect

  • Ensure --web.enable-lifecycle is present before using /-/reload.
  • Read the logs for YAML errors. Prometheus keeps the last valid configuration when the replacement is malformed.
  • Confirm that you edited the host file actually mounted into the running container.

Ports cannot be opened

  • Another process may already be using 9090, 8080, or 6379. Change the host side of the mapping, for example 19090:9090, while leaving the container target port unchanged.
  • After changing a port, use the new host port in your browser; internal scrape targets still use service names and container ports.

Production-minded decisions before you expand

  • Pin image versions. A moving image tag can change behavior when the stack is recreated. Record the version you validated.
  • Expose only required ports. Every published port increases the reachable surface of the host. Keep internal-only services un published when host access is unnecessary.
  • Choose intervals deliberately. The 5-second cAdvisor interval is useful for fast-changing container signals but produces more samples than the 15-second default.
  • Back up the data path. A Compose file can recreate containers, but it cannot reconstruct deleted time series.
  • Test configuration changes. Reload only after validating YAML and watch the logs and targets page for the expected result.

With these pieces in place, the Compose file remains the control plane, prometheus.yml remains the source of scrape and rule definitions, exporters remain independently replaceable services, and the named volume preserves the history that makes monitoring useful.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.