Динамическое обнаружение целей в Docker и файловых конфигурациях
«В динамическом мире статическая конфигурация — это технический долг»
До сих пор мы использовали статическую конфигурацию:
scrape_configs:
- job_name: 'node'
static_configs:
- targets:
- 'server1:9100'
- 'server2:9100'
- 'server3:9100'Проблема: в динамической среде (Docker, Kubernetes, облака) цели постоянно меняются:
Решение: Service Discovery (SD) — автоматическое обнаружение целей.
┌─────────────────────────────────────────────────────────────┐
│ Prometheus │
│ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Service Discovery │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ Docker │ │ K8s │ │ Consul │ │ │
│ │ │ SD │ │ SD │ │ SD │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ │ │
│ └────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────┐ │
│ │ Relabeling │ │
│ │ (фильтрация и лейблы) │ │
│ └─────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────┐ │
│ │ Targets для скрапинга │ │
│ └─────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
Процесс:
Автоматическое обнаружение контейнеров Docker.
scrape_configs:
- job_name: 'docker'
docker_sd_configs:
- host: unix:///var/run/docker.sock
refresh_interval: 5s
filters:
- name: label
values: ['prometheus_scrape']
relabel_configs:
- source_labels: [__meta_docker_container_name]
target_label: container
- source_labels: [__meta_docker_container_label_prometheus_job]
target_label: job
- source_labels: [__meta_docker_container_port_number]
target_label: __address__Разбираем:
host — адрес Docker daemon (unix socket или tcp://)refresh_interval — как часто обновлять список целейФильтрует контейнеры перед добавлением:
filters:
- name: label
values: ['prometheus_scrape']Только контейнеры с лейблом prometheus_scrape=true будут добавлены.
Преобразует метаданные контейнера в лейблы Prometheus:
- source_labels: [__meta_docker_container_name]
target_label: container_meta лейблы (автоматически добавляются Docker SD):
__meta_docker_container_name — имя контейнера__meta_docker_container_label_* — лейблы контейнера__meta_docker_container_port_number — порт__meta_docker_network_ip — IP адрес в сетиversion: '3.8'
services:
prometheus:
image: prom/prometheus:v2.52.0
container_name: prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
- /var/run/docker.sock:/var/run/docker.sock:ro
command:
- '--config.file=/etc/prometheus/prometheus.yml'
restart: unless-stopped
api:
image: myapp/api:latest
labels:
- prometheus_scrape=true
- prometheus_job=api
- prometheus_port=8000
ports:
- "8000:8000"
worker:
image: myapp/worker:latest
labels:
- prometheus_scrape=true
- prometheus_job=worker
- prometheus_port=9000global:
scrape_interval: 15s
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'docker'
docker_sd_configs:
- host: unix:///var/run/docker.sock
refresh_interval: 5s
filters:
- name: label
values: ['prometheus_scrape']
relabel_configs:
# Используем лейбл prometheus_job как имя job
- source_labels: [__meta_docker_container_label_prometheus_job]
target_label: job
# Порт из лейбла prometheus_port
- source_labels: [__meta_docker_container_label_prometheus_port]
target_label: __address__
# Имя контейнера как лейбл
- source_labels: [__meta_docker_container_name]
target_label: containerКак работает:
prometheus_scrape=trueprometheus_port лейблаprometheus_jobcontainer с именем/metrics эндпоинтаПреимущество: добавьте новый контейнер с лейблами — Prometheus автоматически начнёт его скрапить.
SD из JSON-файлов.
scrape_configs:
- job_name: 'node'
file_sd_configs:
- files:
- '/etc/prometheus/targets/node.json'
refresh_interval: 5m
relabel_configs:
- source_labels: [__address__]
target_label: instance[
{
"targets": ["server1:9100", "server2:9100"],
"labels": {
"env": "production",
"datacenter": "us-east",
"team": "backend"
}
},
{
"targets": ["server3:9100"],
"labels": {
"env": "staging",
"datacenter": "eu-west",
"team": "frontend"
}
}
]Формат:
targets — список адресовlabels — лейблы для всех target в группеПреимущества:
#!/usr/bin/env python3
import json
import boto3
# Пример: генерация из AWS EC2
ec2 = boto3.client('ec2')
instances = ec2.describe_instances(
Filters=[{'Name': 'tag:Environment', 'Values': ['production']}]
)
targets = []
for reservation in instances['Reservations']:
for instance in reservation['Instances']:
targets.append({
"targets": [f"{instance['PrivateIpAddress']}:9100"],
"labels": {
"env": "production",
"instance_id": instance['InstanceId'],
"az": instance['Placement']['AvailabilityZone']
}
})
with open('/etc/prometheus/targets/node.json', 'w') as f:
json.dump(targets, f, indent=2)Запускайте скрипт по cron каждые 5 минут.
SD из HTTP-эндпоинта.
scrape_configs:
- job_name: 'consul'
http_sd_configs:
- url: 'http://consul:8500/v1/health/service/prometheus'
refresh_interval: 5sИсточники:
Автоматическое обнаружение подов и сервисов в Kubernetes.
scrape_configs:
- job_name: 'kubernetes-pods'
kubernetes_sd_configs:
- role: pod
kubeconfig_file: /etc/prometheus/kubeconfig
selectors:
- role: pod
label: prometheus.io/scrape=true
relabel_configs:
# Порт из аннотации
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_port]
action: replace
target_label: __address__
regex: (.+)
replacement: $1
# Path из аннотации
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+)
# Имя пода как лейбл
- source_labels: [__meta_kubernetes_pod_name]
target_label: pod
# Namespace как лейбл
- source_labels: [__meta_kubernetes_namespace]
target_label: namespaceАннотации в поде:
apiVersion: v1
kind: Pod
metadata:
name: myapp
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
prometheus.io/path: "/metrics"
spec:
containers:
- name: app
image: myapp:latest
ports:
- containerPort: 8080_meta_kubernetes лейблы:
__meta_kubernetes_pod_name — имя пода__meta_kubernetes_namespace — namespace__meta_kubernetes_pod_label_* — лейблы пода__meta_kubernetes_pod_annotation_* — аннотации пода__meta_kubernetes_pod_ip — IP подаRelabeling — мощный механизм преобразования метаданных перед скрапингом.
| action | Описание |
|---|---|
replace | Заменить значение лейбла (по умолчанию) |
keep | Оставить target только если regex совпадает |
drop | Отбросить target если regex совпадает |
labelmap | Создать лейблы из matching meta-лейблов |
labeldrop | Удалить лейблы по regex |
Фильтрация по лейблу:
relabel_configs:
- source_labels: [__meta_docker_container_label_prometheus_scrape]
action: keep
regex: "true"Только контейнеры со prometheus_scrape=true будут добавлены.
Изменение адреса:
relabel_configs:
- source_labels: [__meta_docker_container_ip, __meta_docker_container_port]
separator: ':'
target_label: __address__Добавление статического лейбла:
relabel_configs:
- target_label: env
replacement: productionLabelmap — копирование всех лейблов:
relabel_configs:
- action: labelmap
regex: __meta_docker_container_label_(.+)
replacement: $1Копирует все лейблы контейнера в лейблы Prometheus.
metric_relabel_configs применяется к метрикам после сбора (перед хранением).
metric_relabel_configs:
- source_labels: [__name__]
regex: 'go_.*'
action: dropОтбрасывает все метрики, начинающиеся с go_ (внутренние метрики Go runtime).
metric_relabel_configs:
- source_labels: [__name__]
regex: 'node_(cpu|memory|disk|net)_.*'
action: keepСохраняет только ключевые метрики Node Exporter.
metric_relabel_configs:
- source_labels: [__name__]
regex: 'http_requests(.*)'
target_label: __name__
replacement: 'api_requests$1'
action: replaceПереименовывает http_requests_total в api_requests_total.
Не скрапьте всё подряд. Фильтруйте по лейблам:
filters:
- name: label
values: ['prometheus_scrape']relabel_configs:
- source_labels: [__meta_docker_container_name]
target_label: container
- source_labels: [__meta_docker_container_label_com_docker_compose_service]
target_label: service
- source_labels: [__meta_docker_network_ip]
target_label: instance# Отдельно для API
- job_name: 'docker-api'
filters:
- name: label
values: ['prometheus_job=api']
# Отдельно для воркеров
- job_name: 'docker-worker'
filters:
- name: label
values: ['prometheus_job=worker']Отбрасывайте ненужные метрики для экономии места:
metric_relabel_configs:
- source_labels: [__name__]
regex: 'go_.*|process_.*'
action: dropВ Prometheus UI:
В Prometheus UI:
Добавьте в Prometheus:
global:
log_level: debugИли через командную строку:
prometheus --log.level=debugВ следующей теме вы изучите best practices — как не наступить на грабли при построении мониторинга.
Вопросы ещё не добавлены
Вопросы для этой подтемы ещё не добавлены.