Alloy

Alloy is an open-source OpenTelemetry collector by Grafana Labs for collecting, processing, and exporting telemetry data such as logs, metrics, and traces.

This compose file deploys Alloy as a log collector that ships Docker container logs and Linux journal logs to a Loki instance. It mounts the Docker socket for docker logs and journal directory for journal logs, with its configuration stored on NFS. The Alloy dashboard is proxied through a Traefik reverse proxy with Cloudflare TLS certificates. An example Alloy configuration file is included that sends the collected logs to a Loki instance.

For more information, check out the official documentation.

Docker Compose

# compose.yaml

services:
  alloy:
    image: grafana/alloy:latest
    container_name: alloy
    restart: unless-stopped
    # ports:
    #  - 12345:12345
    networks:
      - alloy_proxy
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /var/log/journal:/var/log/journal:ro
      - type: volume
        source: docker-nfs
        target: /etc/alloy
        volume:
          subpath: alloy/config
    command:
      - run
      - /etc/alloy/config.alloy
      - --storage.path=/var/lib/alloy/data
      - --server.http.listen-addr=0.0.0.0:12345
      - --stability.level=generally-available
    environment:
      LOKI_HOST: ${LOKI_HOST}
      DOCKER_HOST: ${DOCKER_HOST}
      TZ: Europe/London
    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=alloy_proxy"

      - "traefik.http.services.alloy.loadbalancer.server.port=12345"

      - "traefik.http.routers.alloy.rule=Host(`alloy.${TRAEFIK_BASE_URL}`)"
      - "traefik.http.routers.alloy.entrypoints=websecure"
      - "traefik.http.routers.alloy.tls.certresolver=cloudflare"

volumes:
  docker-nfs:
    driver: local
    driver_opts:
      type: nfs
      o: addr=xxx.xxx.xxx.xxx,nolock,soft,rw,nfsvers=4.2
      device: :/mnt/nfs-volume

networks:
  alloy_proxy:
    name: alloy_proxy

Environment Variables

# .env

TRAEFIK_BASE_URL=example.com
DOCKER_HOST=VM_NAME
LOKI_HOST=loki.example.com

Configuration

The Alloy configuration file is found in the mounted /etc/alloy directory.

// config.alloy

logging {
  level  = "info"
  format = "logfmt"
  write_to = [loki.relabel.alloy_logs.receiver]
}


discovery.docker "local_docker" {
  host = "unix:///var/run/docker.sock"
}


loki.source.journal "read" {
  forward_to    = [ loki.relabel.journal_labels.receiver ]
  labels        = {
    application = "journald",
    host = sys.env("DOCKER_HOST"),
  }
  path          = "/var/log/journal"
}


loki.relabel "journal_labels" {
  forward_to = [loki.write.lokiout.receiver]

  rule {
    source_labels = ["__journal__systemd_unit"]
    target_label  = "unit"
  }
  rule {
    source_labels = ["__journal__transport"]
    target_label  = "transport"
  }
  rule {
    source_labels = ["__journal_priority_keyword"]
    target_label  = "priority"
  }
}


discovery.relabel "docker_labels" {
  targets = []

  rule {
    source_labels = ["__meta_docker_container_name"]
    target_label  = "container"
    regex         = "/(.*)"
    replacement   = "$1"
  }
  rule {
    source_labels = ["__meta_docker_container_id"]
    target_label  = "container_id"
  }
}


loki.source.docker "docker_engine" {
  host = "unix:///var/run/docker.sock"

  targets = discovery.docker.local_docker.targets

  labels = {
    application = "docker",
    host = sys.env("DOCKER_HOST"),
  }

  relabel_rules = discovery.relabel.docker_labels.rules

  forward_to = [loki.write.lokiout.receiver]
}


loki.write "lokiout" {
  endpoint {
    url = "https://loki.example.com/loki/api/v1/push"
  }
}


loki.relabel "alloy_logs" {
  forward_to = [loki.write.lokiout.receiver]

  rule {
    target_label = "service"
    replacement  = "alloy"
  }
  rule {
    target_label = "host"
    replacement = sys.env("DOCKER_HOST")
  }
  rule {
    target_label = "application"
    replacement = "alloy"
  }
}

Traefik Configuration

# compose.yaml (excerpt)

services:
  traefik:
    image: traefik:latest
    container_name: traefik
    ...
    networks:
      - traefik
      # here
      - alloy_proxy
    ...

networks:
  # here
  alloy_proxy:
    name: alloy_proxy