Почему мониторинг дисков в контейнерах - это критично
Заполненный до нуля диск на узле Kubernetes или Docker-хосте - это не предупреждение, а уже авария. Pod'ы переходят в статус Evicted или CrashLoopBackOff, контейнеры теряют возможность писать логи, базы данных останавливаются с ошибкой 'No space left on device'. Восстановление занимает часы, а причина часто банальна: закончилось место на Persistent Volume или раздулся каталог /var/lib/docker.
Практика показывает три типовых сценария. Первый: разработчик развернул приложение с записью логов внутрь контейнера без ротации, и через неделю PV на 20 ГБ заполнен под завязку. Второй: CI/CD пайплайн собирает образы, а старые не удаляются - Docker-хост уходит в отказ. Третий: StatefulSet с PostgreSQL работает без мониторинга, и в пиковый момент база падает из-за нехватки места под WAL-файлы. Каждый из этих сценариев предотвращается за 15 минут настройки.
Стек для полного контроля дискового пространства выглядит так: cAdvisor собирает метрики использования файловой системы контейнеров, kube-state-metrics отдаёт состояние Persistent Volumes и Persistent Volume Claims, Node Exporter показывает занятость дисков на уровне узлов. Prometheus агрегирует все метрики, а Alertmanager рассылает оповещения до того, как место закончится. В этом руководстве - проверенная на рабочих средах инструкция по развёртыванию и настройке каждого компонента.
Если вы ещё не знакомы с базовым мониторингом контейнеров, начните с нашего руководства по мониторингу Docker-контейнеров для продакшена. Там разобраны основы Prometheus, Grafana и Loki, которые мы используем здесь как данность.
Архитектура мониторинга: кто за что отвечает
Мониторинг дисков в контейнерной среде требует трёх уровней сбора метрик: уровень контейнера, уровень оркестрации и уровень узла. Каждый уровень закрывает свой экспортер, и путать их зоны ответственности - верный путь пропустить критичный инцидент.
cAdvisor: мониторинг контейнеров изнутри
cAdvisor (Container Advisor) - это агент с открытым исходным кодом, встроенный в kubelet и доступный как standalone-контейнер для Docker. Он анализирует cgroups и выдаёт детальные метрики по каждому контейнеру: использование CPU, памяти, сети и файловой системы.
Для мониторинга дисков ключевые метрики cAdvisor:
- container_fs_usage_bytes - фактически занятое место файловой системой контейнера (слои образа плюс записанные данные);
- container_fs_limit_bytes - лимит, установленный для контейнера (размер диска узла или квота);
- container_fs_writes_bytes_total - счётчик записанных байт, полезен для выявления аномальной активности записи.
cAdvisor интегрируется с Docker автоматически: он монтирует сокет Docker и читает данные напрямую из демона. В Kubernetes kubelet запускает cAdvisor на каждом узле по умолчанию, и метрики доступны через API kubelet на порту 10250. Ограничение: cAdvisor видит только файловую систему контейнера, но не имеет информации о Persistent Volumes, смонтированных через CSI-драйверы. Для PV нужен отдельный инструмент.
kube-state-metrics и Node Exporter: покрытие Kubernetes
kube-state-metrics - это сервис, который слушает API Kubernetes и генерирует метрики о состоянии объектов кластера: подов, деплойментов, нод, PV и PVC. Он не смотрит внутрь контейнеров, а опрашивает control plane. Для дисков это означает:
- kube_persistentvolume_capacity_bytes - общая ёмкость PV;
- kube_persistentvolume_status_phase - статус тома (Available, Bound, Released, Failed);
- kube_persistentvolumeclaim_resource_requests_storage_bytes - запрошенный размер PVC.
Эти метрики критичны для обнаружения PV, которые скоро заполнятся, или PVC, которые не могут зарезервировать том. kube-state-metrics не показывает, сколько места занято внутри PV - только ёмкость и статус. Фактическое использование даёт cAdvisor или агент внутри пода.
Node Exporter закрывает третий уровень - метрики самого узла. Он работает как DaemonSet на каждой ноде и отдаёт:
- node_filesystem_avail_bytes - доступное место на файловой системе;
- node_filesystem_size_bytes - общий размер;
- node_filesystem_free_bytes - свободное место (с учётом зарезервированных блоков);
- node_disk_io_time_seconds_total - время операций ввода-вывода.
Разница между метриками контейнеров и инфраструктуры принципиальна. container_fs_usage_bytes показывает, сколько занято внутри образа контейнера. node_filesystem_avail_bytes - сколько осталось на физическом диске. Если первое растёт, проблема в приложении. Если второе падает - проблема на уровне хоста: логи, снапшоты, временные файлы.
Prometheus агрегирует все три источника метрик по единой модели: pull-сбор с интервалом 15-30 секунд, хранение в TSDB, оценка правил алертинга. Alertmanager получает алерты от Prometheus, группирует, маршрутизирует и отправляет в Slack, Telegram, email или PagerDuty. Схема взаимодействия линейна: экспортеры → Prometheus → Alertmanager → канал уведомлений.
Для глубокого понимания метрик всего кластера, включая нагрузку на CPU и сеть, обратитесь к нашему руководству по мониторингу кластеров серверов. Там разобраны дашборды Grafana и специфичные решения для HA-кластеров.
Настройка мониторинга дисков в Docker с помощью cAdvisor и Prometheus
Для standalone Docker-хоста связка cAdvisor + Prometheus - минимально достаточное решение. cAdvisor собирает метрики со всех контейнеров, Prometheus сохраняет и оценивает их. Разворачивается за 5 минут через Docker Compose.
Запуск cAdvisor через Docker Compose
Создайте файл docker-compose.yml в отдельной директории, например /opt/monitoring:
version: '3.8'
services:
cadvisor:
image: gcr.io/cadvisor/cadvisor:v0.47.2
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
- /dev/disk/:/dev/disk:ro
privileged: true
devices:
- /dev/kmsg
prometheus:
image: prom/prometheus:v2.52.0
container_name: prometheus
restart: unless-stopped
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--storage.tsdb.retention.time=15d'
volumes:
prometheus_data:Маппинг томов для cAdvisor критичен: /rootfs даёт доступ ко всей файловой системе хоста (read-only), /var/run - к сокету Docker, /sys - к cgroups, /var/lib/docker - к данным контейнеров. Без privileged: true и /dev/kmsg cAdvisor не сможет читать системные метрики. Порт 8080 используется для веб-интерфейса и отдачи метрик Prometheus по эндпоинту /metrics.
Запустите стек командой:
docker-compose up -dПроверьте, что cAdvisor отдаёт метрики: curl http://localhost:8080/metrics | grep container_fs_usage_bytes. Вы увидите строки с лейблами контейнеров и текущими значениями в байтах.
Интеграция cAdvisor с Prometheus
Создайте файл prometheus.yml рядом с docker-compose.yml:
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'cadvisor'
static_configs:
- targets: ['cadvisor:8080']
metric_relabel_configs:
- source_labels: ['container_label_com_docker_compose_service']
target_label: 'service'
- source_labels: ['container_label_com_docker_compose_project']
target_label: 'project'job_name 'cadvisor' указывает Prometheus опрашивать контейнер cadvisor по внутреннему DNS-имени в сети Docker Compose. metric_relabel_configs упрощают лейблы: вместо длинных container_label_com_docker_compose_service вы получаете короткий service. После перезапуска Prometheus (docker-compose restart prometheus) проверьте targets в веб-интерфейсе http://localhost:9090/targets - статус cadvisor должен быть UP.
Пример PromQL-запроса для получения процента использования диска конкретным контейнером:
(container_fs_usage_bytes{name="myapp"} / container_fs_limit_bytes{name="myapp"}) * 100Этот запрос вернёт процент заполнения файловой системы контейнера myapp. Используйте его для отладки или как основу для правила алертинга.
Мониторинг дисков в Kubernetes: установка kube-state-metrics и Node Exporter
В кластере Kubernetes мониторинг дисков требует двух дополнительных экспортеров: kube-state-metrics для объектов PV/PVC и Node Exporter для метрик узлов. Оба устанавливаются через Helm - это стандартный и поддерживаемый способ.
Установка kube-state-metrics
Добавьте репозиторий и установите чарт в namespace monitoring:
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
helm install kube-state-metrics prometheus-community/kube-state-metrics \
--namespace monitoring \
--create-namespace \
--set metricLabelsAllowlist='pods=[*],persistentvolumes=[*],persistentvolumeclaims=[*]'Параметр metricLabelsAllowlist важен: по умолчанию kube-state-metrics не добавляет все лейблы к метрикам для экономии ресурсов. Для мониторинга дисков нужны лейблы persistentvolume и persistentvolumeclaim - они позволяют связать PV с PVC и пространством имён. Проверьте, что поды запустились:
kubectl get pods -n monitoring -l app.kubernetes.io/name=kube-state-metricsЕсли Prometheus Operator уже развёрнут в кластере, kube-state-metrics автоматически создаст ServiceMonitor. Проверьте в Prometheus UI (обычно доступен через порт-форвард: kubectl port-forward -n monitoring svc/prometheus-kube-prometheus-prometheus 9090) по адресу /targets - фильтр по job kube-state-metrics покажет все эндпоинты.
Настройка сбора метрик Persistent Volumes
Ключевая метрика для алертинга - процент заполнения PV. Прямого показателя использования внутри PV у kube-state-metrics нет, но есть ёмкость. Фактическое использование получают через cAdvisor (kubelet) или sidecar-агент. PromQL-запрос для расчёта процента заполнения PV, смонтированного в под:
(kubelet_volume_stats_used_bytes / kubelet_volume_stats_capacity_bytes) * 100kubelet_volume_stats_used_bytes - это метрика kubelet, доступная в Prometheus при сборе метрик с узлов. Она показывает, сколько байт занято внутри PV. Для сопоставления с PVC используйте лейбл persistentvolumeclaim. Пример запроса с фильтрацией по namespace:
(kubelet_volume_stats_used_bytes{namespace="production"}
/ kubelet_volume_stats_capacity_bytes{namespace="production"}) * 100Этот запрос вернёт процент заполнения для каждого PV в namespace production. Значение выше 80% - повод для предупреждения, выше 90% - критический алерт.
Развертывание Node Exporter для метрик узлов
Node Exporter устанавливается как DaemonSet - по одному поду на каждый узел кластера. Используйте официальный чарт:
helm install node-exporter prometheus-community/prometheus-node-exporter \
--namespace monitoring \
--set prometheus.monitor.enabled=true \
--set prometheus.monitor.relabelings[0].targetLabel=node \
--set prometheus.monitor.relabelings[0].replacement='${1}' \
--set prometheus.monitor.relabelings[0].sourceLabels[0]=__meta_kubernetes_pod_node_nameФлаг prometheus.monitor.enabled=true создаёт ServiceMonitor для автоматического обнаружения Prometheus Operator. После установки проверьте метрики в Prometheus UI запросом node_filesystem_avail_bytes. Лейбл mountpoint позволяет отфильтровать системные разделы и оставить только значимые, например /var/lib/docker или /data:
node_filesystem_avail_bytes{mountpoint="/var/lib/docker"}Для алертинга используйте процент доступного места: (node_filesystem_avail_bytes / node_filesystem_size_bytes) * 100. Значение ниже 20% - предупреждение, ниже 10% - критический алерт.
Если вам нужен мониторинг дисков на уровне операционной системы без контейнеров, посмотрите наше руководство по мониторингу дисков в Linux. Там разобраны Zabbix, Netdata и другие инструменты.
Настройка оповещений о нехватке дискового пространства в Alertmanager
Метрики без алертов - это архив. Настройка оповещений превращает мониторинг из пассивного наблюдения в активную защиту от инцидентов. Prometheus оценивает правила алертинга каждые 15 секунд (или согласно evaluation_interval), и при срабатывании условия отправляет алерт в Alertmanager.
Правила алертинга для дисков
Создайте манифест PrometheusRule с алертами для трёх уровней: узел, Persistent Volume и контейнер Docker. Пример для Kubernetes с Prometheus Operator:
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: disk-space-alerts
namespace: monitoring
spec:
groups:
- name: disk-space
rules:
- alert: NodeDiskSpaceUsageHigh
expr: |
(node_filesystem_avail_bytes{mountpoint="/"}
/ node_filesystem_size_bytes{mountpoint="/"}) * 100 < 20
for: 5m
labels:
severity: warning
annotations:
summary: "Дисковое пространство на узле {{ $labels.instance }} заканчивается"
description: "Доступно {{ $value | humanize }}% на разделе {{ $labels.mountpoint }}."
- alert: NodeDiskSpaceUsageCritical
expr: |
(node_filesystem_avail_bytes{mountpoint="/"}
/ node_filesystem_size_bytes{mountpoint="/"}) * 100 < 10
for: 1m
labels:
severity: critical
annotations:
summary: "Критически мало места на узле {{ $labels.instance }}"
description: "Осталось {{ $value | humanize }}% на разделе {{ $labels.mountpoint }}. Немедленно примите меры."
- alert: PersistentVolumeUsageHigh
expr: |
(kubelet_volume_stats_used_bytes
/ kubelet_volume_stats_capacity_bytes) * 100 > 80
for: 10m
labels:
severity: warning
annotations:
summary: "Persistent Volume {{ $labels.persistentvolumeclaim }} заполнен на {{ $value | humanize }}%"
description: "PVC {{ $labels.persistentvolumeclaim }} в namespace {{ $labels.namespace }} превысил порог 80%."
- alert: PersistentVolumeUsageCritical
expr: |
(kubelet_volume_stats_used_bytes
/ kubelet_volume_stats_capacity_bytes) * 100 > 90
for: 5m
labels:
severity: critical
annotations:
summary: "Persistent Volume {{ $labels.persistentvolumeclaim }} заполнен критически"
description: "PVC {{ $labels.persistentvolumeclaim }} в namespace {{ $labels.namespace }} превысил 90%. Возможна остановка подов."
- alert: ContainerDiskUsageHigh
expr: |
(container_fs_usage_bytes{name=~".+"}
/ container_fs_limit_bytes{name=~".+"}) * 100 > 85
for: 5m
labels:
severity: warning
annotations:
summary: "Контейнер {{ $labels.name }} использует {{ $value | humanize }}% диска"
description: "Файловая система контейнера {{ $labels.name }} на хосте {{ $labels.instance }} заполнена."Ключевые моменты в правилах: for указывает, сколько времени условие должно выполняться до отправки алерта - это фильтрует кратковременные всплески. severity разделяет warning и critical для маршрутизации: warning идёт в общий канал, critical - в срочный (PagerDuty, телефон).
Конфигурация Alertmanager и каналы уведомлений
Пример alertmanager.yml с маршрутизацией по severity и каналами в Slack и email:
global:
slack_api_url: 'https://hooks.slack.com/services/YOUR/WEBHOOK/URL'
route:
receiver: 'slack-warnings'
routes:
- match:
severity: critical
receiver: 'slack-critical'
repeat_interval: 5m
- match:
severity: warning
receiver: 'slack-warnings'
repeat_interval: 30m
receivers:
- name: 'slack-warnings'
slack_configs:
- channel: '#monitoring-warnings'
title: '{{ .GroupLabels.alertname }}'
text: '{{ range .Alerts }}{{ .Annotations.summary }}
{{ .Annotations.description }}
{{ end }}'
- name: 'slack-critical'
slack_configs:
- channel: '#monitoring-critical'
title: '[CRITICAL] {{ .GroupLabels.alertname }}'
text: '{{ range .Alerts }}{{ .Annotations.summary }}
{{ .Annotations.description }}
{{ end }}'
- name: 'email'
email_configs:
- to: 'devops@example.com'
from: 'alertmanager@example.com'
smarthost: 'smtp.example.com:587'
auth_username: 'alertmanager@example.com'
auth_password: 'password'Маршрутизация построена на лейбле severity: critical-алерты уходят в канал #monitoring-critical с повтором каждые 5 минут, warning - в #monitoring-warnings с интервалом 30 минут. repeat_interval определяет, как часто Alertmanager будет напоминать о неразрешённом алерте.
Для проверки работоспособности отправьте тестовый алерт через API Alertmanager (порт 9093):
curl -X POST http://alertmanager:9093/api/v1/alerts \
-H 'Content-Type: application/json' \
-d '[{"labels":{"alertname":"TestAlert","severity":"critical"},"annotations":{"summary":"Тестовый алерт","description":"Проверка канала уведомлений"}}]'В канале Slack должно появиться сообщение. Если нет - проверьте логи Alertmanager: docker logs alertmanager или kubectl logs -n monitoring alertmanager-0.
Типовые причины заполнения дисков и как их избежать
Алерты сообщают о проблеме, когда она уже возникла. Профилактика устраняет причины. Три главных источника заполнения дисков в контейнерных средах: логи, образы и неочищаемые тома.
Логи контейнеров. Docker по умолчанию использует драйвер json-file без ограничения размера. Контейнер, пишущий в stdout/stderr, может занять весь диск за сутки. Решение - настройка log rotation в демоне Docker (/etc/docker/daemon.json):
{
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "3"
}
}После изменения конфигурации перезапустите Docker: systemctl restart docker. Для Kubernetes настройте ротацию через kubelet (флаг --container-log-max-size и --container-log-max-files) или используйте централизованный сбор логов в Loki - это подробно разобрано в нашем гайде по деплою Docker в production.
Накопление образов. CI/CD пайплайны собирают образы, старые версии остаются на хосте. Команда docker system df показывает использование диска Docker-объектами. Очистка: docker system prune -a -f удаляет все неиспользуемые образы, контейнеры и тома. Добавьте эту команду в cron на ежедневное выполнение. В Kubernetes следите за образами через garbage collection kubelet (настраивается флагами --image-gc-high-threshold и --image-gc-low-threshold).
Неочищаемые Persistent Volumes. PV с политикой Retain после удаления PVC остаются в статусе Released и не освобождают место. Администратор должен вручную удалить PV и очистить данные на стороне хранилища. Настройте мониторинг PV в статусе Released через метрику kube_persistentvolume_status_phase и алерт на долго висящие тома.
Рекомендации по лимитам. Устанавливайте resource.requests.storage для PVC - это предотвращает резервирование избыточного места. Для контейнеров без PV задавайте размер временного хранилища через ephemeral-storage limits в спецификации пода. Это защитит узел от контейнера, который внезапно начал писать данные на локальный диск.
Заключение: полный цикл мониторинга дисков
Вы развернули cAdvisor для метрик контейнеров, kube-state-metrics для состояния PV и PVC, Node Exporter для дисков узлов. Prometheus собирает метрики со всех трёх источников, Alertmanager рассылает оповещения о заполнении до того, как место закончится. Архитектура покрывает все уровни: контейнер, оркестрация, инфраструктура.
Следующий шаг - визуализация. Импортируйте дашборд Node Exporter Full (ID 1860) в Grafana для отображения дисковой статистики узлов в реальном времени. Для Kubernetes используйте дашборд Kubernetes Compute Resources Persistent Volume (ID 11074). Оба доступны на grafana.com и показывают тренды заполнения за дни и недели - это помогает прогнозировать, когда место закончится.
Проверьте настройки на тестовом стенде: заполните PV тестовыми данными, убедитесь, что алерт приходит в Slack. Настройте repeat_interval в Alertmanager так, чтобы вас не засыпало повторными уведомлениями, но и не пропустить эскалацию. Для продвинутых сценариев алертинга и наблюдаемости высоконагруженных систем обратитесь к нашему руководству по наблюдаемости для высоконагруженных систем - там разобраны SRE-практики и GitOps-подход к мониторингу.
Если вам нужна облачная инфраструктура для развёртывания этого стека, обратите внимание на Timeweb Cloud - они предоставляют Kubernetes и VDS с гибким масштабированием ресурсов. Для автоматизации создания контента и SEO-продвижения вашей базы знаний используйте LidBiz - сервис автоматической генерации и публикации материалов.