Skip to main content

Як моніторити Docker контейнери у production?

Моніторинг Docker у проді означає знати чотири речі весь час: чи container живий, чи healthy, чи не використовує забагато ресурсів, чи не рестартує надто часто. Інструменти для цього добре відомі; робота це зв'язати їх разом.

Теорія

TL;DR

  • Три шари моніторити: host (Linux-метрики), Docker-daemon, самі container.
  • Стандартний стек: cAdvisor (per-container метрики) + Prometheus (TSDB) + Grafana (дашборди) + Alertmanager (paging).
  • Логи окремо: Loki / ELK / fluentd / Datadog Logs.
  • На що alert: неочікувані рестарти, healthcheck-fails, OOM-kill, CPU/memory saturation.
  • Критичний інсайт: container-рестарти це сигнали, docker stats не зловить flapping container, що крутиться 30с і помирає.

Що міряти

Рівень host: - CPU/пам'ять/диск/мережа на host-масштабі - Docker-daemon uptime Рівень container: - CPU-використання (% від ліміту) - Memory-використання (vs cgroup-ліміт) - Network I/O - Block I/O - Restart count - Health-статус (healthy/unhealthy) - Uptime Рівень застосунку (всередині container): - HTTP latency / errors - Request rate - Кастомні business-метрики

Docker-специфічний моніторинг це шари 1-2. App-level метрики експортуються САМИМ застосунком (/metrics-endpoint, Prometheus-scraping).

Стандартний стек

cAdvisor — per-container метрики

Google cAdvisor читає cgroup-дані і експортує як Prometheus-метрики:

yaml
services: cadvisor: image: gcr.io/cadvisor/cadvisor:v0.49.0 container_name: cadvisor privileged: true devices: - /dev/kmsg ports: - "8080:8080" volumes: - /:/rootfs:ro - /var/run:/var/run:ro - /sys:/sys:ro - /var/lib/docker:/var/lib/docker:ro - /dev/disk:/dev/disk:ro restart: unless-stopped

Зайди на http://localhost:8080 для швидкого UI; метрики на /metrics.

Ключові cAdvisor-метрики:

  • container_cpu_usage_seconds_total — CPU consumed
  • container_memory_working_set_bytes — реальна пам'ять у use
  • container_network_receive_bytes_total / container_network_transmit_bytes_total — network I/O
  • container_fs_usage_bytes — disk-використання

Prometheus — зберігати і query'їти

yaml
prometheus: image: prom/prometheus:v2.55.0 volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro - promdata:/prometheus ports: - "9090:9090" command: - --config.file=/etc/prometheus/prometheus.yml - --storage.tsdb.retention.time=30d
yaml
# prometheus.yml global: scrape_interval: 15s scrape_configs: - job_name: 'cadvisor' static_configs: - targets: ['cadvisor:8080'] - job_name: 'docker-daemon' static_configs: - targets: ['host.docker.internal:9323'] - job_name: 'app' static_configs: - targets: ['api:3000'] metrics_path: /metrics

Prometheus скрейпить кожні 15 секунд і зберігає 30 днів метрик.

Grafana — дашборди

yaml
grafana: image: grafana/grafana:11.3.0 ports: - "3000:3000" environment: GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD} volumes: - grafana:/var/lib/grafana

Імпортуй pre-built дашборди: «Docker and System Monitoring» (ID: 893), «Docker Container & Host Metrics» (ID: 10619). П'ять кліків і у тебе повна container-observability.

Alertmanager — paging

yaml
alertmanager: image: prom/alertmanager:v0.27.0 ports: - "9093:9093" volumes: - ./alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro

Визнач alert у Prometheus, route через Alertmanager у Slack/PagerDuty/email.

Essential alerts

yaml
# rules.yml groups: - name: docker rules: - alert: ContainerDown expr: time() - container_last_seen{name!=""} > 300 for: 5m annotations: summary: "Container {{ $labels.name }} not seen for 5 minutes" - alert: ContainerHighMemory expr: container_memory_working_set_bytes / container_spec_memory_limit_bytes > 0.9 for: 10m annotations: summary: "Container {{ $labels.name }} above 90% memory" - alert: ContainerOOMKilled expr: increase(container_oom_events_total[5m]) > 0 annotations: summary: "Container {{ $labels.name }} OOM-killed in last 5 minutes" - alert: ContainerRestarting expr: increase(container_start_time_seconds[15m]) > 2 annotations: summary: "Container {{ $labels.name }} restarted >2 times in 15 minutes" - alert: ContainerUnhealthy expr: container_health_status == 0 for: 2m annotations: summary: "Container {{ $labels.name }} unhealthy for 2 minutes"

Ці п'ять покривають більшість прод-failure-mode.

Логи

Метрики кажуть, що щось не так; логи кажуть чому. Стандартні прод-стеки:

  • Loki + Promtail + Grafana — Prometheus-flavored, log-labels збігаються з metric-labels.
  • ELK (Elasticsearch + Logstash + Kibana) — важкий, але потужний search.
  • Fluentd / Fluent Bit — log-collector, шиппить будь-куди.
  • Vector — сучасна альтернатива fluentd, менший overhead.

На Docker-рівні налаштуй log-driver:

yaml
services: api: image: myapp logging: driver: json-file options: max-size: "10m" max-file: "3" # Також: tag, labels для централізованого routing

Без max-size дефолтні json-file логи ростуть нескінченно і заповнюють диск.

Health-driven моніторинг

Якщо твої container мають визначений healthcheck:, Prometheus / cAdvisor експозять container_health_status. Alert на нього. Сама логіка healthcheck це твій liveness-probe.

yaml
services: api: healthcheck: test: ["CMD", "curl", "-f", "http://localhost:3000/health"] interval: 30s retries: 3

Без healthcheck = monitoring blind spot.

Типові помилки

Жодних alert

Дашборд, на який ніхто не дивиться, це не моніторинг. Постав Alertmanager + paging з першого дня. «Ми будемо перевіряти дашборд» ніколи не працює.

Логи без retention або ротації

yaml
services: api: image: myapp # дефолтні json-file логи ростуть без межі

Через 6 місяців /var/lib/docker/containers/<id>/*-json.log може бути сотні GB. Завжди ставлять max-size і max-file.

Моніторити host-метрики, але не container-метрики

Host з 50% CPU може бути одним container на 100% CPU. Per-container метрики дозволяють знайти noisy-neighbor.

Забути скрейпити сам daemon

Docker-daemon експозить Prometheus-метрики, якщо увімкнено (/etc/docker/daemon.json: { "metrics-addr": "0.0.0.0:9323", "experimental": true }). Daemon-level метрики показують daemon-health, image push/pull rate тощо.

Ігнорувати restart count

Container з --restart=unless-stopped, що flap'ить кожні 30 секунд, виглядає «up» більшість часу, але зламаний. Change-rate container_start_time_seconds ловить це.

Реальне застосування

  • Малі/середні команди: Compose-based стек cAdvisor + Prometheus + Grafana + Loki. ~30 хвилин на setup, покриває 90% потреб.
  • Cloud-провайдери: AWS CloudWatch Container Insights, GCP Cloud Monitoring, Azure Container Insights. Managed, без setup, billed per metric.
  • Datadog / New Relic / Honeycomb: SaaS APM з Docker-інтеграцією. Платиш за зручність.
  • Kubernetes-style: Prometheus Operator + kube-state-metrics + node-exporter. Та сама ідея, K8s-native.

Питання для поглиблення

Q: Чи можна використовувати docker stats для прод-моніторингу?


A: Ні. Це live-snapshot, не TSDB. Корисно для ad-hoc inspect («чому це повільне зараз?»), безкорисно для trend або alert.

Q: Чому cAdvisor замість просто docker stats?


A: cAdvisor експозить Prometheus-endpoint, тож метрики скрейпляться, зберігаються і queryable історично. docker stats ні.

Q: Чи Docker daemon експозить метрики сам?


A: Так, якщо увімкнеш: /etc/docker/daemon.json з "metrics-addr": "0.0.0.0:9323". Тоді скрейпиш host:9323/metrics.

Q: Яка різниця між метриками і логами?


A: Метрики це aggregate через час (CPU 75% at t=12:00). Логи це події («GET /api/users 200 in 12ms at t=12:00:01»). Обидва потрібні; метрики для alert і trend, логи для debug причини.

Q: (Senior) Як кореляційно зіставляти метрики, логи і трейси у проді Docker?


A: Додай labels скрізь: container-labels (com.docker.stack=myapp), match'й їх у cAdvisor-метриках, пропагуй через Loki-labels для логів і додавай OpenTelemetry trace ID до log-рядків. View «Explore» Grafana дозволяє кликати metric-сплеск, стрибнути у логи на цій timestamp з тими ж labels, потім стрибнути у trace по trace ID. Інфраструктура: cAdvisor + Prometheus + Loki + Tempo за одним Grafana. Складна частина: добре інструментувати застосунок, не deployment.

Приклади

Compose-based monitoring-стек

yaml
services: cadvisor: image: gcr.io/cadvisor/cadvisor:v0.49.0 privileged: true devices: ["/dev/kmsg"] volumes: - /:/rootfs:ro - /var/run:/var/run:ro - /sys:/sys:ro - /var/lib/docker:/var/lib/docker:ro networks: [monitor] prometheus: image: prom/prometheus:v2.55.0 volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro - ./rules.yml:/etc/prometheus/rules.yml:ro - promdata:/prometheus ports: ["9090:9090"] networks: [monitor] grafana: image: grafana/grafana:11.3.0 ports: ["3001:3000"] environment: GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD} volumes: - grafana:/var/lib/grafana networks: [monitor] alertmanager: image: prom/alertmanager:v0.27.0 volumes: - ./alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro ports: ["9093:9093"] networks: [monitor] loki: image: grafana/loki:3.2.0 ports: ["3100:3100"] networks: [monitor] promtail: image: grafana/promtail:3.2.0 volumes: - /var/log:/var/log:ro - /var/lib/docker/containers:/var/lib/docker/containers:ro - ./promtail.yml:/etc/promtail/config.yml:ro networks: [monitor] volumes: promdata: grafana: networks: monitor:

Чотири стовпи (метрики з cAdvisor, store у Prometheus, alert через Alertmanager, дашборди у Grafana) плюс log-shipping (Promtail → Loki). Один docker compose up.

Налаштування ротації логів скрізь

yaml
# У compose.yaml твого стеку x-logging: &default-logging driver: json-file options: max-size: "10m" max-file: "3" tag: "{{.Name}}" services: api: image: myapp logging: *default-logging worker: image: myworker logging: *default-logging

YAML-anchor застосовує той самий logging-config між сервісами. Disk-використання лишається обмеженим.

Endpoint метрик daemon-рівня

json
# /etc/docker/daemon.json { "metrics-addr": "0.0.0.0:9323", "experimental": true }
bash
sudo systemctl restart docker curl http://localhost:9323/metrics | head # # HELP engine_daemon_engine_info ... # # TYPE engine_daemon_engine_info gauge # ...

Тепер Prometheus може скрейпити daemon на host:9323 для engine-level метрик.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.

Коментарі

Ще немає коментарів