linuxlab.io
Учебники▾
  • Линукс и сети
    Файловая система, процессы, TCP/IP, BGP и OSPF
    →
  • Terraform и IaC
    HCL, state, plan/apply на sandbox LocalStack
    →
  • Git и GitHub
    Объектная модель, plumbing, ветвление, GitHub Actions
    →
Все учебники →
ЦеныО платформеВойтиСоздать аккаунт
/
  • Введение
  • Уроки
  • How it works
  • Симулятор
  • База знаний
  • Собеседование
Index
Categories
All entries
Footer
linuxlab-УчебникиЦеныО платформеКонфиденциальность и куки
Copyright © 2026 LinuxLab. Все права защищены.
home/linux/kb/Контейнеры (бонус)/kubernetes-storage

kb/containers ── Контейнеры (бонус) ── intermediate

Kubernetes storage - PV, PVC, StorageClass, CSI

PV - физический volume. PVC - запрос pod'а. StorageClass + CSI - шаблон для dynamic provisioning. ReadWriteOnce типичный (block), ReadWriteMany нужен NFS/CephFS. Эфемерные (emptyDir, configMap) живут пока жив pod.

view as markdownaka: k8s-storage, pv-pvc, storageclass, csi-driver, k8s-volumes

Зачем абстракция PV/PVC

Pod в k8s может умереть и переехать на другую ноду. Если данные пишутся в локальный диск pod'а, они теряются. Нужен persistent volume: storage, который переживает pod и доступен новым pod'ам где бы они не запустились (или хотя бы на тех же нодах).

Причём application-team не должна знать, какой именно storage под капотом, EBS, GCE PD, Ceph, NFS, vSAN. Отсюда два слоя:

  • PersistentVolume (PV), кусок реального хранилища, описан в kube
  • PersistentVolumeClaim (PVC), заявка pod'а: «дай мне 10 Gi с режимом RWO». kube-scheduler сматчит её с подходящим PV.
app dev пишет PVC ──► kube-controller-manager ──► binding к PV
                                                │
                                                └─► pod монтирует

Static vs Dynamic provisioning

Static, администратор заранее создаёт PV, потом приходят PVC и матчатся. Подход 2014 года, сейчас почти нигде. Используется только для legacy-storage без CSI-драйвера.

Dynamic, есть StorageClass (шаблон с параметрами provisioner'а). Когда приходит PVC c storageClassName, controller вызывает CSI-driver, тот идёт в облако/SAN, аллоцирует диск, возвращает имя/handle, controller создаёт PV и биндит к PVC. Всё автоматически.

CSI, Container Storage Interface

Стандартизированный gRPC-интерфейс между k8s и storage-vendor. До CSI каждый driver был встроен в kubelet (in-tree). Это создавало жуткую coupling, релиз k8s блокировал обновления драйверов.

CSI-driver, это два DaemonSet'а:

  • Node plugin, на каждой ноде, делает Mount/Unmount
  • Controller plugin, обычно на одном pod'е, делает CreateVolume/DeleteVolume/AttachVolume в облаке

Популярные:

CSI driverГде работает
ebs.csi.aws.comAWS EBS (RWO, block)
pd.csi.storage.gke.ioGCE Persistent Disk
disk.csi.azure.comAzure managed disks
rook-ceph.rbd.csi.ceph.comCeph RBD (RWO block)
cephfs.csi.ceph.comCeph FS (RWX)
nfs.csi.k8s.ioлюбой [[nfs
local.csi.k8s.ioлокальный диск ноды
longhorn.iodistributed block-storage от Rancher

StorageClass

yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast-ssd
provisioner: ebs.csi.aws.com
parameters:
  type: gp3                          # тип диска EBS
  encrypted: "true"
  iops: "3000"
  throughput: "125"
  fsType: ext4                       # как будет отформатирован
reclaimPolicy: Delete                # что с PV при удалении PVC
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
  • reclaimPolicy: Delete, удалить PV (и реальный диск) при удалении PVC. Retain, оставить, размечать как Released, чтобы админ вручную почистил (production-friendly).
  • volumeBindingMode: WaitForFirstConsumer, отложить provisioning пока pod не запланирован, чтобы зону диска подобрать под зону ноды. Immediate, создать сразу, может попасть «не в ту зону».
  • allowVolumeExpansion: true, можно увеличить PVC живьём (online resize, подерживается XFS/ext4 поверх EBS). Уменьшать нельзя.

PVC, заявка от приложения

yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: app-data
spec:
  accessModes: [ReadWriteOnce]
  storageClassName: fast-ssd
  resources:
    requests: { storage: 50Gi }

В pod'е:

yaml
spec:
  containers:
  - name: app
    volumeMounts:
    - name: data
      mountPath: /var/lib/myapp
  volumes:
  - name: data
    persistentVolumeClaim:
      claimName: app-data

Access Modes

ModeАббрЧто значитГде работает
ReadWriteOnceRWOодин node может монтировать read-writeEBS, GCE PD, RBD - типичный block
ReadOnlyManyROXмного node могут монтировать read-onlyредко, configMap-style
ReadWriteManyRWXмного node могут писать одновременноNFS, CephFS, Azure Files, filesystem-уровень
ReadWriteOncePodRWOPодин pod (k8s 1.27+)strict-locking БД

RWO, на блок-устройство. Нельзя смонтировать на 2 ноды (FS не consistent). Если pod переехал, PV отвязывается от старой ноды и привязывается к новой (через CSI ControllerUnpublish/Publish, занимает 10-60 сек).

RWX, нужен shared filesystem: NFS, CephFS, GlusterFS, Azure Files. Block-storage не умеет.

Ephemeral volumes, данные на жизнь pod'а

Не всегда нужен persistent storage. Для scratch-данных:

  • emptyDir, пустой dir на ноде, удаляется с pod'ом. Backed by node-disk или RAM (medium: Memory через [[tmpfs-overlayfs|tmpfs]]).
  • configMap / secret, readonly mount контента из ConfigMap/Secret.
  • downwardAPI, pod metadata как файлы.
  • projected, несколько источников в один mount (часто для serviceAccountToken + ca-cert).
  • generic ephemeral volume, inline PVC, удаляется с pod'ом. Удобно для temporary workloads, не надо отдельный PVC.
yaml
volumes:
- name: cache
  emptyDir:
    sizeLimit: 1Gi
- name: tls-certs
  secret:
    secretName: api-tls

StatefulSet + volumeClaimTemplates

Для БД, очередей, KV-store нужны:

  1. Стабильное имя pod'а (mongo-0, mongo-1), даёт StatefulSet
  2. Свой PVC на каждый pod, переживающий рескейлинг
yaml
apiVersion: apps/v1
kind: StatefulSet
metadata: { name: mongo }
spec:
  serviceName: mongo
  replicas: 3
  selector: { matchLabels: { app: mongo } }
  template:
    spec:
      containers:
      - name: mongo
        image: mongo:7
        volumeMounts:
        - { name: data, mountPath: /data/db }
  volumeClaimTemplates:
  - metadata: { name: data }
    spec:
      accessModes: [ReadWriteOnce]
      storageClassName: fast-ssd
      resources: { requests: { storage: 100Gi } }

StatefulSet создаст data-mongo-0, data-mongo-1, data-mongo-2 каждый со своим PV. При delete StatefulSet PVC не удаляется (специально, чтобы не потерять данные). Чистить руками (kubectl delete pvc data-mongo-{0,1,2}).

Snapshot и clone

CSI поддерживает VolumeSnapshot (если у driver'а есть capability).

yaml
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata: { name: app-data-2026-05-03 }
spec:
  volumeSnapshotClassName: ebs-snapshot
  source: { persistentVolumeClaimName: app-data }

Из snapshot'а можно создать новый PVC (dataSource: kind: VolumeSnapshot, name: ...). Это облачный snapshot, не файловый делается через AWS/GCE API, очень быстро (CoW).

Performance, на что смотреть

  • IOPS/throughput провизионируются через StorageClass parameters (для EBS gp3, iops, throughput). gp2, IOPS привязан к размеру.
  • Latency, local SSD < cloud SSD < network filesystem. RWX storage всегда заметно медленнее RWO (NFS overhead).
  • Resize, увеличение PVC требует поддержки online-resize в FS. ext4 и xfs оба умеют. ZFS, нет (через k8s).
  • Backup, k8s не делает бэкап автоматически. Velero, Stash, Kasten K10, внешние инструменты.

Когда что-то пошло не так

  • PVC Pending навсегда, kubectl describe pvc. Часто: no StorageClass с таким именем; CSI driver не работает (kubectl logs -n kube-system <csi-controller>); WaitForFirstConsumer но pod не scheduled (no nodes).
  • Pod ContainerCreating бесконечно, проблема mount. kubectl describe pod покажет «MountVolume.SetUp failed». Часто: zone mismatch (PV в зоне A, pod в зоне B), CSI node-plugin crashed.
  • Multi-Attach error, RWO PV пытается смонтироваться на 2 ноды (например при rolling update без правильного strategy). Решение: strategy: Recreate для StatefulSet или podManagementPolicy: OrderedReady.
  • Disk full в pod'е, но PVC показывает много free, забыли allowVolumeExpansion, или FS не resized после увеличения PVC. kubectl get pvc → новый размер; внутри pod'а df -h старый нужно resize2fs/xfs_growfs вручную (новые CSI делают сами).
  • Persistent volume claim is forbidden: storage size cannot be decreased, уменьшение размера запрещено. Создавай новый PVC, мигрируй данные.
  • Reclaimed PV не освобождается, reclaimPolicy: Retain, PV в Released. Удалять руками: kubectl delete pv ..., почистить spec.claimRef и привязывать к новому PVC.

§ команды

bash
kubectl get pv,pvc -A

Все PV и PVC во всех namespace'ах с binding-статусом

bash
kubectl get sc

Все StorageClass с провижонером и default-маркером

bash
kubectl describe pvc my-pvc

Events PVC - первое место смотреть при Pending

bash
kubectl patch pvc my-pvc -p '{"spec":{"resources":{"requests":{"storage":"100Gi"}}}}'

Live-расширение PVC - работает если allowVolumeExpansion=true

bash
kubectl get csidriver

Список зарегистрированных CSI-драйверов в кластере

bash
kubectl exec -it pod-0 -- df -h /data

Реально занятое место в смонтированном volume - сравнить с PVC

bash
kubectl get volumesnapshot,volumesnapshotcontent

Снапшоты и их content - для CSI driver'ов с поддержкой snapshot'ов

§ см. также

  • kubernetes-pod-lifecycleKubernetes pod lifecycle - от Pending до TerminatedPod проходит фазы Pending → Running → Succeeded/Failed/Unknown. Init-containers выполняются последовательно до основных. Probes: startup → readiness/liveness. SIGTERM + grace period при удалении.
  • nfsNFS - сетевая файловая системаNFS - сетевая ФС от Sun. v3 - stateless, v4.1+ - stateful с делегациями и pNFS. /etc/exports на сервере, mount -t nfs на клиенте. root_squash, sync/async, lock manager - три главные опции.
  • mount-and-fstabmount и /etc/fstab - подключение ФС`mount` подключает блочное устройство или ФС к точке монтирования в дереве. `/etc/fstab` - список того что монтировать при загрузке.
  • xfsXFS - extents и параллельный I/OXFS - дефолт RHEL 7+: allocation groups (параллельный I/O), extents-based allocation, online grow. **Нельзя уменьшить** - только grow. Идеален для big files, БД, parallel workload.
  • ext4ext4 - рабочая лошадь Linux-ФСext4 - дефолтная ФС большинства дистро: журналирование, extents, фиксированное число inode при mkfs. Главные тюны - data-mode, noatime, lazy init. Стабилен 15+ лет. Не масштабируется как XFS.
  • helm-chartsHelm charts - пакетный менеджер для KubernetesHelm - пакетный менеджер k8s. Chart - папка с Chart.yaml, values.yaml и templates/ (Go-templates над YAML). Releases хранятся в Secret namespace'а; upgrade/rollback атомарны. Альтернатива - kustomize (без templating, патчи).
Footer
linuxlab-
Copyright © 2026 LinuxLab. Все права защищены.
Учебники
Цены
О платформе
Конфиденциальность и куки