Перейти до вмісту

Модуль 4.3: StorageClass та динамічне виділення

Складність: [MEDIUM] — автоматизація виділення сховища

Час на проходження: 35–45 хвилин

Передумови: Модуль 4.2 (PV та PVC), Модуль 1.2 (CSI)


Що ви зможете зробити

Розділ «Що ви зможете зробити»

Після цього модуля ви зможете:

  • Спроєктувати StorageClass для динамічного виділення в локальних кластерах і кластерах на кшталт AWS, GCP та Azure.
  • Налаштувати поведінку за замовчуванням, явну відмову від класу, політики повторного використання, режими прив’язки, параметри та налаштування розширення.
  • Оцінити прив’язку Immediate проти WaitForFirstConsumer для зональних, локальних і мережевих бекендів сховища.
  • Діагностувати PVC у стані Pending, приєднання до неправильної зони, невдале розширення, недійсні параметри та збої контролера-провізіонера.

Чому цей модуль важливий

Розділ «Чому цей модуль важливий»

Гіпотетичний сценарій: у платформенної команди є кластер із трьома пулами нод, двома зонами доступності та кількома командами, які створюють бази даних протягом тижня релізу. Якщо кожна нова база даних чекає, поки адміністратор вручну створить PersistentVolume, робочий процес сховища перетворюється на чергу заявок замість платформи самообслуговування. Якщо ж динамічне виділення ввімкнено без хороших значень за замовчуванням, з’являється протилежна проблема: команди швидко отримують томи, але ті можуть опинитися в неправильній зоні, використати неправильний клас диска, видалити дані під час видалення PVC або залишитися у стані Pending, бо ім’я провізіонера не збігається з жодним контролером.

StorageClass — це шар політики між запитом розробника на сховище та системою, яка створює реальне сховище. У Модулі 4.2 ви побачили, як PersistentVolumeClaim може прив’язатися до наявного PersistentVolume. Цей модуль додає крок автоматизації: PVC може вказувати на StorageClass, і Kubernetes може попросити провізіонера створити відповідний PV на вимогу. Це звучить просто, але саме деталі вирішують, чи запуститься робоче навантаження зі станом без проблем, чи переживе воно випадкове видалення PVC і чи зможе зрости, коли з’явиться тиск даних.

Уявіть статичне виділення як замовлення меблів на замовлення: хтось вимірює кімнату, купує матеріал, будує полицю, і лише потім користувач може поставити на неї книжки. Динамічне виділення ближче до торгового автомата з кількома підписаними кнопками. StorageClass — це конфігурація автомата, PVC — це зроблений вибір, провізіонер — механізм за панеллю, а отриманий PV — це сховище, яке випадає в комірку. Ваше завдання на іспиті CKA — обрати правильну кнопку, прочитати події, коли автомат заклинило, і знати, які саме налаштування запобігають поширеним експлуатаційним несподіванкам.


StorageClass автоматизує фабрику PV

Розділ «StorageClass автоматизує фабрику PV»

Статичне та динамічне виділення розв’язують одну й ту саму задачу прив’язки на різних рівнях автоматизації. За статичного виділення адміністратор спочатку створює об’єкти PV, часто після ручного створення диска, файлової частки, експорту чи локального шляху поза Kubernetes. За динамічного виділення адміністратор створює StorageClass один раз, і звичайних PVC стає достатньо інформації, щоб кластер створив нове резервне сховище. Розрізнення в контексті CKA має значення, бо багато питань з усунення несправностей починаються з PVC у стані Pending, і ваше перше завдання — вирішити, чи Kubernetes чекає на наявний PV, чи чекає, поки провізіонер його створить.

+----------------------------------------------------------------------+
| Static vs Dynamic Provisioning |
| |
| STATIC (Manual) DYNAMIC (Automatic) |
| --------------- ------------------- |
| |
| 1. Admin creates PV 1. Admin creates StorageClass |
| | | |
| v v |
| 2. Dev creates PVC 2. Dev creates PVC |
| | | |
| v v |
| 3. Kubernetes binds 3. Provisioner creates PV |
| PVC to existing PV | |
| v |
| 4. Kubernetes binds PVC to new PV|
| |
| Pro: Full control Pro: Self-service, scalable |
| Con: Admin bottleneck Con: Less control per volume |
+----------------------------------------------------------------------+

Діаграма приховує одну важливу деталь реалізації: сам Kubernetes не вміє створювати кожен хмарний диск чи локальний каталог. StorageClass містить рядок provisioner, а зовнішній або сумісний із вбудованим контролер стежить за PVC, які посилаються на цей рядок. У сучасному Kubernetes драйвери Container Storage Interface — це звичайний шлях для виробничого сховища. Старіші вбудовані (in-tree) імена провізіонерів досі трапляються в застарілих матеріалах і старіших кластерах, тож ви маєте їх упізнавати, але нові проєкти варто будувати на імені драйвера CSI, який фактично встановила ваша платформа.

Центральний об’єкт навмисно малий. Він не визначає конкретне ім’я тому чи конкретну ноду. Натомість він визначає, як саме слід створити майбутній PV, які параметри бекенду надіслати, яку політику повторного використання скопіювати на динамічно створений PV, коли має відбуватися прив’язка і чи можуть PVC згодом запитувати більше місця. Читайте цей приклад як контракт, а не як універсальний шаблон для вставляння в кожну хмару.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd
annotations:
storageclass.kubernetes.io/is-default-class: "true" # Optional
provisioner: kubernetes.io/aws-ebs # Legacy in-tree name; prefer CSI in new clusters
parameters: # Provisioner-specific settings
type: gp3
iopsPerGB: "10"
reclaimPolicy: Delete # What happens when PVC deleted
volumeBindingMode: WaitForFirstConsumer # When to provision
allowVolumeExpansion: true # Can resize later?
mountOptions: # Mount options for volumes
- discard

Кожне поле має різний радіус ураження. parameters впливають на те, як створюється резервний диск чи частка. reclaimPolicy стає поведінкою видалення для PV, що може означати різницю між очищенням тестового середовища та випадковою втратою виробничих даних. volumeBindingMode впливає на планування, особливо коли сховище може приєднуватися лише до нод у певній зоні. allowVolumeExpansion впливає на майбутні можливості відновлення, бо PVC можна розширити, тільки коли його клас і драйвер підтримують розширення.

ProvisionerХмара/ПлатформаТип сховища
kubernetes.io/aws-ebsAWSТоми EBS
kubernetes.io/gce-pdGCPPersistent Disk
kubernetes.io/azure-diskAzureManaged Disk
kubernetes.io/azure-fileAzureAzure Files
ebs.csi.aws.comAWS (CSI)EBS через CSI
pd.csi.storage.gke.ioGCP (CSI)PD через CSI
rancher.io/local-pathkindЛокальний шлях
k8s.io/minikube-hostpathminikubeШлях на хості

Ця таблиця корисна для впізнавання, але вона не замінює перевірки кластера. Середовище іспиту CKA може використовувати локальний провізіонер, тоді як виробничі кластери зазвичай мають хмарний драйвер CSI або драйвер постачальника сховища. Завжди оглядайте kubectl get storageclass і поди контролера CSI, перш ніж припускати ім’я провізіонера. Невідповідність навіть в один символ у полі provisioner достатня, щоб залишити кожен відповідний PVC у нескінченному очікуванні.

Зупиніться та спрогнозуйте: якщо PVC запитує storageClassName: fast-ssd, але жоден запущений провізіонер не стежить за рядком ebs.csi.aws.com, яку подію ви очікуєте побачити на PVC? Перш ніж читати відповідь далі, вирішіть, чи може Kubernetes створити диск самостійно, чи він має чекати на зовнішній контролер.

Відповідь у тому, що Kubernetes записує події виділення, але саму роботу з бекендом має виконати контролер. Якщо відповідного провізіонера не встановлено, PVC залишається у стані Pending, а події зазвичай згадують зовнішнє виділення або відсутній провізіонер. Саме тому усунення несправностей StorageClass починається і з об’єкта, і з контролера. Вам потрібно, щоб клас, PVC, розгортання провізіонера та події збігалися між собою.


Проєктування класів під реальні провізіонери

Розділ «Проєктування класів під реальні провізіонери»

StorageClass має відображати експлуатаційний вибір, зрозумілий і для учнів, і для прикладних команд. Імена на кшталт fast, standard, encrypted-retain та local-dev корисніші за імена, які лише повторюють рядок драйвера. Ім’я — це те, що бачить автор PVC, тож воно має передавати вартість, продуктивність, надійність чи призначення. Під ім’ям платформенна команда може сховати специфічні для постачальника налаштування, які більшості розробників не потрібно запам’ятовувати.

Наступний базовий приклад зберігає старий вбудований патерн провізіонера AWS, бо ви досі можете натрапити на нього в застарілих навчальних матеріалах. Для виробничих кластерів епохи Kubernetes 1.35 надавайте перевагу класу CSI, показаному після нього, коли встановлено драйвер EBS CSI. Концептуальні поля при цьому ті самі: оберіть бекенд, задайте політику, відкладіть прив’язку для зонального сховища та вирішіть, чи дозволено розширення.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: standard
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp2
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer

Для AWS EBS ім’я провізіонера драйвера CSI — ebs.csi.aws.com. Томи EBS є зональними, тож WaitForFirstConsumer зазвичай є безпечнішим режимом прив’язки, бо він дозволяє планувальнику обрати ноду до того, як буде створено диск. У прикладі CSI нижче використано Retain для захисту даних, але цей вибір не є універсально правильним. Він доречний для виробничих баз даних і ризикований для одноразових середовищ, бо видалені PVC можуть залишити по собі диски, за які виставляється рахунок.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ebs
provisioner: ebs.csi.aws.com
parameters:
type: gp3
iopsPerGB: "50"
throughput: "125"
encrypted: "true"
kmsKeyId: "arn:aws:kms:us-east-1:123456789:key/abc-123"
reclaimPolicy: Retain
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true

Для GCP Persistent Disk ім’я провізіонера CSI, яке зазвичай використовує GKE, — pd.csi.storage.gke.io. Параметр replication-type змінює модель надійності та топології, тож його слід обирати свідомо, а не копіювати з лабораторної роботи. Регіональні диски можуть покращити доступність для деяких проєктів, але вони також мають наслідки для вартості й планування. Іспит зазвичай менше цікавлять специфічні для хмари назви параметрів і більше — чи розумієте ви, що параметри належать провізіонеру, а не PVC.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd
provisioner: pd.csi.storage.gke.io
parameters:
type: pd-ssd
replication-type: regional-pd # For HA
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true

Для Azure Disk ім’я провізіонера CSI — disk.csi.azure.com. Керовані диски також чутливі до топології, тож відкладена прив’язка дозволяє уникнути того самого класу проблем із неправильною зоною, який ви бачили з EBS та Persistent Disk. Назви параметрів інші, бо в Azure інші назви продуктів сховища. Саме тому StorageClass, скопійований з однієї хмари, рідко працює в іншій без зміни і рядка провізіонера, і ключів параметрів.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: managed-premium
provisioner: disk.csi.azure.com
parameters:
skuName: Premium_LRS # Standard_LRS, Premium_LRS, StandardSSD_LRS
kind: managed # managed, dedicated, shared
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true

Локальні кластери для розробки теж мають провізіонери, але їхня поведінка ближча до виділення місця в локальній файловій системі, ніж до надійного хмарного сховища. Кластер kind часто використовує провізіонер local-path від Rancher, а minikube зазвичай надає провізіонер на основі hostPath. Вони чудово підходять для вивчення механіки динамічного виділення. Вони не повинні навчити вас, що каталог на хості має таку саму доступність чи мобільність, як хмарний диск, бо локальне сховище прив’язує дані до ноди, яка його розміщує.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: local-path
provisioner: rancher.io/local-path
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: standard
provisioner: k8s.io/minikube-hostpath
reclaimPolicy: Delete
volumeBindingMode: Immediate

Локальні приклади навмисно прості, бо їх зазвичай використовують в одновузлових або невеликих навчальних кластерах. У багатовузловій лабораторії виділення на основі local-path усе ще може бути корисним, але воно робить розміщення частиною коректності. Якщо дані живуть на одній ноді, под-заміна має приземлитися там, де ці дані існують, або шар сховища має відтворити їх в іншому місці. Це не помилка Kubernetes; це природний наслідок локального сховища.

Перш ніж це запускати, який вивід ви очікуєте від kubectl get storageclass на власному кластері? Спершу спрогнозуйте імена провізіонерів, потім запустіть команду й порівняйте свою уявну модель із фактичним кластером. Ця звичка запобігає поширеній екзаменаційній помилці: написанню ідеально оформленого StorageClass, що посилається на провізіонер, якого в середовищі немає.

Terminal window
kubectl get storageclass
kubectl get storageclass -o custom-columns='NAME:.metadata.name,PROVISIONER:.provisioner,DEFAULT:.metadata.annotations.storageclass\.kubernetes\.io/is-default-class,VOLUME_BINDING:.volumeBindingMode'

Замовчування, відмови та час прив’язки

Розділ «Замовчування, відмови та час прив’язки»

Клас StorageClass за замовчуванням відповідає на конкретне запитання: що має статися, коли PVC не вказує storageClassName? Якщо існує рівно один клас за замовчуванням, Kubernetes може застосувати цей клас до PVC, що не містить поля, і динамічне виділення може початися. Якщо класу за замовчуванням немає, PVC без класу не може запустити динамічне виділення за замовчуванням. Якщо ж класів за замовчуванням більше одного, Kubernetes використовує найновіший створений клас за замовчуванням — це детерміновано, але часто несподівано для операторів.

Позначення класу як такого, що за замовчуванням, виконується анотацією. Це робить вибір за замовчуванням адміністративною політикою, а не особливим типом об’єкта. Клас може бути за замовчуванням заради зручності, але він має бути «нудним», широко придатним і достатньо безпечним для більшості PVC. Клас за замовчуванням з агресивними налаштуваннями вартості чи поведінкою Retain може створити дорогу роботу з очищення для кожної команди, яка забуде явно назвати клас.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: standard
annotations:
storageclass.kubernetes.io/is-default-class: "true" # The default annotation
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp3
Terminal window
kubectl patch storageclass standard -p '{"metadata": {"annotations": {"storageclass.kubernetes.io/is-default-class": "true"}}}'
Terminal window
kubectl get storageclass
# NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE
# standard (default) kubernetes.io/aws-ebs Delete WaitForFirstConsumer
# fast-ssd kubernetes.io/aws-ebs Delete Immediate

Протилежність до замовчування — це явна відмова. Якщо PVC залишає storageClassName відсутнім, Kubernetes може застосувати клас за замовчуванням. Якщо ж PVC задає storageClassName: "", Kubernetes трактує це як навмисний запит на відсутність класу, тож заявка збігається лише з тими PV, які також не мають класу. Це крихітне розрізнення — поширене джерело екзаменаційних питань, бо відсутнє поле та порожній рядок виглядають схоже, але поводяться по-різному.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-claim
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
# No storageClassName specified - uses default if one exists
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: static-only-claim
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: "" # Empty string means no dynamic provisioning

Режим прив’язки керує тим, коли Kubernetes має прив’язати чи провізіонувати PV. Immediate означає, що заявка може прив’язатися чи провізіонуватися, щойно PVC існує. WaitForFirstConsumer означає, що Kubernetes відкладає прив’язку чи виділення, доки не буде заплановано под, який використовує заявку. Ця затримка — не лише деталь продуктивності; вона дає планувальнику шанс одночасно врахувати топологію ноди, мітки зон, обмеження пода та розміщення тому.

+----------------------------------------------------------------------+
| Volume Binding Modes |
| |
| IMMEDIATE WAITFORFIRSTCONSUMER |
| --------- -------------------- |
| |
| PVC Created PVC Created |
| | | |
| v v |
| PV Provisioned PVC stays Pending |
| immediately | |
| | | |
| | Pod scheduled |
| | | |
| | v |
| | PV Provisioned |
| | (on same zone as pod) |
| | | |
| v v |
| Pod scheduled Pod can use storage |
| (may fail if wrong zone) |
| |
+----------------------------------------------------------------------+

Проблему неправильної зони найлегше зрозуміти на зональних дисках. Припустімо, том EBS створено до того, як под було заплановано. Провізіонер обирає us-east-1a, а планувальник пізніше розміщує под на ноді в us-east-1b. Под не може приєднати цей том EBS, бо том і нода в різних зонах, тож робоче навантаження зупиняється, навіть попри те, що і специфікація PVC, і специфікація пода виглядають розумно.

Node: us-east-1a Node: us-east-1b
+-------------+ +-------------+
| | | Pod | <- Scheduler puts pod here
| | | (needs |
| | | storage) |
+-------------+ +-------------+
^
|
EBS Volume X Volume in wrong zone
(provisioned X Pod cannot start
immediately in 1a)

WaitForFirstConsumer змінює порядок. PVC може існувати без PV, планувальник розміщує под на ноді, яка задовольняє обмеження пода, і лише тоді виділення відбувається в правильній топології. Цей режим — сильний вибір за замовчуванням для зонального блокового сховища та локального сховища. Він менш важливий для справді мережевого сховища, як-от бекенди на кшталт NFS, бо точка доступу до сховища досяжна з багатьох нод без приєднання, специфічного для зони.

Node: us-east-1a Node: us-east-1b
+-------------+ +-------------+
| | | Pod | <- Scheduler puts pod here
| | | (needs |
| | | storage) |
+-------------+ +-------------+
^
|
EBS Volume OK Volume in correct zone
(provisioned OK Pod starts successfully
in 1b AFTER
pod scheduled)
РежимВипадок використання
ImmediateNFS, розподілене сховище, сховище без зон
WaitForFirstConsumerЗонально-специфічне сховище (EBS, GCE PD, Azure Disk), локальне сховище

Зупиніться та спрогнозуйте: у вас є StorageClass із volumeBindingMode: Immediate для AWS EBS. Розробник створює PVC, і PV негайно провізіонується в us-east-1a. Планувальник потім розміщує под на ноді в us-east-1b. Вирішіть, яку категорію помилок ви б досліджували першою, потім поясніть, як зміна режиму прив’язки запобігає невідповідності.

Ще одну деталь замовчування варто запам’ятати для іспиту. reclaimPolicy зі StorageClass копіюється на динамічно створені PV у момент створення. Зміна чи перестворення StorageClass пізніше не переписує наявні PV. Якщо виробничий клас випадково використав Delete, виправлення класу захищає лише майбутні томи; наявні PV потребують прямого огляду і, за потреби, прямого патча політики повторного використання PV.

Terminal window
kubectl get persistentvolumeclaim my-claim -o jsonpath='{.spec.volumeName}'
kubectl patch persistentvolume pv-001 -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}'

Розширення, параметри та поведінка монтування

Розділ «Розширення, параметри та поведінка монтування»

Розширення тому — це функція відновлення не меншою мірою, ніж функція зручності. Бази даних, кеші збірки, репозиторії артефактів і компоненти логування з часом зростають, а перестворення PVC під час інциденту — зазвичай останнє, чого ви хочете. StorageClass із allowVolumeExpansion: true дає вам можливість пізніше збільшити запит PVC, доки драйвер і тип тому підтримують розширення. Kubernetes не підтримує зменшення PVC, тож планування ємності все одно має значення.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: expandable
provisioner: kubernetes.io/aws-ebs
allowVolumeExpansion: true # Must be true to resize PVCs
parameters:
type: gp3

Розширення PVC починається зі збільшення запитуваного сховища. Запит має рухатися вгору, а не вниз, і StorageClass має дозволяти розширення. Контролер бекенду потім змінює розмір реального диска чи частки, а на боці ноди може знадобитися збільшити файлову систему, коли том змонтовано. Різні драйвери відрізняються поведінкою онлайн-розширення, тож не припускайте, що кожна файлова система зростає точно в момент зміни об’єкта PVC.

Terminal window
# Original PVC with 10Gi
kubectl get persistentvolumeclaim my-claim
# NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS
# my-claim Bound pv-001 10Gi RWO expandable
# Edit to request more space
kubectl patch persistentvolumeclaim my-claim -p '{"spec":{"resources":{"requests":{"storage":"20Gi"}}}}'
# Or edit manually
kubectl edit persistentvolumeclaim my-claim
# Change spec.resources.requests.storage to 20Gi
+---------------------------------------------------------------------+
| PVC Expansion Process |
| |
| 1. Edit PVC --> 2. Controller resizes --> 3. Filesystem |
| (increase underlying storage expansion |
| size) (for example, EBS volume) (when mounted) |
| |
| Status shows: |
| - "Resizing" - storage backend being resized |
| - "FileSystemResizePending" - waiting for pod to mount |
| |
| Note: expansion may require remount or restart for some drivers |
+---------------------------------------------------------------------+

Коли розширення виглядає застряглим, спочатку прочитайте умови (conditions) PVC, перш ніж змінювати інші об’єкти. Resizing зазвичай указує на роботу бекенду, тоді як FileSystemResizePending означає, що ємність бекенду змінилася, але змонтована файлова система ще потребує зростання. Ця друга умова не є автоматично збоєм. Вона може зникнути, коли под змонтує том, або може потребувати перезапуску залежно від драйвера та файлової системи.

Terminal window
kubectl describe persistentvolumeclaim my-claim
# Look for conditions:
# Conditions:
# Type Status
# ---- ------
# FileSystemResizePending True # Waiting for filesystem resize
# Resizing True # Backend resize in progress

Параметри — це місце, де живе специфічна для постачальника поведінка. API Kubernetes зберігає їх як рядки й передає провізіонеру; Kubernetes не розуміє кожного регулятора продукту сховища. Це означає, що недійсні ключі можуть зазнати збою лише тоді, коли провізіонер спробує діяти. Коли PVC залишається у стані Pending після зміни StorageClass, порівнюйте назви параметрів із документацією драйвера та логами контролера, а не припускайте, що проблема в синтаксисі YAML.

parameters:
type: gp3 # gp2, gp3, io1, io2, st1, sc1
iopsPerGB: "50" # For gp3/io1/io2
throughput: "250" # For gp3 (MiB/s)
encrypted: "true"
kmsKeyId: "arn:aws:kms:..."
fsType: ext4 # ext4, xfs
parameters:
type: pd-ssd # pd-standard, pd-ssd, pd-balanced
replication-type: none # none, regional-pd
disk-encryption-kms-key: "projects/..."
fsType: ext4
parameters:
skuName: Premium_LRS # Standard_LRS, Premium_LRS, StandardSSD_LRS
kind: managed # managed, dedicated, shared
cachingMode: ReadOnly
fsType: ext4

Опції монтування копіюються в отриманий PV і використовуються під час монтування тому. Вони потужні, бо можуть впливати на семантику файлової системи, продуктивність і зручність налагодження. Їх також легко використати неправильно, бо Kubernetes не перевіряє кожну опцію щодо кожної файлової системи. Ставтеся до опцій монтування як до рішення на рівні драйвера сховища й операційної системи, а не як до нешкідливого місця для експериментів у спільному класі.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: with-mount-options
provisioner: kubernetes.io/aws-ebs
mountOptions:
- discard
- noatime
- nodiratime
parameters:
type: gp3
fsType: ext4

Зупиніться та поміркуйте: PVC було створено зі StorageClass, що має allowVolumeExpansion: false, а в бази даних закінчується місце. Чи можете ви змінити StorageClass на allowVolumeExpansion: true, а потім розширити цей PVC? Ваша операційна відповідь має згадати незмінність, поведінку наявних PV і безпечніший шлях міграції, якщо прямий шлях розширення заблоковано.

Практичне відновлення залежить від конкретного класу та драйвера, але проєктний урок зрозумілий. Установлюйте allowVolumeExpansion: true для класів, де майбутнє зростання є ймовірним, особливо для класів баз даних і сервісів зі станом. Використовуйте квоти, контроль допуску та огляд вартості для контролю зловживань. Не прибирайте можливість розширення лише тому, що хочете, щоб люди краще планували; інциденти часто приходять після того, як початкова оцінка перестає бути корисною.


Усунення збоїв динамічного виділення

Розділ «Усунення збоїв динамічного виділення»

Коли динамічне виділення зазнає збою, PVC зазвичай залишається у стані Pending. Самого по собі цього недостатньо, бо Pending може означати, що PVC навмисно чекає на першого споживача, чекає на статичний PV, чекає на зовнішнього провізіонера або повторно зазнає збою, бо бекенд відхилив запит. Вашим першим кроком має бути читання подій на PVC, потім огляд StorageClass, потім огляд контролера-провізіонера. Ця послідовність повторює шлях запиту: від заявки до політики й до виконавця.

Terminal window
kubectl describe persistentvolumeclaim dynamic-pvc

Розділ подій часто підказує, структурна проблема чи специфічна для бекенду. Повідомлення про очікування першого споживача може бути нормальним, коли клас використовує WaitForFirstConsumer. Повідомлення про невідомого провізіонера вказує на StorageClass чи відсутній контролер. Помилка хмарного API, помилка квоти, помилка дозволів чи недійсний параметр указують на логи контролера CSI та конфігурацію на боці постачальника.

Terminal window
kubectl get storageclass fast -o yaml
kubectl get pods -n kube-system

Якщо в події PVC бракує деталей, перевірте логи контролера для відповідного драйвера CSI. Простір імен і ім’я розгортання різняться залежно від встановлення, тож виводьте системні поди, а не запам’ятовуйте одне ім’я розгортання. Команда нижче зберігає початковий приклад AWS EBS, але той самий метод застосовний до інших драйверів. Шукайте невдалі виклики create-volume, недійсні параметри, відмови в дозволах, помилки топології та повідомлення про квоти.

Terminal window
# Example for AWS EBS CSI driver
kubectl logs -n kube-system deploy/ebs-csi-controller -c csi-provisioner

Вам також варто перевірити, чи відкладена прив’язка є очікуваним станом. За WaitForFirstConsumer PVC може залишатися у стані Pending, доки под його не використає, і це може бути правильно. Якщо учень бачить Pending і одразу змінює StorageClass на Immediate, він може створити ту саму проблему неправильної зони, якій відкладений режим мав запобігти. Натомість створіть або огляньте под-споживач і читайте події планувальника разом із подіями PVC.

Terminal window
kubectl describe pod dynamic-pod
kubectl get events --sort-by=.lastTimestamp

Компактний діагностичний шлях вберігає вас від ганяння за шумом. По-перше, перевірте, чи PVC називає клас, чи покладається на замовчування. По-друге, перевірте, чи цей клас існує і чи має очікуваний рядок провізіонера. По-третє, перевірте, чи має прив’язка чекати на споживача. По-четверте, перевірте, чи запущений под контролера для цього провізіонера. По-п’яте, читайте логи контролера лише після того, як знатимете, який драйвер має діяти.

Terminal window
kubectl get persistentvolumeclaim dynamic-pvc -o jsonpath='{.spec.storageClassName}{"\n"}'
kubectl get storageclass
kubectl describe storageclass fast
kubectl get persistentvolume

Сценарій вправи: PVC не має storageClassName, у кластері є два класи StorageClass за замовчуванням, а отриманий PV використовує повільніший бекенд. Виправлення — не патчити PVC після виділення з надією, що диск зміниться. Перегляньте анотації за замовчуванням, приберіть ненавмисний дефолт і створіть нову заявку, якщо робочому навантаженню потрібен інший клас. Динамічне виділення обирає клас у момент заявки, а не після того, як том уже створено.

Покрокові розбори збоїв

Розділ «Покрокові розбори збоїв»

Найшвидший спосіб діагностувати проблеми StorageClass — відокремити намір площини управління від виконання на бекенді. PVC каже вам, чого запросило робоче навантаження, StorageClass каже, яку політику застосував Kubernetes, а логи провізіонера кажуть, що сталося, коли звернулися до бекенду. Це три різні шари, і їх змішування призводить до поганих виправлень. Наприклад, зміна специфікації пода не може полагодити недійсний параметр StorageClass, а зміна StorageClass не може перемістити том, який уже створено в неправильній зоні.

+-------+ +--------------+ +------------------+ +------+
| PVC | --> | StorageClass | --> | CSI provisioner | --> | PV |
+-------+ +--------------+ +------------------+ +------+

Розгляньте PVC, який залишається у стані Pending у класі з WaitForFirstConsumer. Якщо жоден под не посилається на заявку, стан Pending є свідченням того, що клас робить саме те, що йому наказали. Якщо под усе ж посилається на заявку, але под не може сплануватися, проблема може бути в селекторах нод, taint’ах, тиску на ресурси чи обмеженнях топології. Якщо под планується, а виділення все одно зазнає збою, то докази зміщуються в бік провізіонера та бекенду. Така послідовність вберігає вас від «полагодження» відкладеної прив’язки, коли справжня проблема — у плануванні.

Збій із неправильною зоною має іншу сигнатуру. PVC може вже бути прив’язаним, а под може застрягти під час приєднання чи монтування, а не чистого планування. У цьому разі читайте спорідненість ноди (node affinity) PV та обрану ноду пода, потім порівняйте мітки зон. Якщо том уже прив’язано до зони, яка не може обслуговувати под, перемикання StorageClass на WaitForFirstConsumer захищає лише майбутні заявки. Наявна заявка зазвичай потребує нового тому, міграції даних або свідомої стратегії перепланування, яка розмістить под там, де том може приєднатися.

+----------+ +-------------+ +-----------------+
| PV zone | --> | Node zone | --> | Attach result |
+----------+ +-------------+ +-----------------+
| 1a | | 1a | | attach succeeds |
| 1a | | 1b | | attach fails |
+----------+ +-------------+ +-----------------+

Збої параметрів часто виглядають як звичайні PVC у стані Pending, доки ви не оглянете події. Друкарська помилка в типі облікового запису сховища, типі диска, параметрі шифрування чи опції файлової системи може пройти валідацію API Kubernetes, бо карта параметрів здебільшого непрозора для Kubernetes. Драйвер CSI — це компонент, який знає, чи приймає бекенд цю опцію. Саме тому дійсний YAML-файл усе одно може спричинити подію невдалого виділення, і саме тому документація постачальника належить до циклу усунення несправностей.

Несподіванки з класом за замовчуванням особливо поширені під час міграцій. Платформенна команда може запровадити новий клас за замовчуванням, поки старіший досі має анотацію дефолту, або лабораторна робота може запатчити тимчасовий клас як дефолт і забути його прибрати. Автори PVC, які опускають storageClassName, делегували вибір кластеру. Якщо це делегування ненавмисне, пишіть клас явно. Якщо заявка має прив’язатися до статичного PV, використовуйте порожній рядок, а не опускання.

+---------------------+ +-------------------------+
| PVC field | | Kubernetes behavior |
+---------------------+ +-------------------------+
| omitted | --> | may use default class |
| storageClassName:"" | --> | no dynamic provisioning |
| storageClassName:X | --> | request class X |
+---------------------+ +-------------------------+

Збої розширення вимагають спокійного читання умов. Заявка, яка досі повідомляє стару ємність, не є автоматично зламаною після патча зміни розміру. Бекенд може змінювати розмір, або файлова система може чекати на операцію монтування. Прочитайте kubectl describe persistentvolumeclaim, перш ніж перезапускати робочі навантаження чи замінювати заявку. Якщо клас не дозволяв розширення на момент створення заявки, плануйте контрольовану міграцію, а не намагайтеся зменшити, змінити чи примусово застосувати непідтримуваний шлях.

Помилки з політикою повторного використання вимагають іншого роду обережності, бо вони впливають на видалення. Якщо виробничий клас використав Delete, небезпечний момент — не створення заявки; це видалення заявки. Прямий патч політики повторного використання PV може захистити вже створені PV, але його слід робити після підтвердження того, які томи містять дані, що мають бути збережені. І навпаки, клас розробки з Retain не є негайно небезпечним для даних, але він може тихо накопичувати осиротілі диски та витрати.

+------------+ +----------------+ +--------------------+
| PVC action | --> | PV policy | --> | Backend result |
+------------+ +----------------+ +--------------------+
| delete | | Delete | | remove storage |
| delete | | Retain | | keep storage |
+------------+ +----------------+ +--------------------+

Іспит CKA часто винагороджує точне спостереження понад широку теорію. Якщо ви можете показати клас заявки, описати клас, оглянути події та прочитати правильні логи контролера, ви зазвичай швидко локалізуєте шар, що дає збій. Уникайте зміни кількох об’єктів одночасно під час діагностики. Зробіть одну зміну, яка відповідає одній гіпотезі, потім перевірте події знову. Ця дисципліна має значення, бо об’єкти сховища можуть створювати реальні ресурси бекенду, а необережні повтори можуть залишити по собі томи.

Усередині кожного збою також ховається проєктний урок. PVC у стані Pending учать вас чітко називати класи й установлювати правильний провізіонер. Томи в неправильній зоні вчать відкладати прив’язку для топологічно обізнаного сховища. Інциденти розширення вчать вмикати зростання до того, як прийде тиск. Помилки з політикою повторного використання вчать відокремлювати одноразові та захищені дані. Хороша вправа в модулі — не лише спосіб скласти лабораторну роботу; це репетиція читання цих виробничих сигналів по порядку.

Проєктні нотатки з урахуванням постачальника

Розділ «Проєктні нотатки з урахуванням постачальника»

Хмарне блокове сховище зручне, бо відчувається як диск, але ця простота обмежена топологією та правилами приєднання. Класи EBS, Persistent Disk та Azure Disk мають робити поведінку зон явною через відкладену прив’язку, якщо ваша платформа не має конкретної причини обрати інакше. Їхні налаштування продуктивності мають бути прив’язані до очікувань робочого навантаження, а не до загального уявлення про «швидкість». Кеш, реляційна база даних і робочий простір збірки можуть усі використовувати блокове сховище, проте вони мають різні потреби щодо збереження та розширення.

Мережеве файлове сховище має іншу форму. Воно може бути досяжним з багатьох нод і може підтримувати режими доступу, яких не можуть блокові диски. Це може зробити Immediate прийнятним, бо сховище не створюється в одній зоні приєднання, але це не усуває потреби розуміти обмеження бекенду. Спільні файлові системи можуть мати власні квоти, дозволи, патерни затримки та режими збоїв. StorageClass усе одно представляє контракт політики, навіть коли розміщення в зоні менш центральне.

Динамічне виділення на основі local-path та hostPath — чудові навчальні інструменти, бо вони роблять створення PV видимим у невеликому кластері. Це також найлегше місце засвоїти неправильний урок. Локальний шлях не реплікується магічним чином лише тому, що Kubernetes створив для нього об’єкт PV. Якщо ноду втрачено, спорожнено (drained) чи вона недоступна, шлях до даних теж може бути недоступним. Використовуйте локальні провізіонери для лабораторних робіт, крайових випадків і свідомих проєктів локального сховища, а не як випадкову заміну надійному сховищу.

CSI-сайдкари пояснюють, чому усунення несправностей StorageClass часто потребує більш ніж одного логу контролера. Зовнішній провізіонер стежить за PVC і створює томи, зовнішній resizer реагує на запити розширення, а інші сайдкари обробляють приєднання, знімки чи реєстрацію залежно від драйвера. Вам не потрібно запам’ятовувати кожен сайдкар для іспиту CKA, але ви маєте знати, що збій сховища може статися після того, як PVC прийнято. Kubernetes зберігає бажаний стан; компоненти CSI узгоджують цей стан із бекендом.

Для виробничої платформи імена класів мають бути частиною інтерфейсу користувача. Розробникові не повинно бути потрібно знати, що gp3 — це тип диска, лише щоб обрати безпечне сховище за замовчуванням, але платформенна команда має задокументувати, що означають standard, database-retain чи shared-rwx. Хороші імена зменшують кількість заявок до підтримки, бо вони спрямовують поведінку ще до того, як хтось напише YAML. Погані імена змушують користувачів читати параметри постачальника й гадати, який клас захищає їхнє робоче навантаження.

Політика допуску може зробити StorageClass безпечнішими, не роблячи їх загадковими. Кластер може вимагати явних класів у виробничих просторах імен, обмежувати дорогі класи схваленими командами або забороняти класи з Retain в одноразових середовищах. Ці політики живуть поза об’єктом StorageClass, але вони підкріплюють ті самі проєктні цілі. Модуль зосереджується на об’єктах Kubernetes, бо саме це перевіряє іспит, тоді як реальні платформи часто додають політику навколо цих об’єктів, щоб тримати вибір узгодженим.

Моніторинг завершує проєкт. Динамічне виділення ховає ручне створення дисків, тож операторам потрібна видимість кількості PVC, заявок у стані Pending, осиротілих збережених томів, подій розширення, тиску квот та помилок провізіонера. Клас, що працює під час лабораторної роботи, усе одно може бути операційно слабким, якщо ніхто не бачить невдалих викликів до бекенду чи покинутих томів. Коли ви проєктуєте клас, також вирішіть, як ви помітите, що його використовують неправильно чи що він дає збій.

Практичне правило просте: ставтеся до StorageClass як до надійних платформенних API. Щойно команди закладають їх у маніфести, зміна семантики може зруйнувати припущення про вартість, видалення, планування та відновлення. Створіть невеликий набір, задокументуйте їх, протестуйте на реальних PVC і подах та уникайте необачної зміни наявних класів. Коли семантику необхідно змінити, створіть нове ім’я класу й свідомо мігруйте користувачів замість тихої зміни значення старого імені.

Швидке читання команд для іспиту

Розділ «Швидке читання команд для іспиту»

Іспит CKA не вимагає пам’ятати кожен параметр постачальника, але він вимагає ефективно читати стан Kubernetes. Виробіть звичку парувати коротку команду з питанням. kubectl get storageclass відповідає «які політики існують?» kubectl describe persistentvolumeclaim відповідає «на що чекає Kubernetes?» kubectl get persistentvolume відповідає «що було створено?» kubectl logs на провізіонері відповідає «що відхилив бекенд?»

Коли часу обмаль, не починайте з редагування YAML. Спершу спостерігайте, бо правки сховища можуть створювати чи видаляти ресурси бекенду. Єдиний kubectl describe може показати, що PVC лише чекає на першого споживача, а це означає, що правильний наступний крок — створити под, а не змінювати клас. Інший describe може показати помилку провізіонера, а це означає, що редагування пода змарнує час. Спостереження захищає і ваш бал, і ваші дані.

Та сама звичка читання команд застосовна й до очищення. Якщо клас використовує Delete, видалення заявки може прибрати резервний том. Якщо клас використовує Retain, видалення заявки може залишити вивільнений PV і бекенд-сховище, що потребує ручної обробки. Перш ніж видаляти об’єкти сховища у спільному середовищі, читайте політику повторного використання й підтверджуйте, чи є дані одноразовими. У екзаменаційній лабораторії очищення зазвичай безпечне, але звичка все одно має бути свідомою.

Нарешті, пам’ятайте, що проблеми StorageClass рідко розв’язуються однією універсальною командою. Правильна команда залежить від того, який шар під підозрою. Події PVC указують на статус заявки та виділення, YAML StorageClass указує на політику, події пода вказують на планування та монтування, а логи контролера вказують на виклики до бекенду. Якщо ви можете пояснити, який шар перевіряє команда, ви вже мислите як оператор, а не як той, хто завчив команди.


Патерни та антипатерни

Розділ «Патерни та антипатерни»

Патерни для StorageClass переважно про те, щоб зробити безпечний вибір простим. Хороша платформа надає невеликий набір іменованих класів, які відображають реальні потреби робочих навантажень, а потім документує, який клас використовувати для розробки, виробничих баз даних, спільних файлів, локальних лабораторій і високопродуктивних навантажень. Забагато класів перекладають специфічну для постачальника складність назад на прикладні команди. Замало класів змушують критичні та одноразові навантаження проходити через одну й ту саму політику.

ПатернКоли застосовуватиЧому це працюєАспект масштабування
Загальний клас за замовчуваннямБільшості просторів імен потрібне звичайне сховище RWOРозробники можуть безпечно опускати storageClassNameТримайте вартість і поведінку повторного використання консервативними
Клас Retain для виробничих данихБази даних і системи зі станом із потребами у відновленніВипадкове видалення PVC не видаляє том бекендуПотребує процесу очищення для виведених томів
WaitForFirstConsumer для топологічно обізнаного сховищаЗональні хмарні диски та локальне сховищеПланувальник і провізіонер узгоджують розміщення на ноді чи в зоніПарується з мітками нод та обмеженнями планування подів
Розширювані класи для зростаючих данихЛоги, бази даних, реєстри та кешіОператори можуть збільшувати ємність без заміни заявкиМоніторте квоту й вартість, щоб зростання залишалося видимим

Антипатерни зазвичай походять від копіювання StorageClass без розуміння середовища. YAML може бути дійсним, але в кластері може бракувати драйвера, бекенд може відхиляти параметр, або обрана політика може конфліктувати з життєвим циклом даних. Ставтеся до StorageClass як до платформенних контрактів, звернених до API. Щойно команди залежать від них, зміна семантики може вплинути на багато робочих навантажень, навіть попри те, що сам об’єкт виглядає малим.

АнтипатернЩо йде не такКраща альтернатива
Один клас із назвою fast для кожного навантаженняКоманди не можуть визначити вартість, надійність чи поведінку повторного використання за назвоюВикористовуйте назви, що описують намір, як-от standard-delete чи prod-retain
Immediate для зональних дисківТоми можуть створюватися в зоні, яку под-споживач не може використатиВикористовуйте WaitForFirstConsumer для топологічно чутливого сховища
Кілька класів за замовчуваннямPVC без класу можуть використати несподіваний бекендТримайте рівно один дефолт і перевіряйте анотації після змін
Retain усюдиВидалені тестові PVC залишають по собі томи, за які виставляється рахунокВикористовуйте Delete для одноразових класів і Retain для захищених даних
Параметри постачальника, скопійовані між хмарамиПровізіонування зазнає збою, бо ключі драйвера різнятьсяЧитайте документацію встановленого драйвера й перевіряйте малим PVC
Розширення вимкнено за звичкоюІнциденти потребують міграції замість простого збільшення PVCВмикайте розширення там, де драйвер його підтримує, і контролюйте зростання квотою

Найсильніший патерн — проєктувати StorageClass у зворотному напрямку від наміру навантаження. Запитайте, що навантаженню потрібно для доступності, продуктивності, безпеки видалення, розширення, топології та вартості. Потім оберіть драйвер і параметри, що виражають цей намір. Цей підхід повільніший за копіювання першого прикладу з документації, але він дає класи, що переживають реальний експлуатаційний тиск.


Структура прийняття рішень

Розділ «Структура прийняття рішень»

Використовуйте процес прийняття рішень нижче, коли вам потрібно спроєктувати чи налагодити клас. Починайте з топології, бо неправильний режим прив’язки може зупинити под ще до того, як застосунок взагалі запуститься. Потім обирайте поведінку життєвого циклу, бо політика видалення впливає на безпеку даних. Нарешті обирайте параметри постачальника, бо вони тонко налаштовують продукт сховища після того, як більші експлуатаційні рішення вже правильні.

+--------------------------------------------------------------+
| StorageClass Decision Path |
+--------------------------------------------------------------+
| Does storage attach only in one zone or on one node? |
| yes -> use WaitForFirstConsumer |
| no -> Immediate may be acceptable for network storage |
| |
| Is the data disposable after PVC deletion? |
| yes -> reclaimPolicy: Delete |
| no -> reclaimPolicy: Retain |
| |
| Can the workload grow over time? |
| yes -> allowVolumeExpansion: true if the driver supports it|
| no -> document why expansion is intentionally disabled |
| |
| Do teams need different cost or performance tiers? |
| yes -> create a small named set of classes |
| no -> keep one clear default class |
+--------------------------------------------------------------+
РішенняНадавайте перевагуУникайтеПричина
Невідомий провізіонер кластераОгляньте наявні класи та поди CSIВгадування імені драйвераІмена провізіонерів специфічні для встановлення
Зональне блокове сховищеWaitForFirstConsumerImmediateВідкладена прив’язка запобігає томам у неправильній зоні
Прив’язка до статичного PVstorageClassName: "" на PV та PVCОпускання поля на PVCОпускання може викликати клас за замовчуванням
Видалення виробничих данихRetain плюс runbook очищенняDelete за звичкоюПеревірка людиною захищає дані під час помилок
Лабораторні чи preview-середовищаDelete плюс квотиRetain усюдиАвтоматичне очищення запобігає витоку дисків
Зростання бази данихУвімкнене й моніторене розширенняПерестворення PVC під тискомРозширення безпечніше за міграцію під час інцидентів

Який підхід ви б тут обрали і чому: двовузловій локальній лабораторії потрібні швидкі PVC для вправ, тоді як багатозональному виробничому кластеру потрібні диски для баз даних. Лабораторія може прийняти клас local-path із Delete, бо дані одноразові. Виробничий кластер має використовувати встановлений драйвер CSI, відкладену прив’язку, увімкнене розширення, шифрування за потреби та політику повторного використання, обрану за стандартом збереження даних.

Структура також допомагає під час аналізу збоїв. Якщо PVC у стані Pending, класифікуйте очікування: замовчування, статична прив’язка, відкладена прив’язка, відсутній провізіонер, недійсний запит до бекенду чи конфлікт планувальника. Кожна категорія має іншу наступну команду. Хороше усунення несправностей — це не запуск кожної відомої вам команди; це вибір команди, яка перевіряє наступну найімовірнішу ланку в ланцюгу.


  • Kubernetes підтримує API StorageClass storage.k8s.io/v1 як стабільний API уже багато років, тому сучасні приклади не повинні використовувати стару бета-групу API. Вбудований провізіонер kubernetes.io/aws-ebs було вилучено в Kubernetes 1.27, тож нові кластери мають натомість використовувати драйвер EBS CSI (ebs.csi.aws.com).
  • Анотація storageclass.kubernetes.io/is-default-class може бути присутньою на більш ніж одному класі, і Kubernetes обирає найновіший створений дефолт для PVC, що опускає storageClassName.
  • WaitForFirstConsumer став стабільною поведінкою StorageClass, щоб топологічно обізнане виділення могло чекати на рішення планувальника про под, а не вгадувати зону надто рано.
  • Розширення PVC може збільшити запитуване сховище, але Kubernetes не підтримує зменшення PVC, тож помилково завеликий запит потребує плану міграції, а не зворотного патча.

ПомилкаЧому вона трапляєтьсяЯк її виправити
Кілька класів StorageClass за замовчуваннямКоманди патчать дефолти під час міграцій і забувають прибрати старішу анотаціюТримайте рівно один дефолт і перевіряйте kubectl get storageclass після змін
Неправильний провізіонер для платформиПриклади копіюють з іншої хмари чи зі застарілої вбудованої документаціїОгляньте встановлені драйвери CSI й використовуйте точний рядок провізіонера, за яким вони стежать
Режим Immediate із зональним сховищемКлас скопійовано з прикладу мережевого сховища без урахування топологіїВикористовуйте WaitForFirstConsumer для EBS, Persistent Disk, Azure Disk і локального сховища
Забуте allowVolumeExpansionПерший PVC працює, тож майбутнє зростання ігнорують аж до інцидентуВмикайте розширення там, де драйвер його підтримує, і керуйте зростанням квотами
Неправильні параметри для провізіонераНазви параметрів виглядають переносними, але це специфічні для драйвера рядкиПеревіряйте документацію постачальника й читайте логи провізіонера на повідомлення про відхилення бекендом
Спроба зменшити PVCОператори припускають, що запити сховища поводяться як запити CPU та пам’ятіМігруйте дані до меншого PVC, бо Kubernetes підтримує розширення, а не зменшення
Опускання storageClassName для статичної прив’язкиПорожнє поле плутають із порожнім рядкомВикористовуйте storageClassName: "" на PVC і відповідний статичний PV під час відмови від класу

Q1: Розробник створює PVC у кластері з класом StorageClass за замовчуванням на ім'я `gp3-standard`, але очікував, що той прив'яжеться до вручну створеного PV. Натомість з'являється новий динамічний PV. Що сталося і як слід було написати заявку?

Коли storageClassName опущено, Kubernetes може застосувати клас StorageClass за замовчуванням, тож PVC запросив динамічне виділення через gp3-standard. Ручний PV не було проігноровано випадково; заявка попросила клас за замовчуванням опусканням поля. Щоб прив’язатися лише до статичного PV без класу, задайте storageClassName: "" на PVC і переконайтеся, що PV також не має класу. Саме це розрізнення робить опущене поле й порожній рядок різними в специфікаціях PVC.

Q2: Багатозональне навантаження AWS використовує клас із `volumeBindingMode: Immediate`, а потім под приземляється в зоні, відмінній від нового тому EBS. Що спричинило збій приєднання і яке налаштування класу йому запобігає?

Immediate дозволив провізіонеру створити том до того, як планувальник обрав ноду для пода. Томи EBS є зональними, тож том в одній зоні не може приєднатися до ноди в іншій зоні. WaitForFirstConsumer запобігає невідповідності, відкладаючи виділення, доки под не отримає рішення планувальника. Мережеве сховище на кшталт NFS відрізняється, бо воно не приєднане до однієї зонально-специфічної ноди в той самий спосіб.

Q3: PVC бази даних патчиться з `50Gi` до `100Gi`, і `kubectl describe` показує `FileSystemResizePending`. Чи має оператор перестворити PVC?

Перестворення PVC — неправильна перша реакція, бо FileSystemResizePending може бути частиною нормального потоку розширення. Це означає, що ємність бекенду оброблено, але файлова система всередині змонтованого тому ще потребує зростання. Оператор має перевірити, чи запущений под, чи драйвер підтримує онлайн-розширення файлової системи і чи потрібен перемонтаж або перезапуск. Перестворюйте чи мігруйте лише тоді, коли драйвер не може завершити розширення або клас його ніколи не дозволяв.

Q4: Адміністратор знаходить два класи, анотовані як дефолтні, — `gp3-fast` і `standard-hdd`. PVC без `storageClassName` використав повільніший клас. Як адміністратору виправити політику кластера?

Kubernetes розв’язує кілька дефолтів, обираючи найновіший створений клас за замовчуванням, але така поведінка заплутує користувачів. Адміністратор має прибрати анотацію дефолту з ненавмисного класу й перевірити, що лише один клас показано як дефолтний. Наявні PV, уже провізіоновані з неправильного класу, не зміняться лише тому, що анотацію виправлено. Навантаження, яким потрібен інший бекенд, мають отримати нові PVC з використанням потрібного класу.

Q5: Виробничий StorageClass використовував `reclaimPolicy: Delete`, і кілька PV вже було створено з нього. Чи може перестворення StorageClass захистити ці наявні PV?

Перестворення StorageClass змінює поведінку лише для майбутніх динамічно створених PV. Наявні PV зберігають політику повторного використання, яку отримали під час створення. Щоб захистити ці томи, адміністратор має оглянути та запатчити PV напряму, якщо організація вирішить, що їх слід зберегти. Саме тому політика повторного використання є налаштуванням з великим впливом, навіть попри те, що це лише один рядок у класі.

Q6: PVC у стані Pending, клас використовує `WaitForFirstConsumer`, і жоден под наразі не посилається на заявку. Чи є стан Pending збоєм?

Не обов’язково. За WaitForFirstConsumer виділення та прив’язку може бути навмисно відкладено, доки под не використає заявку. Наступний крок — створити чи оглянути под-споживач і прочитати його події планування. Якщо под існує, а планування все одно не може просунутися, то досліджуйте обмеження топології, логи провізіонера та параметри StorageClass. Трактування кожного PVC у стані Pending як збою провізіонера може призвести до непотрібних змін класу.

Q7: Вам потрібен один клас для одноразових preview-середовищ і один клас для виробничих баз даних. Як би ви порівняли вибір політики повторного використання, режиму прив'язки та розширення?

Для preview-середовищ зазвичай доречне Delete, бо дані одноразові, а автоматичне очищення запобігає витоку томів. Для виробничих баз даних Retain часто безпечніший, бо видалення PVC не повинно негайно видаляти диск бекенду. Обидва класи зазвичай мають використовувати WaitForFirstConsumer для зонального блокового сховища, а виробничий клас має вмикати розширення, коли драйвер його підтримує. Preview-клас також може вмикати розширення, але квоти й контроль вартості мають тримати тимчасові середовища в межах.


Практична вправа: динамічне виділення

Розділ «Практична вправа: динамічне виділення»

Сценарій вправи: ви створите StorageClass, створите PVC, який його використовує, приєднаєте цю заявку до пода й переконаєтеся, що PV з’являється динамічно. Лабораторна робота найкраще працює на кластері з локальним провізіонером, як-от kind із провізіонером local-path від Rancher чи minikube з його провізіонером hostPath. Якщо ваш кластер використовує інший провізіонер, адаптуйте лише поле provisioner і залиште діагностичний потік тим самим.

Завдання 1: Перевірте наявні класи StorageClass

Розділ «Завдання 1: Перевірте наявні класи StorageClass»

Почніть із читання кластера, а не з вгадування. Перша команда показує імена, які можуть запитувати користувачі, а друга команда розкриває рядок провізіонера та анотацію дефолту. Якщо клас за замовчуванням уже є, занотуйте його перед опціональним завданням про дефолт, щоб згодом ви могли відновити вихідну політику кластера.

Terminal window
# See what's available
kubectl get storageclass
# Check if there's a default
kubectl get storageclass -o custom-columns='NAME:.metadata.name,PROVISIONER:.provisioner,DEFAULT:.metadata.annotations.storageclass\.kubernetes\.io/is-default-class'
Підказка до розв'язання

Ви маєте побачити принаймні один StorageClass, якщо ваш кластер має налаштоване динамічне виділення. У kind провізіонером часто є rancher.io/local-path; у minikube — часто k8s.io/minikube-hostpath. Якщо список порожній, ви все одно можете вивчати YAML, але завдання з динамічного виділення не вдадуться, доки не буде встановлено провізіонер.

Завдання 2: Створіть StorageClass

Розділ «Завдання 2: Створіть StorageClass»

Цей приклад використовує провізіонер local-path, бо він поширений у практичних кластерах на основі kind. Не копіюйте цей рядок провізіонера в хмарний кластер, якщо цей драйвер фактично не встановлено. Важлива поведінка для спостереження — це WaitForFirstConsumer: PVC може існувати до створення PV, а под запустить остаточне рішення про виділення.

Terminal window
cat <<EOF | kubectl apply -f -
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast
provisioner: rancher.io/local-path # For kind; change for your cluster
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
EOF

Розширення тому — переважно функція хмарного CSI; на встановленнях rancher.io/local-path це поле може бути прийняте, але мовчки проігноровано.

Підказка до розв'язання

kubectl get storageclass fast -o yaml має показати клас із провізіонером, політикою повторного використання, режимом прив’язки та налаштуванням розширення, які ви застосували. Якщо API відхиляє об’єкт, спершу перевірте відступи та назви полів. Якщо об’єкт прийнято, але пізніші заявки не прив’язуються, наступна ймовірна проблема — що жоден контролер не стежить за рядком провізіонера.

Завдання 3: Створіть PVC, що використовує StorageClass

Розділ «Завдання 3: Створіть PVC, що використовує StorageClass»

Створіть малий PVC, який явно називає клас. Оскільки клас використовує WaitForFirstConsumer, справна заявка може залишатися у стані Pending, доки под її не використає. Цей стан Pending — поведінка, яку ви хочете спостерігати; він доводить, що режим прив’язки впливає на робочий процес.

Terminal window
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: dynamic-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: fast
EOF
# Check status - should be Pending when waiting for a consumer
kubectl get persistentvolumeclaim dynamic-pvc
Підказка до розв'язання

Якщо PVC у стані Pending з подією про очікування першого споживача, це очікувано. Якщо він прив’язується негайно, ваш провізіонер чи кластер може реалізовувати іншу локальну поведінку, або клас не було застосовано як очікувалося. Якщо він у стані Pending з помилками виділення, читайте події й переконайтеся, що fast називає провізіонер, який існує у вашому кластері.

Завдання 4: Створіть под, щоб запустити виділення

Розділ «Завдання 4: Створіть под, щоб запустити виділення»

Под — це перший споживач. Коли планувальник розміщує цей под, система сховища має достатньо контексту топології, щоб провізіонувати резервний том. Контейнер записує невелике повідомлення в змонтований шлях, щоб ви могли перевірити, що змонтований PVC придатний до використання, а не лише прив’язаний.

Terminal window
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: dynamic-pod
spec:
containers:
- name: app
image: busybox:1.36
command: ['sh', '-c', 'echo "Dynamically provisioned!" > /data/message; sleep 3600']
volumeMounts:
- name: storage
mountPath: /data
volumes:
- name: storage
persistentVolumeClaim:
claimName: dynamic-pvc
EOF
Підказка до розв'язання

Після створення пода PVC має перейти до стану Bound, і має з’явитися PV зі згенерованим іменем. Якщо под не може сплануватися, опишіть под і перевірте повідомлення про ноду, taint і топологію. Якщо под планується, але заявка залишається у стані Pending, опишіть PVC і огляньте логи провізіонера.

Завдання 5: Перевірте динамічне виділення

Розділ «Завдання 5: Перевірте динамічне виділення»

Перевірка має слідувати ланцюгу об’єктів. Дочекайтеся пода, перевірте PVC, визначте згенерований PV, підтвердьте, що PV записує очікуваний клас, а потім прочитайте повідомлення зі змонтованого шляху. Ця послідовність доводить, що клас, заявка, том і под з’єднані.

Terminal window
# Wait for pod to trigger provisioning and become ready
kubectl wait --for=condition=Ready pod/dynamic-pod --timeout=60s
# PVC should now be Bound
kubectl get persistentvolumeclaim dynamic-pvc
# STATUS: Bound
# A PV was automatically created
kubectl get persistentvolume
# Should see a dynamically named PV like pvc-xxxxx
# Check the PV details accurately
PV_NAME=$(kubectl get persistentvolumeclaim dynamic-pvc -o jsonpath='{.spec.volumeName}')
kubectl get persistentvolume "$PV_NAME" -o jsonpath='{.spec.storageClassName}{"\n"}'
# Should show: fast
# Verify pod can read the dynamically provisioned storage
kubectl exec dynamic-pod -- cat /data/message
Підказка до розв'язання

PVC має бути у стані Bound, PV має називати StorageClass fast, а под має вивести Dynamically provisioned!. Якщо змінна PV_NAME порожня, заявка ще не прив’язалася. Скористайтеся kubectl describe persistentvolumeclaim dynamic-pvc та kubectl describe pod dynamic-pod, щоб вирішити, чи затримка пов’язана з планувальником, провізіонером чи бекендом.

Завдання 6: Протестуйте клас StorageClass за замовчуванням

Розділ «Завдання 6: Протестуйте клас StorageClass за замовчуванням»

Цей крок опціональний, бо зміна дефолтів впливає на інші PVC у кластері. В одноразовій лабораторії позначте клас fast як дефолтний, створіть PVC без storageClassName і підтвердьте, що Kubernetes застосовує клас за замовчуванням. У спільному кластері пропустіть це завдання або відновіть вихідний дефолт одразу після тестування.

Terminal window
# Make our StorageClass the default
kubectl patch storageclass fast -p '{"metadata": {"annotations": {"storageclass.kubernetes.io/is-default-class": "true"}}}'
# Create PVC without storageClassName
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: default-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 500Mi
# No storageClassName - uses default
EOF
# Check it uses the default class
kubectl get persistentvolumeclaim default-pvc -o jsonpath='{.spec.storageClassName}{"\n"}'
# Should show: fast
Підказка до розв'язання

PVC має показати fast як свій клас сховища після замовчування. Якщо ні, перевірте, чи існує інший клас за замовчуванням і чи вдався ваш патч анотації. Пам’ятайте, що кілька дефолтів можуть дати несподівані результати, тож використовуйте kubectl get storageclass до й після тесту.

  • StorageClass створено успішно.
  • PVC залишається у стані Pending до створення пода, коли активний WaitForFirstConsumer.
  • PV створюється автоматично, коли под заплановано.
  • Под може записувати в динамічно провізіоноване сховище й читати з нього.
  • Поведінку класу StorageClass за замовчуванням перевірено або навмисно пропущено у спільному кластері.
  • Діагностуйте PVC у стані Pending, приєднання до неправильної зони, невдале розширення, недійсні параметри та збої контролера-провізіонера за допомогою подій і логів.
  • Ви можете пояснити зв’язок між StorageClass, PVC, PV, провізіонером і плануванням подів.

Очищення має прибрати под перед PVC, щоб том не був змонтований під час видалення заявки. За reclaimPolicy: Delete видалення PVC має також прибрати динамічно провізіонований PV і його бекенд-сховище. Якщо ви змінювали дефолт спільного кластера, відновіть вихідну анотацію дефолту в межах очищення.

Terminal window
kubectl delete pod dynamic-pod
kubectl delete persistentvolumeclaim dynamic-pvc default-pvc
kubectl delete storageclass fast

Тренувальні вправи

Розділ «Тренувальні вправи»

Використовуйте ці короткі вправи після основної лабораторної роботи, щоб напрацювати швидкість. Вони зберігають ті самі дії з оригінального модуля, але команди написано з повним kubectl, щоб вони працювали при копіюванні в неінтерактивну оболонку. Для кожної вправи назвіть очікуваний результат, перш ніж запускати команду.

Terminal window
# Drill 1: List all StorageClasses and identify the default
kubectl get storageclass
Terminal window
# Drill 2: Create StorageClass "slow" with provisioner rancher.io/local-path
cat <<EOF | kubectl apply -f -
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: slow
provisioner: rancher.io/local-path
reclaimPolicy: Retain
EOF
Terminal window
# Drill 3: Make StorageClass "standard" the default
# Use annotation: storageclass.kubernetes.io/is-default-class: "true"
Terminal window
# Drill 4: Create PVC "data-pvc" requesting 5Gi with StorageClass "fast"
Terminal window
# Drill 5: Create PVC that will not use any StorageClass
# Hint: storageClassName: ""
Terminal window
# Drill 6: Diagnose why a PVC is stuck in Pending
kubectl describe persistentvolumeclaim <name>
# Check Events section for errors
Terminal window
# Drill 7: Create StorageClass with volume expansion enabled
# Key field: allowVolumeExpansion: true
Terminal window
# Drill 8: Check the volumeBindingMode of StorageClass "standard"
kubectl get storageclass standard -o jsonpath='{.volumeBindingMode}{"\n"}'

Перевірка для учня

Розділ «Перевірка для учня»

Розширення тому — переважно функція хмарного CSI; на встановленнях rancher.io/local-path це поле може бути прийняте, але мовчки проігноровано.

Чому слід перевіряти поведінку розширення на власному кластері, а не покладатися лише на allowVolumeExpansion: true?

Перейдіть до Модуля 4.4: Знімки та клонування томів, щоб дізнатися про функції резервного копіювання та захисту даних для сховища Kubernetes.