Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Як моніторити Docker контейнери у production?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Прод Docker-моніторинг це стек:** cAdvisor скрейпить container-метрики → Prometheus зберігає → Grafana візуалізує → Alertmanager пейджить. Плюс log-aggregation (Loki, ELK, fluentd) і uptime-перевірки. ```yaml services: cadvisor: image: gcr.io/cadvisor/cadvisor volumes: - /:/rootfs:ro - /var/run:/var/run:ro - /sys:/sys:ro - /var/lib/docker:/var/lib/docker:ro prometheus: image: prom/prometheus # скрейпить cadvisor:8080 grafana: image: grafana/grafana ``` **Головне:** чотири сигнали важать — CPU, пам'ять, restart count, healthcheck-fails. Alert на усі чотири. Логи це окремий pipeline.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Моніторинг 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 метрик.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.