За межами базового моніторингу
Існує суттєва різниця між моніторингом і спостережуваністю. Моніторинг каже вам, коли щось не так. Спостережуваність каже вам, чому. Стек спостережуваності продакшн-рівня поєднує метрики, логи й трейси в єдиному поданні, яке дозволяє вашій команді діагностувати проблеми за хвилини, а не години.
У цьому посібнику ми проходимо стек, який ми найчастіше розгортаємо в DevOpsVibe: Prometheus для метрик, Grafana для візуалізації, Alertmanager для сповіщень і Loki для агрегації логів. Усе працює на Kubernetes.
Огляд архітектури
Стек складається з чотирьох основних компонентів:
- Prometheus -- скрейпить і зберігає time-series метрики з ваших сервісів та інфраструктури
- Grafana -- надає дашборди, інструменти дослідження та єдиний інтерфейс запитів
- Alertmanager -- обробляє маршрутизацію сповіщень, дедуплікацію, групування та silencing
- Loki -- горизонтально масштабована система агрегації логів, спроєктована для роботи з Grafana
Разом ці інструменти дають вам три стовпи спостережуваності: метрики, логи і (з додаванням Tempo) трейси.
Розгортання стека за допомогою Helm
Найшвидший шлях до продакшну — Helm-чарт kube-prometheus-stack, що включає Prometheus, Grafana, Alertmanager і набір попередньо налаштованих recording rules та дашбордів:
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
helm install monitoring prometheus-community/kube-prometheus-stack \
--namespace monitoring \
--create-namespace \
--values custom-values.yaml
Кастомні значення
Ось налаштований під продакшн custom-values.yaml:
# custom-values.yaml
prometheus:
prometheusSpec:
retention: 30d
retentionSize: "50GB"
storageSpec:
volumeClaimTemplate:
spec:
storageClassName: gp3
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 100Gi
resources:
requests:
memory: 4Gi
cpu: "2"
limits:
memory: 8Gi
scrapeInterval: 30s
evaluationInterval: 30s
grafana:
adminPassword: "${GRAFANA_ADMIN_PASSWORD}"
persistence:
enabled: true
size: 10Gi
dashboardProviders:
dashboardproviders.yaml:
apiVersion: 1
providers:
- name: custom
orgId: 1
folder: "Custom"
type: file
disableDeletion: false
editable: true
options:
path: /var/lib/grafana/dashboards/custom
alertmanager:
alertmanagerSpec:
storage:
volumeClaimTemplate:
spec:
storageClassName: gp3
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 5Gi
Налаштування service discovery
Prometheus автоматично виявляє цілі в Kubernetes за допомогою custom resources ServiceMonitor і PodMonitor. Щоб моніторити новий застосунок, створіть ServiceMonitor:
# servicemonitor.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: my-api
namespace: monitoring
labels:
release: monitoring
spec:
selector:
matchLabels:
app: my-api
namespaceSelector:
matchNames:
- production
endpoints:
- port: metrics
interval: 15s
path: /metrics
scrapeTimeout: 10s
Ключова деталь, яку багато команд пропускають: лейбл release: monitoring має збігатися з ім'ям Helm-релізу. Без нього Prometheus не підхопить ваш ServiceMonitor.
Побудова ефективних дашбордів
Поширена помилка — створення дашбордів з десятками панелей, на які ніхто не дивиться. Натомість дотримуйтесь методів RED і USE:
Метод RED (для сервісів)
- Rate -- запитів за секунду
- Errors -- рівень помилок у відсотках
- Duration -- перцентилі затримки (p50, p95, p99)
Метод USE (для ресурсів)
- Utilization -- відсоток використовуваної ємності ресурсу
- Saturation -- кількість роботи в черзі
- Errors -- кількість помилкових подій
Ось визначення панелі дашборду Grafana для затримки API за допомогою PromQL:
{
"title": "API Latency (p99)",
"type": "timeseries",
"targets": [
{
"expr": "histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket{service=\"my-api\"}[5m])) by (le))",
"legendFormat": "p99"
},
{
"expr": "histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket{service=\"my-api\"}[5m])) by (le))",
"legendFormat": "p95"
},
{
"expr": "histogram_quantile(0.50, sum(rate(http_request_duration_seconds_bucket{service=\"my-api\"}[5m])) by (le))",
"legendFormat": "p50"
}
]
}
Сповіщення, що не викликають втоми
Втома від сповіщень — причина номер один, чому інвестиції в моніторинг провалюються. Інженери починають ігнорувати сповіщення, і потім справжній інцидент проходить непоміченим. Ось як ми налаштовуємо Alertmanager, щоб запобігти цьому:
# alertmanager-config.yaml
global:
resolve_timeout: 5m
slack_api_url: "${SLACK_WEBHOOK_URL}"
route:
receiver: "default"
group_by: ["alertname", "namespace", "service"]
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
routes:
- match:
severity: critical
receiver: "pagerduty-critical"
repeat_interval: 15m
- match:
severity: warning
receiver: "slack-warnings"
repeat_interval: 4h
receivers:
- name: "default"
slack_configs:
- channel: "#alerts-default"
title: '{{ .GroupLabels.alertname }}'
text: '{{ range .Alerts }}{{ .Annotations.description }}{{ end }}'
- name: "pagerduty-critical"
pagerduty_configs:
- service_key: "${PAGERDUTY_SERVICE_KEY}"
severity: critical
- name: "slack-warnings"
slack_configs:
- channel: "#alerts-warnings"
inhibit_rules:
- source_match:
severity: critical
target_match:
severity: warning
equal: ["alertname", "namespace"]
Написання хороших правил сповіщень
Кожне сповіщення має бути actionable. Якщо інженер отримує сповіщення і не знає, що робити, такого сповіщення не повинно існувати.
# alert-rules.yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: api-alerts
namespace: monitoring
spec:
groups:
- name: api.rules
rules:
- alert: HighErrorRate
expr: |
sum(rate(http_requests_total{status=~"5.."}[5m])) by (service)
/
sum(rate(http_requests_total[5m])) by (service)
> 0.05
for: 5m
labels:
severity: critical
annotations:
summary: "High error rate on {{ $labels.service }}"
description: "{{ $labels.service }} is returning 5xx errors at {{ $value | humanizePercentage }} over the last 5 minutes."
runbook: "https://wiki.example.com/runbooks/high-error-rate"
- alert: HighLatency
expr: |
histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le, service))
> 2.0
for: 10m
labels:
severity: warning
annotations:
summary: "High p99 latency on {{ $labels.service }}"
description: "p99 latency for {{ $labels.service }} is {{ $value }}s, exceeding 2s threshold."
Додавання агрегації логів за допомогою Loki
Розгорніть Loki разом зі стеком Prometheus, щоб об'єднати метрики й логи в Grafana:
helm install loki grafana/loki-stack \
--namespace monitoring \
--set promtail.enabled=true \
--set loki.persistence.enabled=true \
--set loki.persistence.size=50Gi \
--set loki.persistence.storageClassName=gp3
Потім додайте Loki як data source у Grafana. Сила цього налаштування — у можливості перейти від сплеску метрики безпосередньо до відповідних логів за допомогою split view Grafana та label matching.
Типовий запит LogQL для пошуку помилок:
{namespace="production", app="my-api"} |= "error" | json | level="error" | line_format "{{.timestamp}} {{.message}}"
Моніторинг на основі SLO
Замість того щоб сповіщати на довільні пороги, визначте Service Level Objectives і сповіщайте на burn rates:
- SLI: Співвідношення успішних запитів до загальних
- SLO: 99.9% запитів повинні успішно завершуватися за 30-денним вікном
- Error budget: 0.1% запитів можуть зазнати невдачі (приблизно 43 хвилини простою на місяць)
Сповіщайте, коли ваш error budget вигорає занадто швидко:
- alert: ErrorBudgetBurnRate
expr: |
(
sum(rate(http_requests_total{status=~"5.."}[1h])) by (service)
/
sum(rate(http_requests_total[1h])) by (service)
) > (14.4 * 0.001)
for: 5m
labels:
severity: critical
annotations:
summary: "Error budget burning fast for {{ $labels.service }}"
Операційні поради
- Підбирайте retention правильно. 30 днів даних високої роздільної здатності з downsampled довготривалим зберіганням через Thanos або Cortex.
- Використовуйте recording rules для попереднього обчислення дорогих запитів. Це драматично покращує час завантаження дашбордів.
- Розділяйте Prometheus для сповіщень і Prometheus для дашбордів у великих середовищах, щоб уникнути впливу навантаження запитів на оцінку сповіщень.
- Зберігайте дашборди як код у системі контролю версій за допомогою системи provisioning Grafana або інструментів на кшталт Grafonnet.
- Тестуйте свої сповіщення. Використовуйте
promtoolдля unit-тестування правил сповіщень перед їх розгортанням.
Висновок
Добре побудований стек спостережуваності — не розкіш, а фундамент, що робить можливим усе інше. Без нього реакція на інциденти — це гадання, планування ємності — азартна гра, а оптимізація продуктивності — стрільба наосліп.
У DevOpsVibe ми проєктуємо й розгортаємо платформи спостережуваності, адаптовані до вашої інфраструктури. Від початкового налаштування до кастомних дашбордів і SLO-фреймворків — ми дбаємо, щоб ваша команда мала видимість, яка їй потрібна. Зв'яжіться з нами, щоб обговорити ваші потреби в моніторингу.