A guide to collect Docker and host logs using Grafana Alloy + Loki, and why Alloy is replacing Promtail. Includes diagrams, permissions, docker-compose, and config files.
Containers made deployments fast, portable, and efficient.
But collecting logs from hosts + containers + services quickly becomes chaotic.
Thatβs why the modern stack uses Grafana Alloy + Loki instead of the older Promtail-based approach.
π§ Why Grafana Loki Uses Alloy Instead of Promtail
Promtail served its purpose well β but infrastructure evolved.
Grafana introduced Alloy as its unified, modern, extensible telemetry collector.
π₯ Promtail vs Alloy (Honest Breakdown)
| Feature | Promtail | Alloy |
|---|---|---|
| Log Collection | βοΈ Yes | βοΈ Yes |
| Metrics Collection | β No | βοΈ Yes |
| Traces Collection | β No | βοΈ Yes |
| Unified pipeline | β | βοΈ Logs + Metrics + Traces |
| Docker auto-discovery | Limited | βοΈ Excellent |
| Processing pipeline | Basic | βοΈ Powerful |
| Extensibility | Low | βοΈ High |
| Future support | π₯ Legacy | π© Actively developed |
π The real reason Alloy replaces Promtail
Promtail = log-only agent
Alloy = one collector for logs, metrics, and traces
Promtail is now maintenance-only.
Alloy is the future.
π§© Architecture Overview
The logging pipeline includes:
- Alloy β collector
- Loki β log store
- Grafana β visualization
π₯ High-level workflow
Host Logs β
Alloy β Loki β Grafana
Docker Logs β
π§± Architecture Diagram (Text View)
βββββββββββββββββββββββββ
β Grafana β
β (Dashboards + Logs) β
ββββββββββββ¬βββββββββββββ
β
ββββββββββ΄ββββββββββ
β Loki β
β (Log Store) β
ββββββββββ¬ββββββββββ
β
ββββββββββββββββββ΄βββββββββββββββββ
β Alloy β
β (Unified Telemetry Collector). β
βββββββββββββ¬ββββββββββββ¬ββββββββββ
β β
Host Logs Docker Logs
(/var/log/*) (via Docker Engine)
π Folder Structure
/opt/alloy/
βββ alloy/
β βββ config.alloy
βββ grafana-data/
βββ loki/
β βββ loki-config.yaml
βββ loki-data/
βββ docker-compose.yml
π Required Permissions (Critical)
Loki & Grafana will fail without correct folder ownership.
Loki storage (UID/GID 10001)
sudo mkdir -p /opt/alloy/loki-data
sudo chown -R 10001:10001 /opt/alloy/loki-data
sudo mkdir -p /opt/alloy/grafana-data
sudo chown -R 472:472 /opt/alloy/grafana-data
π³ docker-compose.yaml (Production Ready)
services:
loki:
image: grafana/loki:3.1.0
container_name: loki
command: -config.file=/etc/loki/local-config.yaml
volumes:
- ./loki/loki-config.yaml:/etc/loki/loki-config.yaml:ro
- ./loki-data:/loki
ports:
- "3100:3100"
alloy:
image: grafana/alloy:latest
container_name: alloy
privileged: true
volumes:
- ./alloy/config.alloy:/etc/alloy/config.alloy:ro
- /var/run/docker.sock:/var/run/docker.sock
- /var/log:/var/log:ro
ports:
- "12345:12345"
grafana:
image: grafana/grafana:latest
container_name: grafana
volumes:
- ./grafana-data:/var/lib/grafana
ports:
- "3000:3000"
βοΈ config.alloy
### Send Alloyβs internal logs to Loki
logging {
level = "info"
format = "logfmt"
write_to = [loki.relabel.alloy_logs.receiver]
}
### Auto-discover Docker containers
discovery.docker "local_docker" {
host = "unix:///var/run/docker.sock"
}
### Match host logs (/var/log/*log)
local.file_match "host_logs" {
path_targets = [
{ __path__ = "/var/log/*log" },
]
}
### Tail host logs
loki.source.file "host_tail" {
targets = local.file_match.host_logs.targets
forward_to = [loki.process.host_pipeline.receiver]
}
### Add static labels to host logs
loki.process "host_pipeline" {
forward_to = [loki.write.local.receiver]
stage.static_labels {
values = {
job = "varlogs",
source = "host",
env = "dev",
}
}
}
### Collect logs from Docker containers (stdout/stderr)
loki.source.docker "docker_engine" {
host = "unix:///var/run/docker.sock"
targets = discovery.docker.local_docker.targets
labels = {
job = "docker_logs",
env = "dev",
cluster = "local",
}
forward_to = [loki.write.local.receiver]
}
### Loki ingest endpoint
loki.write "local" {
endpoint {
url = "http://loki:3100/loki/api/v1/push"
}
}
### Add label to internal Alloy logs
loki.relabel "alloy_logs" {
forward_to = [loki.write.local.receiver]
rule {
target_label = "service"
replacement = "alloy"
}
}
loki-config.yaml
auth_enabled: false
server:
http_listen_port: 3100
grpc_listen_port: 9096
common:
instance_addr: 127.0.0.1
path_prefix: /loki
storage:
filesystem:
chunks_directory: /loki/chunks
rules_directory: /loki/rules
replication_factor: 1
ring:
kvstore:
store: inmemory
query_range:
results_cache:
cache:
embedded_cache:
enabled: true
max_size_mb: 100
limits_config:
ingestion_rate_mb: 10
ingestion_burst_size_mb: 20
max_concurrent_tail_requests: 20
max_cache_freshness_per_query: 10m
max_streams_per_user: 50
allow_structured_metadata: false
schema_config:
configs:
- from: 2024-01-01
store: tsdb
object_store: filesystem
schema: v13
index:
prefix: index_
period: 24h
π Restart and Run
docker compose up -d
- β All Docker logs collected
- β All host logs collected
- β Alloy logs included with label
service=alloy - β Grafana fully functional
- β No permission errors
- β Production-grade observability pipeline
Alloy replaces Promtail and simplifies the entire telemetry ecosystem β logs, metrics, traces β in one place.
Top comments (0)