Prometheus automated discovery of services with docker-compose

When using docker-compose, we can use labels to annotate containers with some metadata. Similarly to how this can be done on Kubernetes using annotations.

You might already be using labels if you are using traefik or ofelia.

Prometheus service discovery

Prometheus supports service discovery mechanism. We are going to be using docker_sd to discover docker containers.

We can use a configuration like this. Which will use the docker.sock to get all containers, and then we can do some modification depending on labels, for example we can override the scheme, port and path via labels. As well as checking if prometheus.scrape is set to "true", to only scrape those containers that we explicitly say we want.

prometheus.yaml file would look like this:

scrape_configs:
  - job_name: docker-containers
    docker_sd_configs:
      - host: unix:///var/run/docker.sock
    relabel_configs:
      # Only keep containers that have a `prometheus.scrape` label set to true.
      - source_labels: [__meta_docker_container_label_prometheus_scrape]
        regex: true
        action: keep

      # Only keep those that are in network named metrics.
      - source_labels: [__meta_docker_network_name]
        regex: metrics
        action: keep

      # allow override of http scheme with `promehteus.scheme`
      - action: replace
        regex: (https?)
        source_labels: [__meta_docker_container_label_prometheus_scheme]
        target_label: __scheme__

      # allow override of default /metrics path with `prometheus.path`
      - action: replace
        regex: (.+)
        source_labels: [__meta_docker_container_label_prometheus_path]
        target_label: __metrics_path__

      # allow override of default port with `prometheus.port`
      - action: replace
        regex: ([^:]+)(?::\d+)?;(\d+)
        replacement: $1:$2
        source_labels: [__address__, __meta_docker_container_label_prometheus_port]
        target_label: __address__

      # Add all labels
      - {action: labelmap, regex: __meta_docker_container_label_(.+)}

the docker-compose.yaml would look like this:

version: "3"

networks:
  # Create a dedicated network for metrics
  metrics:
    name: metrics

services:
  # Run prometheus service that uses the prometheus.yaml config
  prometheus:
    image: prom/prometheus
    restart: always
    command:
      - "--config.file=/etc/prometheus/prometheus.yaml"
    networks:
      - metrics
    # root is needed to access the docker.sock.
    user: root
    volumes:
      # We need to pass the docker.sock for prometheus to be able
      # to connect to docker engine and discover containers.
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./prometheus.yaml:/etc/prometheus/prometheus.yaml:ro

Using the discovery with an application container

Now that we have Prometheus set up, we can deploy an application and tell the Prometheus to scrape it via the labels.

version: "3"

networks:
  traefik:
    name: traefik
  # We created metrics network in the docker-compose for prometheus,
  # that's why we have set it here to "external".
  metrics:
    external: true

services:
  # Example traefik which is configured to expose metrics in port 8082
  traefik:
    image: traefik:3.0
    restart: always
    networks:
      - traefik
      # The service must be part of metrics network,
      # otherwise the prometheus won't be able to connect to it.
      - metrics
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./traefik.toml:/traefik.toml
      - ./certificates:/certificates/
    labels:
      prometheus.scrape: "true"
      prometheus.port: "8082"
      prometheus.path: "/metrics" # /metrics is default
      prometheus.scheme: "http"   # http is default

When our service is deployed, the Prometheus should automatically discover it and start scraping the metrics.

This site is not using any commenting system, but you can share your thoughts with the author by sending an email to me@mnts.dev.