Kubernetes

Теория: Volume и постоянное хранилище

Контейнеры в Kubernetes эфемерны — при перезапуске Pod все данные в файловой системе контейнера теряются. Для приложений, которым нужно сохранять данные между перезапусками, эта модель не подходит. База данных потеряет все записи, файловое хранилище лишится загруженных файлов, логи исчезнут. Volume решает эту проблему, предоставляя механизм для хранения данных вне жизненного цикла контейнера.

Проблема эфемерного хранилища

Представьте веб-приложение, которое позволяет пользователям загружать изображения. Файлы сохраняются в директорию /uploads внутри контейнера. Всё работает, пока Pod не перезапустится из-за обновления или сбоя. После перезапуска все загруженные файлы исчезают — контейнер создаётся с чистой файловой системой.

Другой сценарий: база данных PostgreSQL хранит данные в /var/lib/postgresql/data. Каждый перезапуск Pod — это потеря всей базы данных.

Volume позволяет монтировать хранилище, которое существует независимо от жизненного цикла контейнера. Данные сохраняются при перезапуске Pod и могут разделяться между несколькими контейнерами в одном Pod.

emptyDir: временное хранилище

Простейший тип Volume — emptyDir. Kubernetes создаёт пустую директорию при создании Pod. Директория существует, пока существует Pod. При удалении Pod данные теряются.

Зачем нужен, если данные всё равно теряются? Для обмена данными между контейнерами в одном Pod:

apiVersion: v1
kind: Pod
metadata:
  name: shared-data
spec:
  containers:
    - name: writer
      image: busybox
      command: ["sh", "-c", "echo 'Hello from writer' > /data/message.txt && sleep 3600"]
      volumeMounts:
        - name: shared
          mountPath: /data
    - name: reader
      image: busybox
      command: ["sh", "-c", "sleep 5 && cat /data/message.txt && sleep 3600"]
      volumeMounts:
        - name: shared
          mountPath: /data
  volumes:
    - name: shared
      emptyDir: {}

Контейнер writer пишет файл, контейнер reader его читает. Оба видят одну и ту же директорию.

Для кеша или временных файлов, которые нужны только во время работы Pod, можно использовать память:

volumes:
  - name: cache
    emptyDir:
      medium: Memory
      sizeLimit: 128Mi

Данные хранятся в RAM — быстро, но исчезают при перезапуске.

hostPath: директория на ноде

hostPath монтирует директорию с ноды в контейнер:

volumes:
  - name: host-data
    hostPath:
      path: /var/log/app
      type: DirectoryOrCreate

Не используйте hostPath для данных приложений. Это создаёт жёсткую привязку к конкретной ноде — Pod не может переехать на другую ноду, данные доступны только локально.

hostPath нужен для системных задач:

  • Доступ к логам ноды
  • Доступ к Docker socket (/var/run/docker.sock)
  • Мониторинг и агенты, которым нужен доступ к файловой системе ноды

Для обычных приложений используйте PersistentVolume.

PersistentVolume и PersistentVolumeClaim

Для постоянного хранилища Kubernetes использует два объекта:

PersistentVolume (PV) — ресурс хранения в кластере. Это может быть диск в облаке (AWS EBS, GCE Persistent Disk), сетевое хранилище (NFS), или локальный диск. PV существует независимо от Pod.

PersistentVolumeClaim (PVC) — запрос на хранилище от приложения. Разработчик создаёт PVC, указывая «мне нужно 10GB с доступом ReadWriteOnce». Kubernetes находит подходящий PV и связывает их.

Такое разделение позволяет разработчикам не знать детали инфраструктуры. Разработчик запрашивает хранилище, администратор заранее готовит PV нужных типов.

Создание PV:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: local-pv
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: local-storage
  hostPath:
    path: /mnt/data

Для minikube используем hostPath. В реальном кластере здесь будет облачный диск или сетевое хранилище.

Режимы доступа:

  • ReadWriteOnce (RWO) — чтение/запись на одной ноде
  • ReadOnlyMany (ROX) — только чтение на многих нодах
  • ReadWriteMany (RWX) — чтение/запись на многих нодах

Не все типы хранилищ поддерживают все режимы. AWS EBS — только RWO. NFS — все три.

Создание PVC (делает разработчик):

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: app-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
  storageClassName: local-storage

Kubernetes найдёт PV с подходящим storageClassName, размером и режимом доступа, и свяжет их.

Использование PVC в Pod:

apiVersion: v1
kind: Pod
metadata:
  name: app-with-storage
spec:
  containers:
    - name: app
      image: busybox
      command: ["sh", "-c", "echo 'Data persists!' > /data/test.txt && sleep 3600"]
      volumeMounts:
        - name: storage
          mountPath: /data
  volumes:
    - name: storage
      persistentVolumeClaim:
        claimName: app-pvc

Данные в /data переживут перезапуск Pod.

StorageClass: автоматическое создание PV

Ручное создание PV неудобно. StorageClass позволяет автоматически создавать PV по требованию.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast
provisioner: k8s.io/minikube-hostpath
reclaimPolicy: Delete

volumeBindingMode: Immediate

Теперь при создании PVC с storageClassName: fast Kubernetes автоматически создаст PV нужного размера.

В облаках используются провайдеры хранилищ:

  • AWS: kubernetes.io/aws-ebs
  • GCP: kubernetes.io/gce-pd
  • Azure: kubernetes.io/azure-disk

Политики освобождения (reclaimPolicy):

  • Retain — при удалении PVC данные сохраняются, PV переходит в статус Released. Администратор должен вручную очистить данные. Используйте для важных данных.
  • Delete — при удалении PVC удаляется и PV, и физическое хранилище. Удобно для тестовых окружений, опасно для production.

Частые ошибки

  • PVC в статусе Pending — нет подходящего PV. Проверьте storageClassName, размер и режим доступа. Используйте kubectl describe pvc <name> для деталей.
  • Pod не стартует, ждёт Volume — PVC не привязан к PV. Проверьте kubectl get pvc.
  • Данные пропали после перезапуска — вы использовали emptyDir вместо PVC, или PV был удалён вместе с данными (политика Delete).
  • Pod не может переехать на другую ноду — используете hostPath или локальный PV. Для миграции Pod между нодами нужно сетевое хранилище (NFS, облачные диски).

Что запомнить

  • emptyDir — временное хранилище для обмена данными между контейнерами в Pod. Данные теряются при удалении Pod.
  • hostPath — только для системных задач. Не используйте для данных приложений.
  • PV + PVC — постоянное хранилище. PV — ресурс хранения, PVC — запрос на хранилище. Данные переживают перезапуск Pod.
  • StorageClass — автоматическое создание PV. Не нужно заранее создавать PV вручную.
  • Retain vs Delete — политика освобождения. Retain сохраняет данные, Delete удаляет. Для production используйте Retain.

Рекомендуемые программы

+7 800 100 22 47

бесплатно по РФ

+7 495 085 21 62

бесплатно по Москве

108813 г. Москва, вн.тер.г. поселение Московский,
г. Московский, ул. Солнечная, д. 3А, стр. 1, помещ. 20Б/3
ОГРН 1217300010476
ИНН 7325174845