Повреждение файловой системы в persistent storage контейнера - критический инцидент, который останавливает stateful-приложения: базы данных, очереди сообщений, хранилища. В отличие от виртуальных машин, восстановление данных в средах Docker и Kubernetes требует понимания многоуровневой архитектуры хранения и точных, безопасных действий. Эта статья - практическое руководство, которое позволит вам диагностировать сбой, изолировать проблемный том, выполнить ремонт файловой системы и вернуть сервис в работу с минимальным простоем. Мы разберем конкретные команды для типовых ошибок, таких как Read-only file system, и стратегии работы с разными бэкендами: от локальных дисков до облачных EBS и сетевых NFS.
Архитектура persistent storage: где искать слабые места
Прежде чем запускать fsck, нужно понять, в каком слое стека хранения произошел сбой. Симптом в виде ошибок ввода-вывода или недоступности тома может быть вызван проблемой на уровне контейнера, узла Kubernetes, сети или внешнего хранилища. Диагностика начинается с определения этой точки.
Docker: Volumes vs Bind Mounts - разные риски потери данных
В Docker есть два основных типа постоянного хранения, и методы их восстановления различаются кардинально.
Docker Volume - сущность, управляемая демоном Docker. Данные хранятся в директории хоста, обычно /var/lib/docker/volumes/<volume_name>/_data. Риски связаны со сбоем самого демона Docker, повреждением этой директории или проблемами с драйвером тома. Восстановление часто требует доступа к этой служебной папке и проверки файловой системы на хосте.
Bind Mount - прямое монтирование директории с хоста в контейнер. Риск потери данных здесь выше, так как он напрямую зависит от состояния файловой системы хоста, прав доступа и действий администратора на самой ноде. Повреждение данных в bind mount означает повреждение данных в смонтированной директории хоста. Перед любыми операциями fsck критически важно определить тип используемого хранилища: для volume нужно найти его физическое расположение, для bind mount - путь на хосте.
Определить тип можно командой docker inspect <container_id>, изучив секцию Mounts.
Kubernetes: от StorageClass до физического диска - цепочка зависимостей
В Kubernetes цепочка доступа к данным длиннее: Pod -> PersistentVolumeClaim (PVC) -> PersistentVolume (PV) -> StorageClass -> CSI Driver/In-tree Plugin -> физический бэкенд (диск, NFS-сервер, облачный том).
Типичные точки отказа:
- Узел (Node): физический сбой сервера, где размещен PV.
- Присоединение тома (Volume Attach/Detach): сбой операции подключения диска к виртуальной машине в облаке или к ноде.
- CSI-драйвер: ошибка в работе драйвера хранилища (например, для Ceph, AWS EBS).
- Файловая система бэкенда: повреждение данных на самом диске, NFS-шаре или в объектном хранилище.
- Сеть: разрыв соединения с сетевым хранилищем (NFS, iSCSI).
Для диагностики пройдите по цепочке:
1. kubectl get pod <pod_name> -o yaml - проверьте статус пода и условия (Conditions).
2. kubectl describe pvc <pvc_name> - убедитесь, что PVC связан с PV (поле VolumeName).
3. kubectl describe pv <pv_name> - ключевой шаг. В статусе (Status) проверьте, Bound ли том. В спецификации найдите nodeAffinity или nodeName, чтобы понять, на какой ноде том примонтирован. Поле Source укажет на бэкенд (например, volumeHandle: vol-0ab1c3def456789ab для AWS EBS).
Ошибка Read-only file system в логах пода - это симптом. Причина может быть на любом из этих уровней.
Экстренный ответ: что делать при первых признаках проблем
Когда приложение сообщает об ошибках записи или чтения, первая цель - изолировать проблему и создать точку восстановления, не усугубляя повреждение данных. Действуйте по протоколу.
Создание диагностического пода: безопасный доступ к поврежденному тому
Не запускайте утилиты проверки файловой системы на работающем production-поде. Создайте изолированную среду. Самый безопасный способ - подключить проблемный PVC к специальному отладочному поду в режиме только для чтения.
Создайте манифест debug-pod.yaml:
apiVersion: v1
kind: Pod
metadata:
name: volume-debugger
spec:
volumes:
- name: damaged-volume
persistentVolumeClaim:
claimName: your-damaged-pvc-claim # Замените на имя вашего PVC
readOnly: true # Критически важный параметр!
containers:
- name: debugger
image: alpine:latest
command: [ "sleep", "3600" ]
volumeMounts:
- name: damaged-volume
mountPath: /data
Примените его: kubectl apply -f debug-pod.yaml. После запуска пода вы можете подключиться к нему и провести первичный осмотр: kubectl exec -it volume-debugger -- /bin/sh. Проверьте, смонтирован ли том (mount | grep /data), попробуйте прочитать файлы. Режим readOnly: true предотвратит случайную запись и дальнейшую порчу.
Альтернативный метод для случаев, когда нужно работать с файловой системой ноды напрямую - kubectl debug node/<node_name> -it --image=alpine. Этот способ дает доступ к хостовой системе, но требует больше прав и осторожности.
Фиксация состояния: VolumeSnapshot и другие методы резервирования
Перед любыми деструктивными операциями (такими как fsck -y) необходимо зафиксировать текущее состояние тома. Идеальный вариант - создать снапшот средствами Kubernetes, если ваш StorageClass и CSI-драйвер это поддерживают.
Пример манифеста для VolumeSnapshot:
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: rescue-snapshot-before-repair
spec:
volumeSnapshotClassName: csi-aws-vsc # Укажите ваш класс снапшотов
source:
persistentVolumeClaimName: your-damaged-pvc-claim
Если снапшоты не поддерживаются (например, для некоторых NFS-бэкендов), создайте резервную копию данных с смонтированного в read-only режиме тома внутри диагностического пода. Используйте tar или dd для копирования на другой, заведомо исправный том или в объектное хранилище.
Пример команды внутри отладочного пода:
tar czf /backup/volume-backup-$(date +%Y%m%d-%H%M).tar.gz -C /data .
Только после создания резервной копии или снапшота можно переходить к активным действиям по восстановлению.
Практикум: команды восстановления для типовых сценариев
Здесь приведены конкретные команды для распространенных сценариев. Предполагается, что том изолирован и подключен к диагностическому поду или хосту, а его состояние зафиксировано.
Ошибка 'Read-only file system': снятие флагов и принудительная проверка
Эта ошибка означает, что файловая система смонтирована в режиме только для чтения. Это может быть как следствие ошибок ввода-вывода на диске (тогда ядро переводит ФС в readonly для безопасности), так и проблема с монтированием в Kubernetes.
Алгоритм действий внутри диагностического пода или на ноде, где физически находится диск:
- Определите устройство: Найдите, какое блочное устройство соответствует вашему тому. Внутри пода выполните
df -h /data. На хосте найдите устройство по точке монтирования или черезlsblk. - Проверьте журналы ядра: Выполните
dmesg | grep -i errorилиdmesg | grep -i <device_name>(например,xvdf1). Ищите ошибки диска типаI/O error,buffer I/O error. - Принудительно размонтируйте: Если ФС смонтирована в read-only, её нужно размонтировать для проверки. Убедитесь, что никакие процессы не используют том.
lsof /dataилиfuser -vm /data. Затем размонтируйте:umount -f /data(флаг-fдля принудительного размонтирования). - Запустите проверку ФС: Определите тип файловой системы:
blkid /dev/<device_name>илиlsblk -f /dev/<device_name>.- Для ext2/ext3/ext4:
fsck -y /dev/<device_name>. Ключ-yавтоматически отвечает «yes» на все запросы исправления. - Для XFS:
xfs_repair /dev/<device_name>. XFS не имеет аналогаfsck -y, но для принудительного размонтирования может потребоваться ключ-L(сбрасывает журнал, используйте с крайней осторожностью).
- Для ext2/ext3/ext4:
- Перемонтируйте в режиме read-write:
mount -o rw /dev/<device_name> /data.
Восстановление после внезапной перезагрузки ноды: проверка целостности ФС
Внезапное отключение питания ноды Kubernetes может привести к повреждению файловых систем на persistent volumes. После перезагрузки ноды и перед запуском подов рекомендуется провести проверку.
На самой ноде выполните:
- Определите тома, которые были примонтированы на этой ноде:
cat /proc/mounts | grep /var/lib/kubelet/podsили проанализируйте выводmount. - Для каждого устройства, связанного с PV, выполните проверку в режиме «только проверка» сначала:
fsck -n /dev/<device>. Это покажет ошибки без внесения изменений. - Если ошибки найдены, и вы уверены, что на томах нет активных процессов, выполните полный ремонт:
fsck -y /dev/<device>илиxfs_repair /dev/<device>.
Особое внимание для StatefulSet с базами данных: Простая проверка fsck может привести к логической несогласованности данных СУБД. Для таких случаев предпочтительнее восстановление из снапшота тома, созданного до инцидента, или использование встроенных механизмов восстановления СУБД (например, pg_resetwal для PostgreSQL).
Повреждение метаданных (inode, superblock): продвинутое восстановление
Если стандартный fsck не может исправить ошибки или сообщает о повреждении суперблока, требуются продвинутые методы.
Для ext4:
1. Найдите резервные копии суперблока: mkfs.ext4 -n /dev/<device> (ключ -n не форматирует, а только показывает информацию). В выводе найдите строку «Backup superblocks at...».
2. Попробуйте восстановить файловую систему, используя один из backup superblock: fsck -b 32768 /dev/<device> (где 32768 - номер backup superblock).
Для XFS:
Инструмент xfs_repair обычно справляется с большинством повреждений. В крайнем случае, если он не работает, можно попробовать ключ -L для сброса журнала: xfs_repair -L /dev/<device>. Внимание: Эта операция может привести к потере последних изменений и увеличивает риск потери данных. Всегда предварительно создавайте полную побитовую копию диска с помощью dd if=/dev/<device> of=/backup/disk.img bs=1M status=progress.
Для комплексного управления томами Docker, включая их визуальный осмотр и мониторинг, может быть полезен графический интерфейс. В статье «Управление томами Docker в Portainer: полный визуальный гайд для DevOps и сисадминов» подробно разбираются практические сценарии работы с хранилищем через Portainer.
Восстановление работы с разными бэкендами: NFS, iSCSI, облачные диски
Процедура восстановления сильно зависит от типа используемого хранилища. Для сетевых и облачных решений фокус смещается с локальной проверки ФС на диагностику сервера или провайдера.
NFS тома: проверка сервера и обработка stale file handle
Если ваш PersistentVolume использует бэкенд NFS, ошибки чаще всего возникают на стороне сервера или сети.
Диагностика на стороне клиента (ноды Kubernetes):
- Проверьте доступность NFS-сервера:
showmount -e <nfs_server_ip>. - Убедитесь, что открыты необходимые порты (обычно 2049):
nc -zv <nfs_server_ip> 2049. - Проверьте текущие NFS-монтирования на ноде:
mount | grep nfs.
Ошибка «Stale NFS file handle» означает, что клиент пытается получить доступ к файлу или директории, которые были удалены или изменены на сервере. Решение на клиенте:
# Принудительное ленивое размонтирование (lazy unmount)
umount -f -l /path/to/nfs/mount
# Затем повторное монтирование
mount -t nfs <nfs_server_ip>:/export/path /path/to/nfs/mount
Основные действия для устранения причины - на стороне NFS-сервера: перезапуск служб nfs-server, проверка целостности экспортируемой файловой системы, анализ логов /var/log/messages или journalctl.
Облачные диски (AWS EBS, GCP PD, Azure Disk): снапшоты и переподключение
Прямой запуск fsck на облачном диске, подключенном к виртуальной машине, возможен, но стандартный flow восстановления в облаке завязан на снапшоты.
Алгоритм для AWS EBS (аналогичен для GCP Persistent Disk и Azure Disk):
- Создайте снапшот поврежденного тома. Сделайте это через AWS Console, CLI (
aws ec2 create-snapshot --volume-id vol-12345) или, если настроено, через Kubernetes VolumeSnapshot. - Создайте новый том из этого снапшота. В консоли AWS это действие «Create Volume from Snapshot». Задайте тот же тип и размер (или больше).
- Обновите PersistentVolume в Kubernetes. Нужно изменить PV так, чтобы он ссылался на новый volumeID. Если PV создавался динамически через StorageClass, проще удалить старый PVC/PV и создать новые, указав в PVC
volumeNameнового PV. Для StatefulSet с автоматическим созданием томов это может быть сложнее - может потребоваться ручное редактирование PV или использование операторов, таких как специализированных для резервного копирования.
Этот метод безопасен, так как исходный поврежденный диск остается нетронутым в качестве последней резервной копии.
Плановые операции: миграция и вывод нод из эксплуатации без потерь
Многие аварийные ситуации можно предотвратить, правильно выполняя плановые работы, такие как обновление кластера или замена оборудования.
Drain ноды Kubernetes с PersistentVolumes: пошаговый алгоритм
Безопасный вывод ноды из эксплуатации при наличии stateful-подов с локальными томами (с volumeMode: Filesystem и привязкой к ноде через nodeAffinity) требует осторожности.
- Установите кордон (cordon) на ноду: Это предотвратит планирование новых подов на эту ноду.
kubectl cordon <node_name> - Используйте drain с учетом DaemonSet и локальных данных:
kubectl drain <node_name> --ignore-daemonsets --delete-emptydir-data
Флаг--delete-emptydir-dataудалит данные из временных томов EmptyDir. Для persistent volumes он безопасен - данные останутся на диске. - Если под с PVC завис в статусе
Terminating, это часто связано с проблемой окончательного отсоединения тома (finalizer). Можно попробовать принудительно удалить под:
kubectl delete pod <pod_name> --grace-period=0 --force --namespace <namespace>
После этого проверьте, что том освободился:kubectl describe pv <pv_name>. Статус должен смениться сReleasedнаAvailable. - Для переноса тома на другую ноду (если используется локальное хранилище и это допустимо) необходимо вручную обновить
nodeAffinityв спецификации PV, указав новую целевую ноду, а затем пересоздать Pod (или StatefulSet), который будет использовать этот PVC.
Для глубокого понимания различий в управлении данными между оркестраторами изучите сравнительное руководство по persistent данным в Docker Swarm и Kubernetes.
Проактивный мониторинг: какие метрики смотреть, чтобы предсказать сбой
Настройка алертинга позволяет реагировать на проблемы до того, как они приведут к повреждению данных или простою.
Ключевые метрики Prometheus для мониторинга хранилища на нодах:
node_filesystem_avail_bytes / node_filesystem_size_bytes- процент свободного места на файловой системе. Настройте алерт при заполнении более чем на 85%.node_filesystem_readonly- метрика, принимающая значение 1, если ФС смонтирована в режиме только для чтения. Это прямой предвестник серьезных проблем с диском.node_disk_io_time_seconds_total- время, затраченное на ввод/вывод. Резкий рост может указывать на проблемы с диском.node_disk_io_error_total- счетчик ошибок ввода-вывода.
Пример правила Alertmanager для алерта на read-only ФС:
- alert: FilesystemReadOnly
expr: node_filesystem_readonly{mountpoint!~"^/(sys|proc|run|dev).*"} == 1
for: 2m
labels:
severity: critical
annotations:
summary: "Файловая система в read-only режиме на {{ $labels.instance }}"
description: "Монтирование {{ $labels.mountpoint }} переведено в режим только для чтения. Требуется немедленная проверка диска."
Идея: при срабатывании такого алерта можно автоматически запускать скрипт, который создает VolumeSnapshot проблемного тома через Kubernetes API, фиксируя его состояние для последующего анализа.
Чек-лист и готовые решения для production
Чек-лист действий при обнаружении повреждения данных в томе:
- Изолировать. Остановить Pod (StatefulSet) или выставить replicas=0. Не пытаться рестартовать приложение.
- Зафиксировать. Создать снапшот тома (VolumeSnapshot) или полную файловую копию (tar/dd) в режиме read-only.
- Диагностировать. Подключить том в режиме read-only к диагностическому поду. Определить тип сбоя (ошибка ФС, сеть, бэкенд) с помощью
dmesg,kubectl describe pv/pvc, проверки доступности бэкенда. - Восстановить. В зависимости от диагноза: запустить
fsck/xfs_repair, переподключить сетевой ресурс, восстановить из снапшота или резервной копии. - Протестировать. Развернуть тестовый под с восстановленным томом, проверить целостность данных и работу приложения.
- Вернуть в работу. Запустить production-под.
Рекомендации по архитектуре для минимизации рисков:
- Выбор StorageClass: Для production-нагрузок избегайте тома
hostPath. Используйте реплицируемые решения (Ceph Rook, Longhorn, облачные managed-диски с автоматическими снапшотами) или, как минимум, Network-Attached Storage (NFS от надежного сервера). - Резервное копирование: Настройте регулярное создание снапшотов томов через Velero в сочетании с снапшотами хранилища. Имейте оттестированный план восстановления.
- Отказоустойчивые файловые системы: Рассмотрите использование томов с ФС, поддерживающими снапшоты и самовосстановление, таких как ZFS или btrfs, поверх базовых блочных устройств.
Восстановление поврежденного persistent storage - сложная, но решаемая задача. Ключ к успеху - методичный подход: изоляция, резервирование, точная диагностика и применение правильного инструмента для конкретного бэкенда. Интеграция процедур мониторинга и создания снапшотов в ваши runbooks превратит экстренный ремонт в управляемый операционный процесс.
Для автоматизации рутинных задач обслуживания Docker, включая освобождение места, которое может косвенно влиять на работу storage, используйте готовые скрипты для безопасной очистки. А для построения отказоустойчивой production-среды ознакомьтесь с полным руководством по Docker в production.