Модуль 1.4: Томи для розробників
Складність:
[MEDIUM]— Необхідний для застосунків зі збереженням стануЧас на виконання: 40–50 хвилин
Передумови: Модуль 1.3 (Піди з кількома контейнерами)
Що ви зможете робити
Розділ «Що ви зможете робити»Після завершення цього модуля ви зможете:
- Створити Піди з томами emptyDir, hostPath та PersistentVolumeClaim
- Налаштувати монтування томів для обміну даними між контейнерами в одному Поді
- Діагностувати помилки монтування томів, включно з проблемами прав доступу та відсутніми PVC
- Пояснити різницю між ефемерними та постійними томами та коли використовувати кожен
Чому цей модуль важливий
Розділ «Чому цей модуль важливий»Контейнери ефемерні — при перезапуску всі дані втрачаються. Для реальних застосунків потрібне постійне зберігання: бази даних потребують надійних даних, застосунки потребують спільних файлів, а контейнерам потрібні способи обміну даними.
CKAD тестує практичне використання томів: монтування ConfigMaps, обмін даними між контейнерами та використання постійного зберігання. Ви не будете керувати StorageClasses (це CKA), але будете використовувати PersistentVolumeClaims.
Аналогія зі шухлядою стола
Файлова система контейнера — як дошка для записів — корисна, поки ви поруч, але стирається, коли ви йдете. Том
emptyDir— як спільний стіл у кімнаті для нарад — усі учасники наради можуть ним користуватися, але він очищується, коли нарада закінчується. PersistentVolume — як ваша шухляда стола — вона ваша, зберігається між робочими днями і містить ваші важливі файли.
Типи томів для розробників
Розділ «Типи томів для розробників»Короткий довідник
Розділ «Короткий довідник»| Тип тому | Збереження | Спільний доступ | Сценарій використання |
|---|---|---|---|
emptyDir | Час життя Підa | Між контейнерами | Тимчасовий простір, кеші |
hostPath | Час життя вузла | Ні | Доступ до вузла (лише для розробки) |
configMap | Час життя кластера | Тільки читання | Конфігураційні файли |
secret | Час життя кластера | Тільки читання | Чутливі дані |
persistentVolumeClaim | Поза Підом | Залежить | Бази даних, застосунки зі збереженням стану |
projected | Різне | Тільки читання | Об’єднання кількох джерел |
emptyDir: Тимчасове спільне сховище
Розділ «emptyDir: Тимчасове спільне сховище»emptyDir створюється при запуску Підa і видаляється при видаленні Підa. Ідеальний для:
- Обміну файлами між контейнерами
- Тимчасового простору для обчислень
- Кешів
Базовий emptyDir
Розділ «Базовий emptyDir»apiVersion: v1kind: Podmetadata: name: emptydir-demospec: containers: - name: writer image: busybox command: ["sh", "-c", "echo 'Hello' > /data/message && sleep 3600"] volumeMounts: - name: shared mountPath: /data - name: reader image: busybox command: ["sh", "-c", "cat /data/message && sleep 3600"] volumeMounts: - name: shared mountPath: /data volumes: - name: shared emptyDir: {}emptyDir в оперативній пам’яті
Розділ «emptyDir в оперативній пам’яті»Для швидкого тимчасового простору:
volumes:- name: cache emptyDir: medium: Memory # Використовує RAM замість диска sizeLimit: 100Mi # Обмеження використання пам'ятіТоми ConfigMap
Розділ «Томи ConfigMap»Монтуйте ConfigMaps як файли. Кожен ключ стає файлом.
Створення ConfigMap
Розділ «Створення ConfigMap»# З літералівk create configmap app-config \ --from-literal=log_level=debug \ --from-literal=api_url=http://api.example.com
# З файлуk create configmap nginx-config --from-file=nginx.confМонтування як том
Розділ «Монтування як том»apiVersion: v1kind: Podmetadata: name: config-demospec: containers: - name: app image: busybox command: ["sh", "-c", "cat /config/log_level && sleep 3600"] volumeMounts: - name: config mountPath: /config volumes: - name: config configMap: name: app-configРезультат:
/config/├── log_level # Містить "debug"└── api_url # Містить "http://api.example.com"Монтування конкретних ключів
Розділ «Монтування конкретних ключів»volumes:- name: config configMap: name: app-config items: - key: log_level path: logging/level.txt # Власний шляхSubPath: Монтування одного файлу без перезапису
Розділ «SubPath: Монтування одного файлу без перезапису»volumeMounts:- name: config mountPath: /etc/app/config.yaml # Конкретний файл subPath: config.yaml # Ключ з ConfigMapТоми Secret
Розділ «Томи Secret»Як ConfigMaps, але для чутливих даних. Змонтовані файли зберігаються в tmpfs (в оперативній пам’яті).
Створення Secret
Розділ «Створення Secret»k create secret generic db-creds \ --from-literal=username=admin \ --from-literal=password=secret123Монтування Secret
Розділ «Монтування Secret»apiVersion: v1kind: Podmetadata: name: secret-demospec: containers: - name: app image: busybox command: ["sh", "-c", "cat /secrets/password && sleep 3600"] volumeMounts: - name: db-secrets mountPath: /secrets readOnly: true volumes: - name: db-secrets secret: secretName: db-credsПрава доступу до файлів
Розділ «Права доступу до файлів»volumes:- name: db-secrets secret: secretName: db-creds defaultMode: 0400 # Тільки читання для власникаPersistentVolumeClaim (PVC)
Розділ «PersistentVolumeClaim (PVC)»Для даних, що переживають перезапуски Підів. Як розробник, ви запитуєте сховище через PVC; кластер його забезпечує.
Створення PVC
Розділ «Створення PVC»apiVersion: v1kind: PersistentVolumeClaimmetadata: name: data-pvcspec: accessModes: - ReadWriteOnce # RWO, ROX, RWX resources: requests: storage: 1Gi # storageClassName: fast # Необов'язково: конкретний класРежими доступу
Розділ «Режими доступу»| Режим | Скорочення | Опис |
|---|---|---|
ReadWriteOnce | RWO | Один вузол може монтувати для читання-запису |
ReadOnlyMany | ROX | Багато вузлів можуть монтувати тільки для читання |
ReadWriteMany | RWX | Багато вузлів можуть монтувати для читання-запису |
Використання PVC у Піді
Розділ «Використання PVC у Піді»apiVersion: v1kind: Podmetadata: name: pvc-demospec: containers: - name: app image: nginx volumeMounts: - name: data mountPath: /data volumes: - name: data persistentVolumeClaim: claimName: data-pvcІмперативне створення PVC
Розділ «Імперативне створення PVC»# Прямої імперативної команди немає, але YAML пишеться швидкоcat << 'EOF' | k apply -f -apiVersion: v1kind: PersistentVolumeClaimmetadata: name: my-pvcspec: accessModes: ["ReadWriteOnce"] resources: requests: storage: 1GiEOFProjected-томи
Розділ «Projected-томи»Об’єднують кілька джерел в одну точку монтування.
apiVersion: v1kind: Podmetadata: name: projected-demospec: containers: - name: app image: busybox command: ["sh", "-c", "ls -la /projected && sleep 3600"] volumeMounts: - name: all-config mountPath: /projected volumes: - name: all-config projected: sources: - configMap: name: app-config - secret: name: app-secrets - downwardAPI: items: - path: "labels" fieldRef: fieldPath: metadata.labelsТипові паттерни томів
Розділ «Типові паттерни томів»Паттерн 1: Спільний тимчасовий простір
Розділ «Паттерн 1: Спільний тимчасовий простір»spec: containers: - name: processor image: processor volumeMounts: - name: scratch mountPath: /tmp/work - name: uploader image: uploader volumeMounts: - name: scratch mountPath: /data volumes: - name: scratch emptyDir: {}Паттерн 2: Конфігурація + Секрети
Розділ «Паттерн 2: Конфігурація + Секрети»spec: containers: - name: app image: myapp volumeMounts: - name: config mountPath: /etc/app - name: secrets mountPath: /etc/secrets readOnly: true volumes: - name: config configMap: name: app-config - name: secrets secret: secretName: app-secretsПаттерн 3: Init-контейнер готує дані
Розділ «Паттерн 3: Init-контейнер готує дані»spec: initContainers: - name: download image: curlimages/curl command: ["curl", "-o", "/data/app.tar", "http://example.com/app.tar"] volumeMounts: - name: app-data mountPath: /data containers: - name: app image: myapp volumeMounts: - name: app-data mountPath: /app volumes: - name: app-data emptyDir: {}Усунення проблем з томами
Розділ «Усунення проблем з томами»Перевірка статусу тому
Розділ «Перевірка статусу тому»# Томи Підak describe pod myapp | grep -A10 Volumes
# Статус PVCk get pvc
# Деталі PVCk describe pvc data-pvcТипові проблеми
Розділ «Типові проблеми»| Симптом | Причина | Рішення |
|---|---|---|
| Під застряг у Pending | PVC не прив’язано | Перевірте наявність PV |
| Відмова у доступі | Неправильний режим/користувач | Встановіть securityContext.fsGroup |
| Файл не знайдено | Неправильний mountPath | Перевірте відповідність шляхів |
| ConfigMap не оновлюється | Змонтовані файли кешуються | Перезапустіть Під або обережно використовуйте subPath |
Виправлення проблем з правами доступу
Розділ «Виправлення проблем з правами доступу»spec: securityContext: fsGroup: 1000 # ID групи для файлів тому containers: - name: app image: myapp securityContext: runAsUser: 1000Чи знали ви?
Розділ «Чи знали ви?»-
ConfigMaps та Secrets є зрештою узгодженими. Коли ви їх оновлюєте, Піди бачать зміни протягом хвилини — але НЕ якщо ви використали монтування через
subPath. Монтування subPath — це знімки, що не оновлюються автоматично. -
emptyDir за замовчуванням використовує диск вузла, але може використовувати RAM (
medium: Memory). Томи в оперативній пам’яті швидші, але враховуються в лімітах пам’яті контейнера. -
Видалення PVC блокується, якщо Під його використовує. Спочатку видаліть Під, потім PVC. Встановіть
persistentVolumeReclaimPolicy: Deleteдля автоматичного видалення базового сховища при видаленні PVC.
Типові помилки
Розділ «Типові помилки»| Помилка | Чому це шкодить | Рішення |
|---|---|---|
Забули volumeMounts | Том визначено, але не змонтовано | Додайте mount до контейнера |
Неправильний mountPath | Файли з’являються у неочікуваному місці | Ретельно перевірте шляхи |
Використання subPath для оновлень у реальному часі | Оновлення не поширюються | Уникайте subPath або перезапустіть Під |
| PVC з неправильним режимом доступу | Багатовузлові застосунки не працюють | Використовуйте RWX для спільного доступу |
| Відсутнє визначення тому | Під не запускається | Визначте том у spec.volumes |
Тест
Розділ «Тест»-
Що відбувається з даними в emptyDir, коли Під видаляється?
Відповідь
Дані видаляються. Сховище emptyDir прив'язане до життєвого циклу Підa — воно створюється при запуску Підa і видаляється при його видаленні. -
Як змонтувати лише один ключ з ConfigMap як конкретний файл?
Відповідь
Використовуйте поле `items` з `path`: ```yaml volumes: - name: config configMap: name: my-config items: - key: app.conf path: application.conf ``` -
Який режим доступу дозволяє кільком вузлам монтувати том для читання-запису?
Відповідь
`ReadWriteMany` (RWX). Це необхідно для спільного сховища між Підами на різних вузлах, наприклад NFS або хмарні файлові сховища. -
Як контейнери в одному Піді обмінюються файлами?
Відповідь
Через спільний том. Визначте `emptyDir` (або інший тип тому) і змонтуйте його в обох контейнерах. Вони зможуть читати/писати ті самі файли.
Практична вправа
Розділ «Практична вправа»Завдання: Створити повний застосунок з кількома типами томів.
Сценарій: Побудуйте застосунок, що:
- Використовує ConfigMap для конфігурації
- Використовує Secret для облікових даних
- Використовує emptyDir для спільного кешу між контейнерами
- Використовує PVC для постійних даних
apiVersion: v1kind: ConfigMapmetadata: name: app-settingsdata: config.json: | {"logLevel": "info", "cacheEnabled": true}---apiVersion: v1kind: Secretmetadata: name: app-credstype: OpaquestringData: api-key: super-secret-key---apiVersion: v1kind: PersistentVolumeClaimmetadata: name: app-dataspec: accessModes: ["ReadWriteOnce"] resources: requests: storage: 100Mi---apiVersion: v1kind: Podmetadata: name: volumes-appspec: containers: - name: app image: nginx volumeMounts: - name: config mountPath: /etc/app - name: secrets mountPath: /etc/secrets readOnly: true - name: cache mountPath: /tmp/cache - name: data mountPath: /data - name: cache-warmer image: busybox command: ["sh", "-c", "while true; do echo 'Cache data' > /cache/warm; sleep 30; done"] volumeMounts: - name: cache mountPath: /cache volumes: - name: config configMap: name: app-settings - name: secrets secret: secretName: app-creds - name: cache emptyDir: {} - name: data persistentVolumeClaim: claimName: app-dataПеревірка:
# Застосувати всі ресурсиk apply -f volumes-app.yaml
# Перевірити, що Під працюєk get pod volumes-app
# Перевірити монтуванняk exec volumes-app -c app -- ls -la /etc/appk exec volumes-app -c app -- ls -la /etc/secretsk exec volumes-app -c app -- ls -la /tmp/cachek exec volumes-app -c app -- ls -la /data
# Перевірити, що PVC прив'язаноk get pvc app-data
# Очищенняk delete pod volumes-appk delete pvc app-datak delete configmap app-settingsk delete secret app-credsПрактичні вправи
Розділ «Практичні вправи»Вправа 1: Спільний emptyDir (Ціль: 3 хвилини)
Розділ «Вправа 1: Спільний emptyDir (Ціль: 3 хвилини)»# Створити Під зі спільним emptyDircat << 'EOF' | k apply -f -apiVersion: v1kind: Podmetadata: name: shared-podspec: containers: - name: writer image: busybox command: ["sh", "-c", "echo hello > /shared/msg && sleep 3600"] volumeMounts: - name: shared mountPath: /shared - name: reader image: busybox command: ["sh", "-c", "sleep 5 && cat /shared/msg && sleep 3600"] volumeMounts: - name: shared mountPath: /shared volumes: - name: shared emptyDir: {}EOF
# Перевірити, що спільний доступ працюєk logs shared-pod -c reader
# Очищенняk delete pod shared-podВправа 2: Том ConfigMap (Ціль: 3 хвилини)
Розділ «Вправа 2: Том ConfigMap (Ціль: 3 хвилини)»# Створити ConfigMapk create configmap web-config --from-literal=index.html="Welcome to CKAD!"
# Створити Під з ConfigMapcat << 'EOF' | k apply -f -apiVersion: v1kind: Podmetadata: name: webspec: containers: - name: nginx image: nginx volumeMounts: - name: html mountPath: /usr/share/nginx/html volumes: - name: html configMap: name: web-configEOF
# Перевірити вмістk exec web -- cat /usr/share/nginx/html/index.html
# Очищенняk delete pod webk delete cm web-configВправа 3: Том Secret (Ціль: 3 хвилини)
Розділ «Вправа 3: Том Secret (Ціль: 3 хвилини)»# Створити Secretk create secret generic db-pass --from-literal=password=mysecret
# Змонтувати у Підcat << 'EOF' | k apply -f -apiVersion: v1kind: Podmetadata: name: secret-podspec: containers: - name: app image: busybox command: ["sh", "-c", "cat /secrets/password && sleep 3600"] volumeMounts: - name: creds mountPath: /secrets readOnly: true volumes: - name: creds secret: secretName: db-passEOF
# Перевірити, що secret змонтованоk logs secret-pod
# Очищенняk delete pod secret-podk delete secret db-passВправа 4: Використання PVC (Ціль: 4 хвилини)
Розділ «Вправа 4: Використання PVC (Ціль: 4 хвилини)»# Створити PVCcat << 'EOF' | k apply -f -apiVersion: v1kind: PersistentVolumeClaimmetadata: name: test-pvcspec: accessModes: ["ReadWriteOnce"] resources: requests: storage: 50MiEOF
# Використати у Підіcat << 'EOF' | k apply -f -apiVersion: v1kind: Podmetadata: name: pvc-podspec: containers: - name: app image: nginx volumeMounts: - name: storage mountPath: /data volumes: - name: storage persistentVolumeClaim: claimName: test-pvcEOF
# Перевірити, що PVC прив'язаноk get pvc test-pvc
# Записати даніk exec pvc-pod -- sh -c "echo 'Persistent!' > /data/test.txt"k exec pvc-pod -- cat /data/test.txt
# Очищенняk delete pod pvc-podk delete pvc test-pvcВправа 5: Projected-том (Ціль: 4 хвилини)
Розділ «Вправа 5: Projected-том (Ціль: 4 хвилини)»# Створити джерелаk create cm proj-config --from-literal=config=valuek create secret generic proj-secret --from-literal=secret=hidden
# Створити Під з projected-томомcat << 'EOF' | k apply -f -apiVersion: v1kind: Podmetadata: name: proj-pod labels: app: projectedspec: containers: - name: app image: busybox command: ["sh", "-c", "ls -la /projected && sleep 3600"] volumeMounts: - name: combined mountPath: /projected volumes: - name: combined projected: sources: - configMap: name: proj-config - secret: name: proj-secretEOF
# Перевірити об'єднані файлиk exec proj-pod -- ls /projected
# Очищенняk delete pod proj-podk delete cm proj-configk delete secret proj-secretВправа 6: Повне завдання з томами (Ціль: 6 хвилин)
Розділ «Вправа 6: Повне завдання з томами (Ціль: 6 хвилин)»Створіть з пам’яті — без підказок:
Створіть Під data-processor, що:
- Init-контейнер завантажує “дані” (симуляція через echo)
- Основний контейнер обробляє дані (nginx)
- Sidecar логує статус обробки
- Використовує emptyDir для спільних даних
- Монтує ConfigMap з налаштуваннями обробки
Відповідь
# Створити ConfigMapk create cm processing-config --from-literal=mode=fast
# Створити Підcat << 'EOF' | k apply -f -apiVersion: v1kind: Podmetadata: name: data-processorspec: initContainers: - name: downloader image: busybox command: ["sh", "-c", "echo 'Downloaded data' > /data/input.txt"] volumeMounts: - name: data mountPath: /data containers: - name: processor image: nginx volumeMounts: - name: data mountPath: /data - name: config mountPath: /etc/config - name: logger image: busybox command: ["sh", "-c", "while true; do echo Processing $(cat /data/input.txt); sleep 5; done"] volumeMounts: - name: data mountPath: /data volumes: - name: data emptyDir: {} - name: config configMap: name: processing-configEOF
# Перевіркаk get pod data-processork logs data-processor -c loggerk exec data-processor -c processor -- cat /etc/config/mode
# Очищенняk delete pod data-processork delete cm processing-configНаступний модуль
Розділ «Наступний модуль»Підсумковий тест Частини 1 — Перевірте свої знання з проєктування та збірки застосунків.