Monitoring Stack¶
Deploy Prometheus, Grafana, and Alertmanager using Docker Compose.
Overview¶
This example demonstrates:
- Docker Compose service management with systemd
- Multi-container orchestration
- Volume and directory setup
- Configuration templating
- Secret injection
Architecture¶
┌─────────────────────────────────────────────┐
│ Monitoring Stack │
┌────────────────┼──────────────────────────────────────────────┤
│ │ │
│ :3000 ┌───┴───┐ :9090 ┌────────────┐ :9093 │
│ ◄─────────▶│Grafana│◄──────────▶│ Prometheus │◄──────────────│
│ └───────┘ └─────┬──────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Alertmanager │ │
│ └─────────────────┘ │
│ ▲ │
│ │ │
│ ┌──────────────────────────┤ │
│ ▼ ▼ │
│ ┌───────────────┐ ┌───────────────┐ │
│ │ Node Exporter │ │ cAdvisor │ │
│ │ :9100 │ │ :8080 │ │
│ └───────────────┘ └───────────────┘ │
│ │
└───────────────────────────────────────────────────────────────┘
Files¶
examples/monitoring_stack/
├── deploy.py
├── templates/
│ ├── docker-compose.yml.j2
│ ├── prometheus.yml.j2
│ └── grafana.ini.j2
└── README.md
Configuration¶
# Stack configuration
STACK_NAME = "monitoring"
STACK_DIR = "/opt/monitoring"
# Ports
GRAFANA_PORT = 3000
PROMETHEUS_PORT = 9090
ALERTMANAGER_PORT = 9093
# Grafana
GRAFANA_ADMIN_PASSWORD = "secure_password"
# Retention
PROMETHEUS_RETENTION = "30d"
# Targets to monitor
SCRAPE_TARGETS = [
{"job": "node", "targets": ["localhost:9100"]},
{"job": "docker", "targets": ["localhost:8080"]},
]
Usage¶
# Preview changes
python examples/monitoring_stack/deploy.py --dry-run
# Deploy
sudo python examples/monitoring_stack/deploy.py
# Access Grafana at http://localhost:3000
What Gets Deployed¶
1. Directory Structure¶
/opt/monitoring/
├── docker-compose.yml
├── prometheus/
│ └── prometheus.yml
├── grafana/
│ ├── grafana.ini
│ └── provisioning/
│ ├── datasources/
│ └── dashboards/
├── alertmanager/
│ └── alertmanager.yml
└── data/
├── prometheus/
└── grafana/
2. Docker Compose Configuration¶
/opt/monitoring/docker-compose.yml:
version: '3.8'
services:
prometheus:
image: prom/prometheus:latest
container_name: prometheus
restart: unless-stopped
ports:
- "9090:9090"
volumes:
- ./prometheus:/etc/prometheus
- ./data/prometheus:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.retention.time=30d'
grafana:
image: grafana/grafana:latest
container_name: grafana
restart: unless-stopped
ports:
- "3000:3000"
volumes:
- ./grafana/grafana.ini:/etc/grafana/grafana.ini
- ./grafana/provisioning:/etc/grafana/provisioning
- ./data/grafana:/var/lib/grafana
environment:
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD}
alertmanager:
image: prom/alertmanager:latest
container_name: alertmanager
restart: unless-stopped
ports:
- "9093:9093"
volumes:
- ./alertmanager:/etc/alertmanager
node-exporter:
image: prom/node-exporter:latest
container_name: node-exporter
restart: unless-stopped
ports:
- "9100:9100"
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
command:
- '--path.procfs=/host/proc'
- '--path.sysfs=/host/sys'
- '--path.rootfs=/rootfs'
cadvisor:
image: gcr.io/cadvisor/cadvisor:latest
container_name: cadvisor
restart: unless-stopped
ports:
- "8080:8080"
volumes:
- /:/rootfs:ro
- /var/run:/var/run:ro
- /sys:/sys:ro
- /var/lib/docker:/var/lib/docker:ro
3. Prometheus Configuration¶
/opt/monitoring/prometheus/prometheus.yml:
global:
scrape_interval: 15s
evaluation_interval: 15s
alerting:
alertmanagers:
- static_configs:
- targets:
- alertmanager:9093
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'node'
static_configs:
- targets: ['node-exporter:9100']
- job_name: 'docker'
static_configs:
- targets: ['cadvisor:8080']
4. Grafana Configuration¶
/opt/monitoring/grafana/grafana.ini:
[server]
http_port = 3000
[security]
admin_user = admin
[users]
allow_sign_up = false
[auth.anonymous]
enabled = false
5. Grafana Datasource Provisioning¶
/opt/monitoring/grafana/provisioning/datasources/prometheus.yml:
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
access: proxy
url: http://prometheus:9090
isDefault: true
6. Systemd Service¶
from fscm.modules import systemd
def create_systemd_service():
systemd.docker_compose_service(
name="monitoring",
compose_file=f"{STACK_DIR}/docker-compose.yml",
description="Monitoring Stack (Prometheus + Grafana)"
)
Key Code Sections¶
Setup Directories¶
def setup_directories():
dirs = [
f"{STACK_DIR}",
f"{STACK_DIR}/prometheus",
f"{STACK_DIR}/grafana",
f"{STACK_DIR}/grafana/provisioning/datasources",
f"{STACK_DIR}/grafana/provisioning/dashboards",
f"{STACK_DIR}/alertmanager",
f"{STACK_DIR}/data/prometheus",
f"{STACK_DIR}/data/grafana",
]
for d in dirs:
mkdir(d, mode="0755")
# Grafana data needs to be writable by container user (uid 472)
chown(f"{STACK_DIR}/data/grafana", "472:472")
Deploy Configurations¶
def deploy_configs():
# Docker Compose
compose = template(
"templates/docker-compose.yml.j2",
prometheus_port=PROMETHEUS_PORT,
grafana_port=GRAFANA_PORT,
alertmanager_port=ALERTMANAGER_PORT,
retention=PROMETHEUS_RETENTION
)
file(f"{STACK_DIR}/docker-compose.yml", compose)
# Prometheus
prom_config = template(
"templates/prometheus.yml.j2",
scrape_targets=SCRAPE_TARGETS
)
file(f"{STACK_DIR}/prometheus/prometheus.yml", prom_config)
# Grafana
grafana_config = template("templates/grafana.ini.j2")
file(f"{STACK_DIR}/grafana/grafana.ini", grafana_config)
# Grafana datasource
datasource = """apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
access: proxy
url: http://prometheus:9090
isDefault: true
"""
file(f"{STACK_DIR}/grafana/provisioning/datasources/prometheus.yml", datasource)
Management¶
Start Stack¶
View Logs¶
Restart After Config Change¶
Using Systemd¶
Accessing Services¶
| Service | URL | Default Credentials |
|---|---|---|
| Grafana | http://localhost:3000 | admin / (configured password) |
| Prometheus | http://localhost:9090 | — |
| Alertmanager | http://localhost:9093 | — |
Troubleshooting¶
Check Container Status¶
Prometheus Targets¶
Visit http://localhost:9090/targets to see scrape status.