Как организовать хранение данных (state) в Kubernetes?

«Как организовать хранение данных (state) в Kubernetes?» — вопрос из категории Kubernetes, который задают на 23% собеседований Devops Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В Kubernetes хранение данных для stateful-рабочих нагрузок требует тщательного подхода. Я использую иерархию абстракций: PersistentVolumeClaim (PVC) -> PersistentVolume (PV) -> StorageClass, и выбираю решение в зависимости от требований приложения.

1. Динамическое выделение хранилища (наиболее частый сценарий): Приложение запрашивает хранилище через PVC, а StorageClass динамически создает PV в облачном провайдере.

# StorageClass для быстрых SSD дисков в GKE
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast-ssd
provisioner: pd.csi.storage.gke.io
parameters:
  type: pd-ssd
  replication-type: none
volumeBindingMode: WaitForFirstConsumer # Важно! Диск создастся только при планировании пода

---
# Запрос хранилища в StatefulSet
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres
spec:
  serviceName: postgres
  selector: { ... }
  template: { ... }
  volumeClaimTemplates:  # Шаблон PVC для каждого пода
  - metadata:
      name: postgres-data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: fast-ssd
      resources:
        requests:
          storage: 100Gi

2. Ключевые параметры и выбор:

  • Access Modes:
    • ReadWriteOnce (RWO): Только одна нода может монтировать том на запись (подходит для большинства БД).
    • ReadWriteMany (RWX): Многие ноды могут монтировать том на запись (для shared-файловых систем, NFS).
  • StorageClass Parameters: Для каждого облачного провайдера свои (тип диска, уровень IOPS, зона).
  • Reclaim Policy: Retain (сохранить данные после удаления PVC) для критичных данных, Delete — для временных.

3. Паттерны для разных типов данных:

  • Базы данных (PostgreSQL, MySQL): Использую StatefulSet с volumeClaimTemplates и локальным SSD (local volume) для максимальной производительности, если позволяет архитектура высокой доступности (HA). Для облачных managed-решений (Cloud SQL) подключаюсь через sidecar-прокси или операторы.
  • Файловое хранилище (NFS, S3-совместимое): Для общих файлов (загрузки пользователей) использую CSI-драйверы для облачных файловых систем (AWS EFS, GCP Filestore) с доступом RWX или sidecar-контейнер, который синхронизирует данные с объектным хранилищем (S3/MinIO).
  • Конфигурации и секреты: Для конфигов, которые меняются редко, — ConfigMaps/Secrets. Для динамических конфигов — специализированные решения (Vault Agent Injector, External Secrets Operator).

4. Резервное копирование (Backup): Хранение в Kubernetes — не освобождает от необходимости бэкапов. Использую:

  • Velero: Для резервного копирования PVC вместе с ресурсами Kubernetes (неймспейсы, деплойменты).
  • Cloud-native snapshotting: Через VolumeSnapshot API Kubernetes, который создает снапшоты дисков на уровне облачного провайдера.
  • Логическое копирование: Для БД — дампы средствами самой СУБД (например, pg_dump), которые затем сохраняются в объектное хранилище.

Главный принцип: данные — самая ценная часть, поэтому выбор решения всегда основан на требованиях к производительности, доступности, стоимости и, что критично, — на продуманной стратегии резервного копирования и восстановления (Disaster Recovery).