How to Run Prometheus with Docker and Docker Compose

Step-by-step guide to running Prometheus in Docker and Docker Compose. Configure scrape jobs, use bind mounts or custom images, persist data with volumes, and verify the setup.

Prometheus is an open source systems monitoring and alerting toolkit. It was originally built at SoundCloud and is now a standalone project maintained by the community. Prometheus collects and stores metrics as time series data: each sample is stored with a timestamp and optional labels (key-value pairs), so you can track how metrics change over time and slice them by job, instance, or other dimensions.

Metrics help you understand how your systems and applications behave. For example, if a web app becomes slow, request rate or latency metrics can show whether the cause is high traffic, slow dependencies, or resource saturation. Prometheus is widely used for monitoring servers, containers, and applications in DevOps and cloud-native environments.

In this guide you will learn how to run Prometheus with Docker and Docker Compose by:

  • Confirming Docker and Docker Compose are available
  • Creating a minimal Prometheus configuration and running Prometheus in a container
  • Using bind mounts or a custom image to supply configuration
  • Defining a Compose stack with optional data persistence
  • Verifying the setup in the Prometheus UI

By the end, you will have Prometheus running in Docker and ready to scrape targets or extend with Alertmanager and Grafana.

What is Prometheus?

Prometheus scrapes metrics over HTTP from configured targets (such as itself, Node Exporter, or application exporters), stores them in a time-series database, and lets you query them with PromQL (Prometheus Query Language). It can evaluate alerting rules and send notifications to Alertmanager. The official Prometheus documentation describes the architecture and components in detail.

Running Prometheus in Docker or Docker Compose is useful for local development, testing, or small deployments where you prefer containers over a host install. For production at scale, you may later consider Kubernetes; see the Production-Ready Prometheus on Kubernetes guide for a full stack with authentication and high availability.

Prerequisites

Before you start, ensure you have:

  • Docker Engine installed and running. On Ubuntu, see How to Install and Use Docker in Ubuntu 22.04; for other distributions, use the official Docker install guide.
  • Docker Compose available. Modern Docker Desktop and recent Docker Engine installs include the Compose V2 plugin, so you run docker compose (with a space). If you use the standalone Python-based docker-compose, run docker-compose (with a hyphen). The examples below use docker compose; substitute docker-compose if that is what you have.
  • Port 9090 free for the Prometheus UI and API (or change the published port in the examples).

Confirm that Docker is working:

1
docker version

You should see both Client and Server sections. Then confirm Compose:

1
docker compose version

If that fails, try docker-compose version. If neither works, install the Compose plugin or the standalone Compose for your platform.

Prometheus Configuration Overview

Prometheus is configured via a single YAML file. The main parts are:

  • global – Default scrape interval and evaluation interval.
  • alerting – Optional Alertmanager endpoints for alerts.
  • rule_files – Optional files containing recording and alerting rules.
  • scrape_configs – List of jobs and targets to scrape (e.g. Prometheus itself, Node Exporter, application metrics).

The minimal config below scrapes only Prometheus itself. You can add more jobs later (e.g. Node Exporter for host metrics).

Running Prometheus with Docker

Official Prometheus images are published on Quay and Docker Hub. A quick start without a custom config is:

1
docker run -p 9090:9090 prom/prometheus

That runs Prometheus with its default configuration and exposes the UI on port 9090. For a config you can edit on the host, use a bind mount or a custom image.

Minimal Configuration File

Save the following as prometheus.yml in a directory you will use for config (e.g. ./prometheus):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Global settings
global:
  scrape_interval: 15s
  evaluation_interval: 15s

# Optional: Alertmanager (uncomment and set targets when used)
alerting:
  alertmanagers:
    - static_configs:
        - targets: []
          # - alertmanager:9093

# Optional: rule files (uncomment when you have rules)
rule_files: []
# - "first_rules.yml"
# - "second_rules.yml"

# Scrape configs: targets to scrape
scrape_configs:
  # Scrape Prometheus itself
  - job_name: "prometheus"
    static_configs:
      - targets: ["localhost:9090"]

The prometheus job scrapes the Prometheus server’s own /metrics endpoint. When you add more services (e.g. Node Exporter), add another job with the appropriate targets.

Option 1: Bind-Mount Configuration

Bind-mount your prometheus.yml into the container so you can change it without rebuilding:

1
2
3
4
5
docker run -d \
  --name prometheus \
  -p 9090:9090 \
  -v "$(pwd)/prometheus.yml:/etc/prometheus/prometheus.yml:ro" \
  prom/prometheus:latest

Or mount the whole config directory:

1
2
3
4
5
docker run -d \
  --name prometheus \
  -p 9090:9090 \
  -v "$(pwd):/etc/prometheus:ro" \
  prom/prometheus:latest

Prometheus stores time-series data inside the container by default. For production, use a named volume for data so it survives container removal and upgrades (see Docker volumes and the Compose example below). Reload config at runtime with a SIGHUP or by restarting the container after editing the file.

Option 2: Custom Image

You can bake the config into an image so you do not need a file on the host. Create a directory with prometheus.yml and a Dockerfile:

Dockerfile:

1
2
FROM prom/prometheus:latest
COPY prometheus.yml /etc/prometheus/prometheus.yml

Build and run:

1
2
docker build -t my-prometheus .
docker run -d --name prometheus -p 9090:9090 my-prometheus

This works well when the config is static and the same across environments. For dynamic or environment-specific config, bind mounts or templating are usually better.

For more options (e.g. dynamic config), see the official Prometheus installation docs (volumes and bind mount, custom image).

Running Prometheus with Docker Compose

Docker Compose lets you define Prometheus (and optionally other services) in a YAML file and start them with one command. Use a bind-mounted config and a named volume for data so metrics persist across restarts and upgrades.

Directory Layout

Create a project directory and put your config there:

1
2
3
prometheus/
├── docker-compose.yaml
└── prometheus.yml

prometheus.yml can be the minimal config shown earlier.

Compose File

docker-compose.yaml:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
services:
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    restart: unless-stopped
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - prometheus_data:/prometheus
    command:
      - "--config.file=/etc/prometheus/prometheus.yml"
      - "--storage.tsdb.path=/prometheus"
      - "--web.enable-lifecycle"

volumes:
  prometheus_data:
  • prometheus.yml is mounted read-only so Prometheus can read it.
  • prometheus_data is a named volume so TSDB data persists. Without it, data is lost when the container is removed.
  • –web.enable-lifecycle allows reloading config via HTTP (e.g. curl -X POST http://localhost:9090/-/reload) when using a bind-mounted config.

Start the stack:

1
2
cd prometheus
docker compose up -d

Example output:

1
2
3
[+] Running 2/2
 ✔ Network prometheus_default    Created
 ✔ Container prometheus          Started

Check that the container is running:

1
docker compose ps

You should see the prometheus service with port 9090 mapped. Open http://localhost:9090 (or http://your-server:9090) in a browser.

Optional: Add Node Exporter for Host Metrics

To scrape host metrics (CPU, memory, disk) from the same host where Docker runs, you can add Node Exporter as a sidecar and point Prometheus at it. Add a service and a scrape job.

docker-compose.yaml (excerpt; add the node_exporter service and update prometheus command so it can reach it):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
services:
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    restart: unless-stopped
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - prometheus_data:/prometheus
    command:
      - "--config.file=/etc/prometheus/prometheus.yml"
      - "--storage.tsdb.path=/prometheus"
      - "--web.enable-lifecycle"
    extra_hosts:
      - "host.docker.internal:host-gateway"

  node_exporter:
    image: prom/node-exporter:latest
    container_name: node_exporter
    restart: unless-stopped
    pid: host
    volumes:
      - /:/host:ro,rslave
    command:
      - "--path.rootfs=/host"

volumes:
  prometheus_data:

On Linux, use extra_hosts: - "host.docker.internal:host-gateway" so Prometheus (in Docker) can reach Node Exporter on the host. Then in prometheus.yml, add a job:

1
2
3
4
5
6
7
scrape_configs:
  - job_name: "prometheus"
    static_configs:
      - targets: ["localhost:9090"]
  - job_name: "node"
    static_configs:
      - targets: ["host.docker.internal:9100"]

Restart: docker compose up -d. After a scrape, you will see the node job in the Prometheus UI. For a full Linux + Prometheus + Grafana setup, see Monitor Linux Server With Prometheus and Grafana.

Verifying the Setup

  1. Open the Prometheus UI Go to http://localhost:9090 (or http://your-server:9090). You should see the Prometheus interface.

  2. Check targets Go to Status → Targets. The prometheus job should be UP. If you added Node Exporter, the node job should be UP after the first scrape.

  3. Run a query Go to Graph (or the query tab), enter up and click Execute. You should see at least one series with job="prometheus" and up=1.

  4. Reload config (if using bind mount) After editing prometheus.yml, either restart the container or, if you started with --web.enable-lifecycle, run:

    1
    
    curl -X POST http://localhost:9090/-/reload
    

Troubleshooting

  • Container exits immediately Check logs: docker compose logs prometheus or docker logs prometheus. Often the cause is an invalid or missing config file. Ensure the path in the volume mount is correct and the YAML is valid.

  • Target is DOWN If the target is another container, ensure they are on the same Docker network and use the service name (e.g. node_exporter:9100). If the target is on the host, use host.docker.internal:9100 (with host-gateway) or the host’s IP.

  • No data in Graph Confirm the scrape interval has passed (default 15s). Check Status → Targets and fix any DOWN targets. Ensure the configured port (e.g. 9090 for Prometheus) is correct.

  • Permission denied on volume Prometheus runs as a non-root user. If you use a bind mount for the data directory, ensure the directory is writable by the Prometheus user (UID in the image) or use a named volume instead.

Summary

You now have Prometheus running with Docker or Docker Compose:

  • Docker: Use docker run with a bind-mounted prometheus.yml or a custom image. Add a named volume for production data.
  • Docker Compose: Define the service with a bind-mounted config and a named volume for /prometheus; use docker compose up -d to run.
  • Verification: Open the UI, check Status → Targets, and run a query such as up.

From here you can add more scrape jobs (Node Exporter, application exporters), configure Alertmanager, or connect Grafana to Prometheus for dashboards. For installing and configuring Prometheus on a bare Linux server, see How to Install and Configure Prometheus on a Linux Server; for Kubernetes, see Production-Ready Prometheus on Kubernetes.

comments powered by Disqus
Citizix Ltd
Built with Hugo
Theme Stack designed by Jimmy