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

Модуль 4.5: Усунення проблем зі сховищем

Hands-On Lab Available
K8s Cluster advanced 40 min
Launch Lab ↗

Opens in Killercoda in a new tab

Складність: [СЕРЕДНЯ] — діагностика та виправлення проблем зі сховищем.

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

Передумови: Модуль 4.1, Модуль 4.2, Модуль 4.3 та Модуль 4.4.


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

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

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

  • Діагностувати збої сховища системно — від PVC у стані Pending до помилок монтування, проблем з місткістю та симптомів «у доступі відмовлено» (permission denied).
  • Простежити ланцюжок надання сховища від Pod’а до PVC, StorageClass, провізіонера, PV, приєднання до ноди й остаточного монтування.
  • Виправити типові проблеми зі сховищем, обираючи найменш руйнівне виправлення для прив’язки, режиму доступу, квоти та проблем з власністю.
  • Спроєктувати контрольний список з усунення проблем сховища, який працює як у сценаріях іспиту CKA, так і у реагуванні на виробничі інциденти.

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

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

Гіпотетичний сценарій: розгортання Deployment виглядає буденним, аж поки половина подів не залишається у стані ContainerCreating, а застосунок не починає віддавати застарілі дані з реплік, що вціліли. Образ контейнера справний, проби звичайні, а планувальник розмістив поди на нодах — проте робоче навантаження не може відкрити свій каталог даних. У цей момент перезапуск подів — це переважно шум, бо збій лежить не всередині процесу застосунку; він десь у контракті між заявкою, томом, драйвером сховища, нодою та поданням файлової системи всередині контейнера.

Усунення проблем сховища важливе тому, що Kubernetes навмисно розподіляє відповідальність між кількома контролерами. Планувальник міркує про ноди, контролер персистентних томів міркує про заявки, зовнішній CSI-провізіонер спілкується з бекендом сховища, контролер приєднання-від’єднання координує приєднання до ноди, а kubelet виконує монтування, яке контейнер зрештою бачить. Цей розподіл потужний, але він означає, що видимий симптом на кшталт Pending, FailedMount чи Permission denied сам по собі рідко називає всю першопричину.

Іспит CKA винагороджує інженерів, які вміють швидко звузити шлях збою, не пошкоджуючи при цьому стан системи. На виробництві та сама звичка запобігає ризикованим виправленням — як-от видаленню PVC до прочитання його політики повернення (reclaim policy) чи примусовому видаленню старого пода до того, як ви довели, що збійна нода більше не пише в том із режимом ReadWriteOnce. Цей модуль навчає повторюваного шляху, який можна застосувати знову і знову: почати з події пода, простежити граф об’єктів сховища, перевіряти контролер чи драйвер лише тоді, коли докази вказують саме туди, і обрати виправлення, яке передусім зберігає дані.

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


Почніть з моделі збою сховища

Розділ «Почніть з моделі збою сховища»

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

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

┌─────────────────────────────────────────────────────────────────────┐
│ Storage Troubleshooting Path │
│ │
│ Pod Issue │
│ │ │
│ ▼ │
│ 1. kubectl describe pod <name> │
│ └─► Check Events section │
│ └─► Check volume mount errors │
│ │ │
│ ▼ │
│ 2. kubectl get pvc <name> │
│ └─► Is STATUS "Bound"? │
│ └─► If "Pending", check Events │
│ │ │
│ ▼ │
│ 3. kubectl get pv │
│ └─► Does matching PV exist? │
│ └─► Is STATUS "Available" or "Bound"? │
│ │ │
│ ▼ │
│ 4. kubectl get sc <storageclass> │
│ └─► Does StorageClass exist? │
│ └─► Is provisioner correct? │
│ │ │
│ ▼ │
│ 5. Check CSI driver │
│ └─► Is driver installed? │
│ └─► Check driver pod logs │
│ │
└─────────────────────────────────────────────────────────────────────┘

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

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

Terminal window
# Pod-level debugging
kubectl describe pod <pod-name>
kubectl get pod <pod-name> -o yaml
kubectl logs <pod-name>

Под — правильна точка входу, бо він поєднує подання планування, тому й контейнера. kubectl describe pod особливо корисна, бо розділ Events часто містить точне повідомлення, видане операцією приєднання чи монтування. kubectl logs допомагає лише після того, як контейнер запустився; коли под усе ще в стані ContainerCreating, події зазвичай важливіші за журнали застосунку.

Terminal window
# PVC debugging
kubectl get pvc
kubectl describe pvc <pvc-name>
kubectl get pvc <pvc-name> -o yaml

PVC каже вам, чи задовольнив Kubernetes заявку. Заявка у стані Bound означає, що площина управління знайшла або створила PV, тоді як Pending означає, що прив’язка все ще очікує або зазнала невдачі. Подання YAML корисне, коли вам потрібні точні поля — як-от storageClassName, запитувана місткість, режими доступу, анотації обраної ноди чи повідомлення про умови (conditions).

Terminal window
# PV debugging
kubectl get pv
kubectl describe pv <pv-name>
kubectl get pv <pv-name> -o yaml

PV має область видимості кластера, тож він може пережити простір імен чи робоче навантаження, які першими його використали. Читайте PV, коли йдеться про статичне прив’язування, коли заявка, схоже, націлена на наявний том, або коли політика повернення впливає на безпечність видалення. PV у стані Released чи Failed — це не те саме, що Available PV, навіть якщо місткість та режими доступу на перший погляд виглядають привабливими.

Terminal window
# StorageClass debugging
kubectl get sc
kubectl describe sc <sc-name>
kubectl get sc <sc-name> -o yaml

StorageClass фіксує політику, а не конкретний диск. Він відповідає на запитання на кшталт: який провізіонер відповідальний, чи дозволено розширення, який режим прив’язки використовується та які параметри бекенду передаються драйверу. Багато PVC у стані Pending пояснюються неправильно написаним ім’ям класу, несподіваним класом за замовчуванням або поведінкою WaitForFirstConsumer, яка є нормальною, а не зламаною.

Terminal window
# Events, often the highest-signal view
kubectl get events --sort-by='.lastTimestamp'
kubectl get events --field-selector involvedObject.name=<pvc-name>
kubectl get events --field-selector involvedObject.name=<pod-name>

Події — це не повний журнал аудиту, але вони чудові орієнтири під час активного усунення проблем. Сортуйте за часовою позначкою, коли вам потрібні найновіші збої, і використовуйте селектори полів, коли простір імен зашумлений. Якщо ви бачите, що та сама подія повторюється, читайте і причину (reason), і повідомлення (message), бо причина часто загальна, а повідомлення містить деталь, специфічну для бекенду чи об’єкта.

Terminal window
# CSI debugging
kubectl get pods -n kube-system | grep csi
kubectl logs -n kube-system <csi-pod> -c <container>
kubectl get csidrivers
kubectl get csinode

Журнали CSI потужні, але вони не перша зупинка для кожної проблеми. Звертайтеся туди, коли події згадують зовнішнє провізіонування, імена драйверів, збої приєднання чи помилки API бекенду. У керованих кластерах контролер CSI та плагін ноди можуть бути встановлені поза простором імен вашого застосунку, тож простір імен та ім’я контейнера мають значення, коли ви отримуєте журнали.

Зупиніться та передбачте: якщо под застряг у стані ContainerCreating, але PVC, на який він посилається, уже у стані Bound, які два етапи конвеєра, ймовірно, завершилися, і який етап вам слід перевірити наступним?

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


Діагностуйте проблеми прив’язки PVC

Розділ «Діагностуйте проблеми прив’язки PVC»

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

Terminal window
kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS
my-pvc Pending fast-ssd

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

Terminal window
kubectl describe pvc my-pvc

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

Events:
Type Reason Message
---- ------ -------
Normal FailedBinding no persistent volumes available for this claim

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

Terminal window
kubectl get pvc my-pvc -o yaml | grep -A8 spec:
Terminal window
kubectl get pv
Terminal window
kubectl describe pv <pv-name>

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

Events:
Type Reason Message
---- ------ -------
Warning ProvisioningFailed storageclass.storage.k8s.io "fast-ssd" not found

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

Terminal window
kubectl get sc
Terminal window
kubectl delete pvc my-pvc
Terminal window
cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: standard
EOF

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

Events:
Type Reason Message
---- ------ -------
Warning ProvisioningFailed failed to provision volume: no csi driver
Terminal window
kubectl get csidrivers
Terminal window
kubectl get pods -n kube-system | grep csi

Відкладена прив’язка — це виняток, який збиває з пантелику багатьох учнів. PVC може залишатися Pending за задумом, коли StorageClass використовує volumeBindingMode: WaitForFirstConsumer, бо провізіонеру потрібен вибір ноди планувальником, перш ніж створювати том, прив’язаний до зони. Якби кластер створив том негайно, под пізніше міг би бути запланований на ноду в іншій зоні й не зміг би приєднатися.

Terminal window
kubectl get sc fast-ssd -o jsonpath='{.volumeBindingMode}'
WaitForFirstConsumer

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

Terminal window
kubectl get pvc my-pvc
STATUS: Pending

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

Terminal window
kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS
pv-1 100Gi RWO Retain Available
Terminal window
kubectl get pvc
NAME STATUS ACCESS MODES STORAGECLASS
my-pvc Pending RWX manual

Виправлення — скоригувати архітектуру, а не лише YAML. Якщо робоче навантаження потребує диска з єдиним записувачем, змініть PVC на ReadWriteOnce і запускайте робоче навантаження відповідно. Якщо кільком нодам справді потрібен спільний запис, оберіть бекенд, який підтримує ReadWriteMany, як-от належно налаштовану мережеву файлову систему чи хмарний файловий сервіс, і прийміть інші характеристики продуктивності та узгодженості.

Невідповідності StorageClass виглядають схоже, бо обидва об’єкти можуть здаватися дійсними окремо. PV із storageClassName: manual не задовольнить заявку, що просить fast, навіть коли місткість та режим доступу збігаються. Клас є частиною ідентичності прив’язки, тож порівнюйте його явно, коли відповідний PV здається очевидним, але контролер відмовляється прив’язувати.

Terminal window
kubectl get pv pv-1 -o jsonpath='{.spec.storageClassName}'
manual
Terminal window
kubectl get pvc my-pvc -o jsonpath='{.spec.storageClassName}'
fast

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

Terminal window
kubectl get pvc my-pvc -o yaml | grep -E 'storageClassName:|volumeName:|accessModes:|storage:'

Діагностуйте помилки монтування та приєднання тому

Розділ «Діагностуйте помилки монтування та приєднання тому»

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

Terminal window
kubectl get pods
NAME READY STATUS RESTARTS AGE
my-pod 0/1 Pending 0 5m

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

Terminal window
kubectl describe pod my-pod
Events:
Warning FailedScheduling 0/3 nodes are available:
persistentvolumeclaim "my-pvc" not found

Посилання на PVC є локальними для простору імен. Заявка з іменем my-pvc у default не задовольняє под у payments, а помилки в імені заявки достатньо, щоб затримати под перед плануванням. Саме тому ви завжди маєте включати простір імен у свої перевірки, коли под не у просторі імен default.

Terminal window
kubectl get pvc my-pvc -n <namespace>
Terminal window
kubectl get pod my-pod -n <namespace> -o yaml | grep -A6 persistentVolumeClaim

Помилки множинного приєднання (multi-attach) небезпечніші, бо вони часто стосуються реального тому та реальних даних. Том із режимом ReadWriteOnce може бути змонтований для читання-запису лише однією нодою за раз, тож под-заміна на іншій ноді може чекати, поки стара нода все ще володіє приєднанням. Це часто з’являється під час збоїв нод, повільного завершення чи ручного переміщення подів.

Events:
Warning FailedAttachVolume Multi-Attach error for volume "pvc-abc":
Volume is already attached to node "node-1"

Швидке виправлення з початкової версії модуля полягало в примусовому видаленні старого пода, але ця дія потребує контексту. Спершу доведіть, що старий под справді застряг, що стара нода несправна, а застосунок може витримати раптове завершення. Примусове видалення прибирає об’єкт API негайно; воно не гарантує, що процес зупинився чисто чи що файлову систему було чисто розмонтовано на недосяжній ноді.

Terminal window
kubectl get pod <old-pod> -o wide
Terminal window
kubectl get node node-1
Terminal window
kubectl describe node node-1 | grep -A8 Conditions

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

Terminal window
kubectl delete pod <old-pod> --force --grace-period=0
Terminal window
kubectl get volumeattachment

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

Events:
Warning FailedMount MountVolume.SetUp failed:
mount failed: exit status 32, permission denied

Виправлення засобами Kubernetes — зробити так, щоб контекст безпеки пода збігався з моделлю власності файлової системи. fsGroup просить kubelet зробити змонтований том доступним для групи, тоді як runAsUser змушує процес контейнера працювати від імені потрібного користувача. Це не безкоштовно на дуже великих томах, бо рекурсивне опрацювання власності може сповільнити перше монтування, але це зазвичай краще за повернення застосунку до root.

# Add securityContext to pod
spec:
securityContext:
fsGroup: 1000
containers:
- name: app
securityContext:
runAsUser: 1000
runAsNonRoot: true

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

Terminal window
kubectl exec my-pod -- id
Terminal window
kubectl exec my-pod -- ls -ld /data

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

Events:
Warning FailedMount hostPath type check failed:
path /data/myapp does not exist

Для лабораторій та контрольованих локальних сценаріїв на ноді DirectoryOrCreate дозволяє kubelet створити шлях, коли його немає. Це корисно для навчальних сценаріїв, але це не загальна заміна довговічному сховищу, бо hostPath прив’язує дані до однієї ноди й обходить багато гарантій ізоляції. На виробництві використовуйте hostPath ощадливо й зазвичай лише для агентів нод чи системних інтеграцій.

volumes:
- name: data
hostPath:
path: /data/myapp
type: DirectoryOrCreate

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

Events:
Warning FailedMount Unable to attach or mount volumes:
timeout expired waiting for volumes to attach
Terminal window
kubectl get pods -n kube-system | grep csi
Terminal window
kubectl logs -n kube-system <csi-controller-pod> -c csi-provisioner
Terminal window
kubectl describe node <node-name> | grep -A8 Conditions

Зупиніться й подумайте: под застряг у стані ContainerCreating, а подія каже Multi-Attach error. Ви знаєте, що том має режим ReadWriteOnce. Перш ніж примусово видаляти старий под, які докази переконали б вас, що старий записувач зник, і яку перевірку на рівні застосунку слід запустити після відновлення?


Діагностуйте проблеми з місткістю, розширенням та квотою

Розділ «Діагностуйте проблеми з місткістю, розширенням та квотою»

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

Terminal window
kubectl get pvc my-pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES
my-pvc Bound pvc-1a2b3c4d-1111-2222-3333-444455556666 10Gi RWO

Місткість PVC — це запитаний чи наданий розмір, а не поточне використання файлової системи. Щоб побачити, чи заповнив застосунок том, перевірте монтування зсередини пода. Це розрізнення важливе, бо Kubernetes може повідомляти про справну, прив’язану заявку, поки процес контейнера зазнає невдачі під час запису зі звичайними помилками No space left on device.

Terminal window
kubectl exec my-pod -- df -h /data
Filesystem Size Used Avail Use% Mounted on
/dev/xvdf 9.8G 9.6G 120M 99% /data

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

Terminal window
kubectl get sc <storageclass> -o jsonpath='{.allowVolumeExpansion}'
true
Terminal window
kubectl patch pvc my-pvc -p '{"spec":{"resources":{"requests":{"storage":"20Gi"}}}}'
Terminal window
kubectl describe pvc my-pvc | grep -A8 Conditions

Очищення даних також є дійсним виправленням, коли дані одноразові, але ставтеся до rm -rf як до рішення на рівні застосунку, а не до загальних ліків для сховища. Тимчасові файли, кеші та артефакти збірки часто можна безпечно видалити; файли баз даних, сегменти черг та завантаження користувачів — ні. У реальному регламенті (runbook) команда очищення має точно називати каталог та правило зберігання.

Terminal window
kubectl exec my-pod -- rm -rf /data/tmp/*

Збої місткості під час провізіонування з’являються до створення тому. Подія може казати insufficient capacity, або журнали CSI можуть нести специфічне для провайдера повідомлення про квоту, топологію, тип тому чи доступність бекенду. У просторах імен із ResourceQuota API Kubernetes може відхиляти чи затримувати запити навіть тоді, коли в бекенді сховища є місце.

Events:
Warning ProvisioningFailed insufficient capacity
Terminal window
kubectl get resourcequota -n <namespace>
Terminal window
kubectl get limitrange -n <namespace>

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

Terminal window
kubectl describe resourcequota -n <namespace>

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

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


Діагностуйте проблеми драйвера CSI та хмарних прав

Розділ «Діагностуйте проблеми драйвера CSI та хмарних прав»

Container Storage Interface дозволяє Kubernetes використовувати багато різних бекендів сховища через спільну модель інтеграції, але він також додає чимало рухомих частин. Типове розгортання CSI має компоненти контролера, які провізіонують та приєднують томи, компоненти ноди, які публікують томи на кожній окремій ноді, та сайдкари на кшталт зовнішнього провізіонера, приєднувача (attacher), розширювача (resizer) та снапшотера (snapshotter). Коли події об’єктів вказують саме на драйвер, вам потрібно знати, який конкретний компонент володіє провальною дією.

Terminal window
kubectl describe pvc my-pvc
Events:
Warning ProvisioningFailed error getting CSI driver name

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

Terminal window
kubectl get csidrivers
Terminal window
kubectl get csinode

Потім перевірте поди, які запускають драйвер. Керовані дистрибутиви відрізняються, але компоненти CSI зазвичай живуть у kube-system чи в іншому платформному просторі імен. Подивіться і на Deployment контролера, і на DaemonSet ноди, бо збої провізіонування й монтування можуть жити в різних компонентах.

Terminal window
kubectl get pods -n kube-system | grep csi
NAME READY STATUS RESTARTS
ebs-csi-controller-abc 0/6 CrashLoopBackOff 5

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

Terminal window
kubectl logs -n kube-system ebs-csi-controller-abc -c csi-provisioner
Terminal window
kubectl logs -n kube-system ebs-csi-controller-abc -c csi-attacher

Хмарні права — поширене джерело збоїв CSI, бо драйверу зазвичай потрібна ідентичність поза API Kubernetes. В AWS контролер EBS CSI зазвичай використовує права IAM через анотацію сервісного акаунта в кластерах стилю EKS. У GCP права можуть надавати Workload Identity чи сервісні акаунти нод. В Azure операції з дисками може авторизувати керована ідентичність чи сервісний принципал.

Terminal window
kubectl get sa -n kube-system ebs-csi-controller-sa -o yaml
metadata:
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/example-ebs-csi-role

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

Terminal window
kubectl describe sc <storageclass>
Terminal window
kubectl get sc <storageclass> -o yaml

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

Terminal window
kubectl describe pvc my-pvc
Terminal window
kubectl logs -n kube-system <csi-controller-pod> -c <driver-container>

Зупиніться та передбачте: под контролера CSI у стані CrashLoopBackOff, а журнали кажуть, що він не зміг прийняти роль IAM. YAML StorageClass та PVC не змінювалися. Який об’єкт Kubernetes ви б перевірили першим, і яку зовнішню конфігурацію ви б звірили після цього?


Побудуйте швидкий довідник, не пропускаючи діагностику

Розділ «Побудуйте швидкий довідник, не пропускаючи діагностику»

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

Повідомлення про помилкуІмовірна причинаШвидке виправлення
persistentvolumeclaim "..." not foundПод посилається на відсутню заявку, часто повідомляється як FailedScheduling до монтуванняВиправте claimName пода або створіть названу заявку в просторі імен пода
no persistent volumes availableНемає відповідного PV для статичного провізіонуванняСтворіть або полагодьте відповідний PV
storageclass not foundНеправильне ім’я StorageClassПеревірте доступні класи та видаліть + перестворіть PVC із дійсним класом
waiting for first consumerРежим прив’язки WaitForFirstConsumerСтворіть або перевірте под, що використовує PVC
Multi-Attach errorТом RWO запитано на кількох нодахПеревірте старий записувач, потім видаліть старий под чи скоригуйте планування
permission deniedНевідповідність власності файлової системи чи контексту безпекиВстановіть fsGroup, runAsUser та перевірте власність
path does not existСуворий тип hostPath із відсутнім шляхом на нодіСтворіть шлях або використайте DirectoryOrCreate у лабораторних сценаріях
timeout waiting for volumesПроблема драйвера CSI, бекенду чи приєднання на нодіПеревірте поди CSI, журнали, стан ноди та обмеження бекенду
insufficient capacityКвоту простору імен чи місткість бекенду вичерпаноПеревірте квоту, розмір запиту, топологію та місткість провайдера
volume is already attachedЗастаріле чи активне приєднання до іншої нодиПеревірте старий под, стан ноди та об’єкти VolumeAttachment

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

Terminal window
echo "=== PVCs ===" && kubectl get pvc && \
echo "=== PVs ===" && kubectl get pv && \
echo "=== StorageClasses ===" && kubectl get sc && \
echo "=== Recent Events ===" && kubectl get events --sort-by='.lastTimestamp' | tail -20
Terminal window
kubectl describe pod <pod-name>
Terminal window
kubectl describe pvc <pvc-name>
Terminal window
kubectl describe sc <storageclass>
Terminal window
kubectl get volumeattachment

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

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

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

ПатернКоли його використовуватиЧому він працюєЩо враховувати при масштабуванні
Трасування від споживача до постачальникаБудь-який збій сховища пода чи PVCПочинається з видимого симптому й слідує фактичному ланцюжку посилань об’єктівДобре працює у великих просторах імен, бо кожен крок звужує набір об’єктів
Діагностика з подій насампередЗбої Pending, ContainerCreating, приєднання чи монтуванняПодії зазвичай містять найновішу причину й повідомлення контролераЗберігання подій обмежене, тож фіксуйте корисні повідомлення під час активних інцидентів
Політика перед зміноюПеред видаленням PVC, PV чи старих подівПолітика повернення, режим доступу й режим прив’язки визначають ризик для данихПотребує регламентів, що називають безпечні умови видалення для кожного класу навантажень
Ескалація до драйвера за доказамиКоли події називають зовнішнє провізіонування, приєднання чи помилки API бекендуЖурнали CSI мають високий сигнал після того, як факти на рівні об’єктів вказали на драйверПлатформним командам слід задокументувати простори імен, імена контейнерів та ідентичності драйверів

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

АнтипатернЩо йде не такКраща альтернатива
Видалення PVC до прочитання PV та політики поверненняБазовий том може бути несподівано видалено чи звільненоПеревірте PVC, PV, політику повернення та снапшоти перед видаленням заявок
Гонитва за журналами CSI до прочитання подій пода й PVCВи витрачаєте час у зашумлених журналах контролера, поки помилка в YAML очевиднаПочніть з describe pod та describe pvc, ескалюйте лише коли події вказують туди
Ставлення до кожного PVC у стані Pending як до зламаногоВідкладена прив’язка може бути нормальною з топологічно-обізнаним сховищемПеревірте volumeBindingMode та чи існує под-споживач
Примусове видалення старих подів під час Multi-Attach без доказів про нодуЗаписувач, що все ще працює, може пошкодити дані застосункуПідтвердьте стан ноди, завершення пода та безпеку навантаження перед примусовим видаленням
Розв’язання permission denied запуском від rootЗастосунок стартує, але стан безпеки регресуєВикористовуйте fsGroup, runAsUser та перевірку власності
Масштабування Deployment, що ділить одну заявку RWOЗайві репліки зазнають невдачі чи борються за один том, приєднаний до нодиВикористайте одну репліку, окремі PVC через StatefulSet або сховище RWX

Структура ухвалення рішень

Розділ «Структура ухвалення рішень»

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

Storage symptom
|
+-- Pod says PVC not found?
| |
| +-- Verify namespace and claimName, then correct the pod spec or create the claim.
|
+-- PVC is Pending?
| |
| +-- Check StorageClass, binding mode, access modes, capacity, selectors, and quota.
|
+-- PVC is Bound but pod is ContainerCreating?
| |
| +-- Check FailedMount, FailedAttach, Multi-Attach, hostPath, node, and CSI events.
|
+-- Pod runs but app cannot write?
|
+-- Check df, ownership, runAsUser, fsGroup, and application retention policy.

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

ДоказОсновний рівеньПеревірки лише для читанняКандидат на виправлення
Подія PVC каже, що клас не знайденоВибір StorageClasskubectl get sc, kubectl describe pvcВидалити + перестворити непов’язаний PVC з наявним класом
Подія PVC каже про очікування на першого споживачаПланувальник і топологіяkubectl get sc -o yaml, перевірити под-споживачСтворити под або виправити обмеження планування
Наявний PV не прив’язуєтьсяКонтракт PV/PVCПорівняти місткість, режими доступу, клас, селектори та claimRefУзгодити заявку або створити сумісний PV
Подія пода каже, що заявку не знайденоПосилання тому подаПеревірити простір імен пода та claimNameВиправити специфікацію пода або створити названу заявку в просторі імен
Помилка Multi-AttachПриєднання до нодиПеревірити старий под, стан ноди та VolumeAttachmentЗачекати, перемістити навантаження чи примусово видалити лише після оцінки ризику
Permission denied після монтуванняВласність файлової системиkubectl exec з id, ls -ld та журнали застосункуВстановити fsGroup, runAsUser чи виправити власність через схвалену Job
Файлова система переповненаМісткість під час роботиdf -h, розмір PVC, розкладка даних застосункуРозширити заявку, якщо дозволено, або очистити безпечні одноразові дані

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

Розбір прикладу: читання доказів за порядком

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

Припустімо, вправа дає вам под з іменем api-0, який не запускається, PVC з іменем api-data та StorageClass з іменем fast-block. Спокусливий хід — одразу перевірити всі три об’єкти, але чистіший хід — запитати, що под уже знає. Якщо подія пода каже, що заявка відсутня, клас і драйвер ще не релевантні; якщо подія каже, що монтування перевищило тайм-аут, ім’я заявки вже розв’язано, і ви можете рухатися глибше.

Тепер уявіть, що подія пода каже persistentvolumeclaim "api-data" not found, але kubectl get pvc у вашій поточній оболонці показує справну заявку з цим іменем. Наступне запитання не в тому, чи Kubernetes неузгоджений; воно в тому, чи використала ваша команда простір імен пода. Заявка з простору імен default не задовольняє под у backend, тож докази штовхають вас до виправлення простору імен, а не до ремонту провізіонування.

Якщо подія пода називає заявку, а заявка у стані Pending, перейдіть до потоку подій PVC. Повідомлення про storageclass not found вказує на невідповідність конфігурації, яку можна виправити, обравши наявний клас чи створивши потрібний клас. Повідомлення про очікування на першого споживача вказує на контекст топології планувальника, тож створення чи виправлення под-споживача — правильний наступний хід. Те саме слово-статус, отже, веде до різних дій залежно від повідомлення події.

Якщо PVC у стані Bound, утримайтеся від спокуси редагувати його лише тому, що под усе ще нездоровий. Прив’язка означає, що площина управління вже асоціювала заявку з PV, а випадкові правки можуть ускладнити осмислення ситуації. На цьому етапі події пода про FailedAttachVolume, FailedMount, hostPath type check failed чи проблеми з правами корисніші за зміни заявки. Рівень-власник перемістився з прив’язки на приєднання до ноди, налаштування монтування чи доступ процесу.

Для Multi-Attach порядок доказів захищає дані. Спершу знайдіть старий под і ноду, потім вирішіть, чи старий записувач зник, чи лише недосяжний з боку API-сервера. Якщо стара нода все ще Ready, примусове видалення — погана звичка, бо вихідний процес може все ще тримати файлову систему відкритою. Якщо нода NotReady і потрібне відновлення, задокументуйте ризик, приберіть застарілий об’єкт API та сплануйте перевірку цілісності застосунку після того, як под-заміна стартує.

Для permission denied порядок доказів запобігає регресу безпеки. Под, що працює, із журналами застосунку, які скаржаться на /data, відрізняється від пода, який взагалі не може змонтувати том. Перевірте id, членство в групах та власність каталогу зсередини контейнера, потім полагодьте контекст безпеки пода чи власність даних. Повернення до root зазвичай є ознакою того, що діагностика зупинилася на симптомі замість пояснення, чому процесу бракувало прав на запис.

Для місткості відокремте запитувану місткість від використаної. Прив’язаний PVC на 20Gi усе одно може бути переповнений з точки зору застосунку, а PVC на 20Gi у стані Pending може зазнати невдачі до того, як будь-яка файлова система існуватиме, бо квота чи місткість бекенду блокують провізіонування. Виправленням для першого випадку може бути розширення чи очищення; для другого — коригування квоти, менші запити, зміни топології чи місткість з боку провайдера. Вивід команди має сказати вам, у якому світі ви перебуваєте, перш ніж ви оберете.

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


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

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

Після створення зміни полів PVC навмисно вузькі: запити на зміну розміру можна змінювати, коли дозволено розширення, але зміна класу сховища вимагає нової заявки.

Ваш PVC усе ще Pending, його подія каже storageclass.storage.k8s.io "fast-ssd" not found, а kubectl get sc показує лише standard. Яка дія безпечно змінює клас, не намагаючись пропатчити незмінне поле?


  • Kubernetes увів підтримку CSI як стабільну в циклі релізу 1.13, що допомогло винести інтеграції сховища з основного дерева коду до незалежно підтримуваних драйверів.
  • volumeBindingMode: WaitForFirstConsumer існує тому, що топологічно-обізнане сховище має знати обрану ноду чи зону, перш ніж безпечно провізіонувати том.
  • Розширення PVC контролюється полем allowVolumeExpansion у StorageClass, тож дві заявки в одному кластері можуть мати різну поведінку розширення.
  • ReadWriteOnce стосується семантики приєднання на рівні ноди для багатьох блокових томів; це не означає, що кожна репліка в Deployment автоматично отримує приватний диск.

ПомилкаЧому вона стаєтьсяЯк її виправити
Не перевіряти Events насампередКоротка таблиця get приховує фактичне повідомлення контролераЗапустіть kubectl describe pod чи kubectl describe pvc та прочитайте розділ Events
Ігнорувати простір іменІмена PVC локальні для простору імен, але PV та StorageClass мають область видимості кластераПеревірте простір імен пода й PVC, перш ніж налагоджувати бекенд
Забути про WaitForFirstConsumerPVC у стані Pending виглядає зламаним, коли він насправді чекає на под-споживачПеревірте режим прив’язки StorageClass та перевірте под, що використовує заявку
Видаляти PVC до перевірки політики поверненняВидалення може звільнити чи прибрати базове сховищеПеревірте PV, політику повернення, снапшоти та власність даних перед видаленням
Пропускати журнали CSI, коли події називають провізіонераЗагальні події PVC можуть приховувати деталі API бекендуПеревірте конкретний контейнер контролера чи плагіна ноди CSI, названий у збої
Виправляти права запуском від rootЦе маскує симптом, послаблюючи ізоляціюВикористовуйте fsGroup, runAsUser та явні перевірки власності
Масштабувати репліки, що ділять одну заявку RWOДругий под приземляється на іншу ноду й не може приєднати томВикористайте одну репліку, StatefulSet з окремими заявками чи сховище з підтримкою RWX

Питання 1: Розробник каже, що под застряг у стані `ContainerCreating` десять хвилин, і перестворення не допомогло. Яку послідовність усунення несправностей сховища ви запускаєте і чому?

Почніть з kubectl describe pod <name>, бо подія пода каже вам, чи збій є відсутньою заявкою, проблемою приєднання чи проблемою монтування. Якщо подія називає PVC, перевірте kubectl get pvc <name> та kubectl describe pvc <name>, щоб довести, чи заявку прив’язано, чи вона у стані Pending. Якщо заявка у стані Pending, перевірте StorageClass, сумісність PV, квоту та відкладену прив’язку; якщо заявку прив’язано, перевірте докази приєднання, ноди, CSI, hostPath та прав. Ця послідовність працює, бо вона слідує фактичному ланцюжку посилань, а не стрибає до сторонніх журналів драйвера.

Питання 2: PVC у стані Pending дві години, але `kubectl describe pvc` каже лише, що він чекає на першого споживача. Інший член команди хоче перевстановити драйвер CSI. Що ви робите?

Не перевстановлюйте драйвер на основі лише цього повідомлення. Перевірте StorageClass та підтвердьте, чи volumeBindingMode дорівнює WaitForFirstConsumer, бо заявка у стані Pending може бути очікуваною, поки под, що її використовує, не заплановано. Наступна корисна дія — створити чи перевірити под-споживач та перевірити, чи обмеження планування перешкоджають вибору ноди. Перевстановлення драйвера додало б ризику, ігноруючи докази того, що Kubernetes чекає на контекст топології.

Питання 3: Под StatefulSet на збійній ноді використовував том RWO, а под-заміна повідомляє про помилку Multi-Attach на іншій ноді. Який шлях відновлення врівноважує швидкість та безпеку даних?

Спершу підтвердьте стан старої ноди й старого пода за допомогою kubectl get pod -o wide, kubectl get node та умов ноди, бо записувач, що все ще працює, — це небезпечний випадок. Якщо нода справді недосяжна, а навантаження потребує відновлення, примусово видаліть старий под лише після прийняття ризику для застосунку, потім перевірте об’єкти VolumeAttachment, якщо приєднання залишається застарілим. Щойно новий под змонтує том, запустіть перевірки цілісності на рівні застосунку, бо успіх приєднання в Kubernetes не доводить, що попередній записувач завершився чисто. Безпечне міркування — довести володіння, перш ніж розривати старе приєднання.

Питання 4: Новий образ працює як UID 1000, PVC монтується успішно, але журнали застосунку кажуть, що він не може писати в `/data/app.log`. Яка першопричина та виправлення засобами Kubernetes?

Імовірна першопричина — власність файлової системи, створена старим контейнером, що працював від root, чи процесом відновлення з іншою числовою власністю. PVC та монтування справні, тож події пода можуть не показувати збій сховища. Додайте контекст безпеки пода з fsGroup: 1000 та контекст безпеки контейнера на кшталт runAsUser: 1000 та runAsNonRoot: true, потім перевірте за допомогою kubectl exec -- id та ls -ld /data. Запуск застосунку від root змусив би симптом зникнути, але послабив би модель безпеки.

Питання 5: PVC, що використовує `premium-ssd`, залишається у стані Pending, StorageClass існує, а подія каже, що зовнішній провізіонер не створив том. Куди ви дивитеся далі?

Подивіться на поди й журнали контролера CSI, бо заявка досягла рівня динамічного провізіонування. Використайте kubectl get pods -n kube-system | grep csi, потім отримайте журнали з контейнерів на кшталт csi-provisioner, csi-attacher чи контейнера драйвера. Імовірними причинами є контролер у стані crashloop, відсутні хмарні права, недійсні параметри StorageClass, квота бекенду чи місткість топології. Перевірка іншого StorageClass за замовчуванням також може сказати вам, чи збій специфічний для класу, чи поширений на весь кластер.

Питання 6: Deployment має дві репліки, які обидві монтують той самий прив'язаний PVC. Один под Running на node-a, інший застряг на node-b, а режим доступу PV — RWO. Яке виправлення на іспиті та яке на виробництві?

Безпосередня проблема в тому, що одну заявку на основі RWO використовують поди на різних нодах. На іспиті найшвидше безпечне виправлення зазвичай — масштабувати Deployment до однієї репліки чи обмежити планування так, щоб приєднання потребувала лише одна нода, залежно від формулювання завдання. Виробниче виправлення — переробити форму сховища: використати StatefulSet з volumeClaimTemplates, щоб кожна репліка отримала власну заявку, або перейти на сховище з підтримкою RWX, якщо застосунок справді потребує спільного запису. Відповідь має згадати режим доступу, бо зміна реплік без зміни семантики сховища лише приховує проблему дизайну.

Питання 7: Квота простору імен дозволяє 10Gi сховища, а учень створює PVC на 20Gi, який ніколи не прив'язується. StorageClass та драйвер CSI справні. Як ви довести та виправите проблему?

Перевірте kubectl describe pvc на події, пов’язані з квотою, потім запустіть kubectl get resourcequota -n <namespace> та kubectl describe resourcequota -n <namespace>, щоб порівняти запитуване сховище з політикою. Виправлення — зменшити запит, попросити зміну квоти чи використати простір імен, призначений для більших заявок. Перезапуски драйвера не релевантні, бо політика API відхиляє чи блокує запит ще до того, як постане питання місткості бекенду. Ця відповідь узгоджує докази з рівнем, що володіє відмовою.


Практична вправа: сценарії усунення несправностей зі сховищем

Розділ «Практична вправа: сценарії усунення несправностей зі сховищем»

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

Terminal window
kubectl create ns storage-debug

Сценарій 1: PVC не прив’язується, бо StorageClass неправильний

Розділ «Сценарій 1: PVC не прив’язується, бо StorageClass неправильний»

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

Terminal window
cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: broken-pvc-1
namespace: storage-debug
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: nonexistent-class
EOF
Terminal window
kubectl get pvc -n storage-debug broken-pvc-1
Terminal window
kubectl describe pvc -n storage-debug broken-pvc-1
Terminal window
kubectl get sc

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

Terminal window
kubectl delete pvc -n storage-debug broken-pvc-1
Terminal window
cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: broken-pvc-1
namespace: storage-debug
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: standard
EOF

Якщо клас використовує WaitForFirstConsumer, перебування PVC у стані Pending без подій помилок очікуване, поки под не посилається на заявку.

Нотатки до розв'язання сценарію 1

Очікуваним доказом є подія на кшталт storageclass.storage.k8s.io "nonexistent-class" not found. Правильне виправлення — не перезапускати поди й не перевіряти журнали CSI першими; це зробити так, щоб заявка просила клас, який існує, чи надати відповідний статичний PV. Якщо standard немає у вашому кластері, підставте фактичне ім’я класу, показане kubectl get sc.

Сценарій 2: Под не може змонтувати, бо ім’я заявки неправильне

Розділ «Сценарій 2: Под не може змонтувати, бо ім’я заявки неправильне»

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

Terminal window
cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: correct-pvc
namespace: storage-debug
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
EOF
Terminal window
cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: broken-pod-1
namespace: storage-debug
spec:
containers:
- name: app
image: busybox:1.36
command: ['sleep', '3600']
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
persistentVolumeClaim:
claimName: wrong-pvc-name
EOF
Terminal window
kubectl get pod -n storage-debug broken-pod-1
Terminal window
kubectl describe pod -n storage-debug broken-pod-1

Виправлення — перестворити под із правильним claimName. Для реального Deployment ви б пропатчили чи оновили шаблон контролера, а не редагували «голий» под, бо контролери відтворюють поди зі своїх шаблонів. У цій лабораторній роботі видалення й перестворення пода тримає фокус на посиланні сховища.

Terminal window
kubectl delete pod -n storage-debug broken-pod-1
Terminal window
cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: broken-pod-1
namespace: storage-debug
spec:
containers:
- name: app
image: busybox:1.36
command: ['sleep', '3600']
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
persistentVolumeClaim:
claimName: correct-pvc
EOF
Нотатки до розв'язання сценарію 2

Подія пода має згадувати, що persistentvolumeclaim "wrong-pvc-name" not found. Важлива деталь — локальне для простору імен іменування: Kubernetes не шукає в інших просторах імен заявку з цим іменем, а справна заявка з іншим іменем не задовольняє специфікацію пода. Найменше виправлення — зробити так, щоб под посилався на correct-pvc.

### Сценарій 3: Помилка типу hostPath

Третій сценарій використовує hostPath, бо він породжує чітку помилку локального монтування на ноді без потреби в хмарному провайдері. Шлях навмисно відсутній, а тип — Directory, що вимагає, щоб каталог існував до запуску пода. Це корисно для навчання, але пам’ятайте, що hostPath рідко є правильною абстракцією для даних застосунку на виробництві.

Terminal window
cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: broken-pod-2
namespace: storage-debug
spec:
containers:
- name: app
image: busybox:1.36
command: ['sleep', '3600']
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
hostPath:
path: /tmp/nonexistent-path-xyz
type: Directory
EOF
Terminal window
kubectl describe pod -n storage-debug broken-pod-2

Полагодьте под, використавши DirectoryOrCreate, який просить kubelet створити каталог на обраній ноді, якщо його не існує. Це доречно для лабораторної роботи, бо шлях одноразовий. У виробничому дизайні ви б зазвичай замінили hostPath на PV, том на основі CSI чи патерн, специфічний для агента ноди.

Terminal window
kubectl delete pod -n storage-debug broken-pod-2
Terminal window
cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: broken-pod-2
namespace: storage-debug
spec:
containers:
- name: app
image: busybox:1.36
command: ['sleep', '3600']
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
hostPath:
path: /tmp/nonexistent-path-xyz
type: DirectoryOrCreate
EOF
Нотатки до розв'язання сценарію 3

Очікувана подія — збій перевірки типу hostPath. Виправлення змінює тип hostPath, а не PVC, StorageClass чи драйвери CSI, бо цей том локальний для ноди й не використовує контролер персистентних томів. Це розрізнення — головний урок: правильне виправлення слідує типу тому, який фактично з’являється у специфікації пода.

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

Terminal window
kubectl get pvc -n <namespace>
Terminal window
kubectl describe pvc <pvc-name> | grep -A20 Events
Terminal window
kubectl exec <pod> -- df -h
Terminal window
kubectl exec <pod> -- ls -la /data
Terminal window
kubectl describe pod <pod-name>
Terminal window
kubectl get pods -n kube-system | grep csi
Terminal window
kubectl get csidrivers
Terminal window
kubectl get pvc <pvc-name> -o yaml | grep -E 'storage:|accessModes:|storageClassName:'
Terminal window
kubectl get pv <pv-name> -o yaml | grep -E 'storage:|accessModes:|storageClassName:'
Terminal window
kubectl get volumeattachment
Terminal window
kubectl get events --field-selector reason=FailedBinding
Terminal window
kubectl get events --field-selector reason=ProvisioningFailed
Terminal window
kubectl get events --sort-by='.lastTimestamp' | tail -20
Terminal window
kubectl get pod <pod-name> -o wide
Terminal window
kubectl get sc <storageclass> -o yaml
Terminal window
kubectl describe node <node-name> | grep -A8 Conditions
Terminal window
kubectl logs -n kube-system <csi-controller-pod> -c csi-provisioner
Terminal window
kubectl logs -n kube-system <csi-controller-pod> -c csi-attacher
Terminal window
kubectl get resourcequota -n <namespace>
Terminal window
kubectl describe resourcequota -n <namespace>

Контрольний список усунення несправностей зі сховищем

Розділ «Контрольний список усунення несправностей зі сховищем»

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

□ Pod stuck? → kubectl describe pod → check Events
□ PVC Pending? → kubectl describe pvc → check Events
□ StorageClass exists? → kubectl get sc
□ PV available? → kubectl get pv
□ Access modes match? → Compare PVC and PV
□ StorageClassName match? → Compare PVC and PV
□ CSI driver running? → kubectl get pods -n kube-system | grep csi
□ Permissions issue? → Check securityContext fsGroup
□ Capacity issue? → Check quotas and storage backend
  • Виявили помилку StorageClass з подій PVC та виправили заявку, щоб вона використовувала дійсний клас для вашого кластера.
  • Виявили неправильне ім’я PVC з подій пода та виправили посилання тому пода.
  • Виявили вимогу типу hostPath з подій пода та безпечно виправили тип для лабораторної роботи.
  • Пояснили, чи належав кожен збій до рівня посилання пода, прив’язки PVC, монтування на ноді чи драйвера сховища.
  • Написали короткий контрольний список усунення несправностей сховища, що починається з подій та уникає руйнівного видалення як першого ходу.
Terminal window
kubectl delete ns storage-debug


Перейдіть до Підсумкового тесту частини 4, щоб перевірити свої знання про сховище перед переходом до ширшого усунення несправностей Kubernetes.