Модуль 2.7: ConfigMaps та Secrets
Складність:
[СЕРЕДНЯ]Час на проходження: 55 хвилин
Передумови: Перш ніж починати, завершіть Модуль 2.1: Поглиблене вивчення Pod’ів та Модуль 2.2: Деплойменти, оскільки цей модуль припускає, що ви вмієте читати специфікації Pod’ів і розумієте, чому перезапуск Pod’а змінює стан під час виконання. Вам також знадобиться запущений кластер Kubernetes 1.35+, наприклад kind або minikube, та робоча оболонка, де доступна команда
kubectl.Вага в CKA: Workloads & Scheduling
Результати навчання
Розділ «Результати навчання»Після цього модуля ви зможете:
- Спроєктувати стратегію впровадження конфігурації, яка відокремлює образи контейнерів від налаштувань, специфічних для середовища, правильно обираючи між ConfigMaps та Secrets.
- Впровадити ConfigMaps та Secrets з літералів, файлів, env-файлів і маніфестів, а потім монтувати вибрані ключі як змінні середовища або файли.
- Порівняти впровадження через змінні середовища, повне монтування томів, проєктовані томи та монтування
subPathза поведінкою під час оновлення, ризиком розкриття та очікуваннями застосунку. - Діагностувати Pod’и, які не запускаються або поводяться неправильно через відсутні ключі, хибні шляхи монтування, застарілі значення, некоректне кодування Secret чи обмежувальні права доступу до файлів.
- Оцінити, коли у виробничих системах доречні незмінні об’єкти конфігурації, імена з номером версії, обмеження RBAC та зовнішні сховища секретів.
Чому цей модуль важливий
Розділ «Чому цей модуль важливий»Гіпотетичний сценарій: інженер релізів випускає новий вебсервіс у п’ятницю по обіді. Образ працює в staging-середовищі, проба готовності (readiness probe) проходить, а Деплоймент розгортається без жодних помилок. Та вже за десять хвилин виробничий трафік починає падати, бо образ контейнера досі вказує на staging-хост бази даних. Образ було перезібрано правильно, але всередину запекли хибне налаштування, тому команді доводиться перезібрати образ, призначити йому новий тег, повторно його просканувати та ще раз розгорнути — і все це лише заради зміни одного-єдиного рядка.
Інша команда уникає цієї помилки, перенісши хост бази даних до ConfigMap, а пароль — до Secret. Їхнє розгортання швидше, але пізніший інцидент виявляє інший режим відмови: пароль було впроваджено як змінну середовища, діагностичний endpoint вивів усе оточення процесу, і обліковий запис, який мав лишитися приватним, з’явився в логах. Примітив був обраний правильно, але метод впровадження не відповідав ризику.
ConfigMaps та Secrets — це прості об’єкти API, але вони лежать на критичній межі між дизайном застосунку, адмініструванням кластера та практиками безпеки. На іспиті CKA вам потрібно швидко їх створювати та під’єднувати до Pod’ів, не ламаючи при цьому робочого навантаження, яке вже працює. У виробництві ж ви також маєте розуміти механіку оновлення, шляхи до файлів, правила кодування, розкриття даних через RBAC та поведінку при перезапуску достатньо добре, щоб обрати такий дизайн, який лишається безпечним навіть після того, як перший kubectl apply уже відпрацював успішно.
Глибший урок полягає в тому, що конфігурація має власний життєвий цикл. Значення створює людина або автоматизація, воно зберігається в API Kubernetes, доставляється kubelet’ом до конкретного Pod’а, читається процесом і зрештою ротується чи видаляється. Кожен крок може зламатися по-своєму. Друкарська помилка в імені об’єкта спричиняє відмову ще до запуску контейнера, хибний ключ може проявитися як CreateContainerConfigError, застаріла змінна середовища здатна пережити коректний патч ConfigMap, а зайвий символ нового рядка в Secret може лишитися непомітним, доки застосунок не спробує автентифікуватися.
Тому цей модуль розглядає ConfigMaps та Secrets як контракти часу виконання, а не просто як фрагменти YAML. Ви створите об’єкти, дослідите їхнє збережене представлення, під’єднаєте їх до контейнерів кількома різними методами впровадження та поміркуєте над тим, що саме відбувається після того, як об’єкт змінено. Це міркування важливе, бо той самий маніфест може виглядати цілком правильним під час код-рев’ю і все одно бути хибним для конкретного застосунку. Досвідчений оператор простежує весь шлях від ключа до представлення під час виконання й щоразу запитує, чи може процес насправді побачити це значення саме в той момент, коли воно йому потрібне.
Тримайте в голові одну ментальну модель упродовж усього модуля: Kubernetes може доставити конфігурацію, але не може змусити застосунок перечитати ту конфігурацію, яку той уже встиг закешувати. Змінні середовища копіюються в процес лише під час запуску, змонтовані файли можуть згодом змінюватися на диску, а монтування subPath навмисно поводяться як фіксовані, разові заміни файлів. Саме ця механіка перетворює прості на вигляд рішення на справжні операційні компроміси. Найшвидша відповідь на іспиті — це часто найкоротша команда, але найнадійніша виробнича відповідь — це та, що має чітку й заздалегідь продуману історію перезавантаження, перезапуску, відкату та перевірки, за якою будь-який інший інженер зможе піти під час інциденту, не вгадуючи при цьому прихований стан системи.
Основний матеріал
Розділ «Основний матеріал»1. Конфігурація — це вхідні дані часу виконання, а не вміст образу
Розділ «1. Конфігурація — це вхідні дані часу виконання, а не вміст образу»Образ контейнера має описувати, чим є застосунок, тоді як конфігурація має описувати, як цей застосунок поводиться в конкретному середовищі. Якщо той самий образ може працювати в розробці, staging та виробництві лише за рахунок зміни об’єктів Kubernetes, розгортання стають швидшими та менш ризикованими. Коли образ містить хости баз даних, прапорці функціональності або сертифікати, кожна зміна конфігурації перетворюється на зміну ланцюга постачання, що збільшує операційні витрати й ускладнює відкат більше, ніж потрібно.
Kubernetes дає вам два першокласні об’єкти для цього розділення. ConfigMap зберігає нечутливу конфігурацію, як-от рівні логування, імена endpoint’ів, прапорці функціональності та конфігураційні файли застосунку. Secret зберігає чутливу конфігурацію, як-от паролі, токени-носії (bearer tokens), SSH-ключі, приватні TLS-ключі та облікові дані реєстру. Об’єкти схожі, бо обидва є відображеннями «ключ-значення», але вони несуть різні очікування щодо безпеки, і люди, автоматизація та застосунки мають поводитися з ними по-різному.
Перше питання дизайну — не «яка команда створює цей об’єкт?». Перше питання — «як застосунок має споживати ці дані?». Деякі застосунки читають змінні середовища під час запуску процесу й більше ніколи до них не повертаються. Інші стежать за змінами файлів або перезавантажують конфігурацію, коли файл змінюється. Одні очікують цілий каталог файлів, тоді як інші очікують один точний шлях до файлу. Ваш дизайн Kubernetes має відповідати такій поведінці застосунку, а не втискати застосунок у зручну форму маніфесту.
+----------------------+ +----------------------+ +----------------------+| Container Image | | Kubernetes Object | | Runtime View in Pod ||----------------------| |----------------------| |----------------------|| app binary | | ConfigMap | | env vars or files || libraries | | Secret | | env vars or files || default config | | projected volume | | merged file tree |+----------------------+ +----------------------+ +----------------------+ | | | | same image across envs | environment-specific data | values injected at start +------------------------------+------------------------------+Корисне правило — класифікувати кожне значення за двома ознаками: чутливістю та поведінкою при перезавантаженні. Рівень логування може бути нечутливим і безпечним як змінна середовища, якщо застосунок читає його лише під час запуску. TLS-ключ є чутливим і зазвичай безпечніший як файл, змонтований лише для читання з обмежувальними правами доступу. Таблиця маршрутизації, яка змінюється під час інциденту, може потребувати повного монтування тому, бо змінні середовища не оновляться всередині процесу, що вже працює.
Запит для активного навчання: Ваша команда хоче зберегти
PAYMENTS_API_URL,FEATURE_CHECKOUT_V2таPAYMENTS_API_TOKEN. Які з них належать до ConfigMap, які — до Secret, і який метод впровадження ви б обрали, якщо застосунок читає лише змінні середовища під час запуску?
Іспит CKA винагороджує швидкість, тож ви часто створюватимете об’єкти імперативно й вноситимете правки до YAML, згенерованого з --dry-run=client -o yaml. Реальні кластери винагороджують чіткість, тож виробничі команди зазвичай керують цими об’єктами через GitOps, Helm, Kustomize, External Secrets або інший контрольований процес. Базова механіка Kubernetes однакова в обох контекстах, і саме тому глибоке вивчення примітива окупається поза межами іспитової м’язової пам’яті.
2. Створення ConfigMaps з літералів, файлів, каталогів та env-файлів
Розділ «2. Створення ConfigMaps з літералів, файлів, каталогів та env-файлів»ConfigMap зберігає рядкові дані під ключами. Ключ може представляти просте значення на кшталт LOG_LEVEL або цілий файл на кшталт nginx.conf. Ця відмінність важлива, бо Kubernetes не досліджує вміст файлів і не розбиває їх автоматично на налаштування застосунку, доки ви не попросите про це правильним режимом створення.
Найпростіший зручний для іспиту метод створення — --from-literal. Використовуйте його, коли кожне значення вже відоме й достатньо коротке, щоб безпечно його надрукувати. Оскільки кожен прапорець --from-literal стає одним ключем, цей метод природно відображається на змінні середовища та невеликі мапи конфігурації.
kubectl create configmap app-config \ --from-literal=LOG_LEVEL=info \ --from-literal=CACHE_TTL_SECONDS=300 \ --from-literal=FEATURE_CHECKOUT_V2=trueОтриманий об’єкт можна дослідити за допомогою kubectl get або kubectl describe. Представлення у вигляді YAML варто прочитати, бо воно показує саме те, на що Pod зможе послатися згодом. Pod не може послатися на «третій літерал» чи «налаштування кешу» як на ідею; він посилається на конкретне ім’я об’єкта та конкретний ключ.
kubectl get configmap app-config -o yamlapiVersion: v1kind: ConfigMapmetadata: name: app-configdata: CACHE_TTL_SECONDS: "300" FEATURE_CHECKOUT_V2: "true" LOG_LEVEL: infoВикористовуйте --from-file, коли застосунок очікує файл, як-от серверний блок NGINX, файл властивостей Java чи YAML-файл застосунку. За простого --from-file=config.properties ключем стає ім’я файлу, а значенням — повний вміст файлу. Kubernetes не розбиває файл на кілька ключів лише тому, що файл випадково містить рядки ключ=значення.
cat > config.properties <<'EOF'database.host=orders-db.default.svc.cluster.localdatabase.port=5432cache.enabled=trueEOF
kubectl create configmap app-file-config --from-file=config.propertiesapiVersion: v1kind: ConfigMapmetadata: name: app-file-configdata: config.properties: | database.host=orders-db.default.svc.cluster.local database.port=5432 cache.enabled=trueЯкщо ім’я файлу в контейнері має відрізнятися від локального імені файлу, задайте власний ключ. Це поширене, коли згенерований файл має тимчасове ім’я на вашій робочій станції, але застосунок очікує стабільний шлях усередині контейнера. Обраний вами ключ стає іменем файлу, коли ConfigMap монтується як том, доки ви знову не перевизначите його шлях за допомогою items.
kubectl create configmap app-file-config-v2 \ --from-file=application.properties=config.propertiesВикористовуйте --from-env-file, коли кожен рядок має стати окремою парою «ключ-значення». Це часта пастка на іспиті, бо env-файли та конфігураційні файли можуть виглядати для людини схожими. Для Kubernetes --from-file означає «збережи весь цей файл під одним ключем», тоді як --from-env-file означає «розбери кожен валідний рядок на власний ключ».
cat > app.env <<'EOF'LOG_LEVEL=debugCACHE_TTL_SECONDS=120FEATURE_CHECKOUT_V2=falseEOF
kubectl create configmap app-env-config --from-env-file=app.envapiVersion: v1kind: ConfigMapmetadata: name: app-env-configdata: CACHE_TTL_SECONDS: "120" FEATURE_CHECKOUT_V2: "false" LOG_LEVEL: debug| Метод створення | Найкраще застосування | Отримані ключі | Поширений ризик на іспиті |
|---|---|---|---|
--from-literal | Кілька відомих значень | Один ключ на прапорець | Друкарська помилка в імені ключа |
--from-file=file | Застосунку потрібен весь файл | Ім’я файлу стає одним ключем | Очікування, що рядки розіб’ються автоматично |
--from-file=key=file | Застосунку потрібне конкретне ім’я файлу | Власний ключ стає іменем файлу | Забути про власний ключ згодом |
--from-file=directory/ | Кілька файлів стають одним ConfigMap | Один ключ на файл | Приховані файли та некоректні імена пропускаються |
--from-env-file=file | Кожен рядок має стати env-ключем | Один ключ на розібраний рядок | Використання для багаторядкових конфігураційних файлів |
Імпорт каталогу корисний, коли застосунок очікує кілька конфігураційних файлів в одному змонтованому каталозі. Kubernetes створює по одному ключу для кожного звичайного файлу в каталозі. Це зручно, але також означає, що вміст каталогу стає частиною об’єкта API, тому уникайте необачного використання цього методу з каталогу, що містить локальні файли редактора, резервні копії чи секрети, яким не місце в ConfigMap.
mkdir -p config-dir
cat > config-dir/app.yaml <<'EOF'server: port: 8080logging: level: infoEOF
cat > config-dir/routes.yaml <<'EOF'routes: - path: /health upstream: localEOF
kubectl create configmap app-directory-config --from-file=config-dir/ConfigMap також можна записати як маніфест, що часто зрозуміліше для змін, які проходять рев’ю. У маніфесті поле data містить текстові значення, а необов’язкове поле binaryData містить двійкові значення, закодовані в base64. Для завдань CKA імперативне створення зазвичай швидше, але знання форми маніфесту допомагає діагностувати згенерований YAML і працювати з реальними репозиторіями.
apiVersion: v1kind: ConfigMapmetadata: name: orders-configdata: LOG_LEVEL: "info" application.yaml: | database: host: orders-db.default.svc.cluster.local port: 5432 features: checkoutV2: trueЗапит для активного навчання: Ви створили ConfigMap з
app.propertiesза допомогою--from-file, потім використалиenvFromу Pod’і й очікували, щоdatabase.hostз’явиться як змінна середовища. Передбачте, яка змінна (якщо взагалі) з’явиться в контейнері, а потім вирішіть, який метод створення вам слід було використати.
3. Впровадження ConfigMaps: змінні середовища, файли та зіставлення шляхів ключів
Розділ «3. Впровадження ConfigMaps: змінні середовища, файли та зіставлення шляхів ключів»Щойно ConfigMap існує, специфікація Pod’а вирішує, як контейнер його бачить. Два найпоширеніші варіанти — змінні середовища та файли, змонтовані з тому. Змінні середовища прості й звичні, але вони фіксуються в момент запуску процесу контейнера. Монтування томів краще підходить для застосунків, орієнтованих на файли, і може отримувати оновлення автоматично, якщо ви уникаєте subPath.
Використовуйте env.valueFrom.configMapKeyRef, коли хочете зіставити один ключ з однією змінною середовища з іменем, специфічним для контейнера. Цей патерн точний і читабельний. Він також дає змогу позначити окремий ключ необов’язковим, що може бути корисним під час поетапних розгортань, але потребує обережності, бо необов’язкова відсутня конфігурація може приховати помилку розгортання.
apiVersion: v1kind: Podmetadata: name: app-env-singlespec: containers: - name: app image: nginx:1.27 env: - name: APP_LOG_LEVEL valueFrom: configMapKeyRef: name: app-config key: LOG_LEVEL - name: APP_CACHE_TTL_SECONDS valueFrom: configMapKeyRef: name: app-config key: CACHE_TTL_SECONDSВикористовуйте envFrom, коли кожен валідний ключ у ConfigMap має стати змінною середовища. Це швидко для іспитових завдань і чисто для простих застосунків, але в продакшені може бути занадто широким, бо кожен ключ стає частиною оточення процесу. Префікс зменшує конфлікти імен і робить зрозумілішим, що значення прийшло з конфігурації Kubernetes.
apiVersion: v1kind: Podmetadata: name: app-env-allspec: containers: - name: app image: nginx:1.27 envFrom: - configMapRef: name: app-config prefix: APP_Коли ConfigMap монтується як том, кожен ключ стає файлом. Це ключова ментальна модель, яка запобігає більшості помилок зі шляхами монтування. Якщо ConfigMap має ключі application.yaml і routes.yaml, а том змонтовано в /etc/app, контейнер бачить /etc/app/application.yaml та /etc/app/routes.yaml.
+-----------------------------+ +--------------------------------+| ConfigMap: orders-config | | Container filesystem ||-----------------------------| |--------------------------------|| data.LOG_LEVEL | env | APP_LOG_LEVEL=info || data.application.yaml | file | /etc/app/application.yaml || data.routes.yaml | file | /etc/app/routes.yaml |+-----------------------------+ +--------------------------------+apiVersion: v1kind: Podmetadata: name: app-config-volumespec: containers: - name: app image: nginx:1.27 volumeMounts: - name: app-config-volume mountPath: /etc/app volumes: - name: app-config-volume configMap: name: orders-configПодана нижче діаграма — найважливіша модель зіставлення шляхів у цьому модулі. Ім’я ключа — не просто метадані; для монтувань томів воно стає іменем файлу, доки Pod не перевизначить його шлях. mountPath — це каталог, де з’являється том, а шлях до файлу всередині контейнера — це каталог плюс зіставлений шлях ключа.
+-----------------------------------+ +--------------------------------------+| ConfigMap key map | | Mounted volume at /etc/app ||-----------------------------------| |--------------------------------------|| application.yaml | ---> | /etc/app/application.yaml || routes.yaml | ---> | /etc/app/routes.yaml || feature-flags.json | ---> | /etc/app/feature-flags.json |+-----------------------------------+ +--------------------------------------+Іноді вам потрібні лише окремі ключі або ви хочете, щоб шлях до файлу всередині змонтованого каталогу відрізнявся від імені ключа. Для такого зіставлення використовуйте items. Це безпечніше, ніж змінювати ключ ConfigMap лише заради відповідності бажаному імені файлу одного застосунку, бо кілька Pod’ів можуть повторно використовувати той самий ConfigMap з різними зіставленнями шляхів.
apiVersion: v1kind: Podmetadata: name: app-config-itemsspec: containers: - name: app image: nginx:1.27 volumeMounts: - name: app-config-volume mountPath: /etc/app volumes: - name: app-config-volume configMap: name: orders-config items: - key: application.yaml path: config/application.yaml - key: routes.yaml path: routes.yaml+-----------------------------+ +--------------------------------+| ConfigMap: orders-config | | mountPath: /etc/app ||-----------------------------| |--------------------------------|| application.yaml | items | /etc/app/config/application.yaml|| routes.yaml | items | /etc/app/routes.yaml || LOG_LEVEL | skipped | no file created |+-----------------------------+ +--------------------------------+Монтування subPath влаштоване інакше. Воно монтує один файл з тому на один точний шлях у контейнері. Це корисно, коли образ уже містить каталог на кшталт /etc/nginx/conf.d, і ви хочете замінити лише /etc/nginx/conf.d/default.conf, не приховуючи решту каталогу. Компроміс суттєвий: оновлення ConfigMap і Secret не поширюються через монтування subPath.
apiVersion: v1kind: Podmetadata: name: nginx-subpath-configspec: containers: - name: nginx image: nginx:1.27 volumeMounts: - name: nginx-config mountPath: /etc/nginx/conf.d/default.conf subPath: nginx.conf volumes: - name: nginx-config configMap: name: nginx-config items: - key: nginx.conf path: nginx.conf+---------------------------+ +-----------------------------------------+| ConfigMap key | | subPath mount result ||---------------------------| |-----------------------------------------|| nginx.conf | -------> | /etc/nginx/conf.d/default.conf || | | single file mount, not auto-refreshed |+---------------------------+ +-----------------------------------------+| Патерн впровадження | Представлення в контейнері | Оновлення в запущеному Pod’і | Найкраще підходить | Головний ризик |
|---|---|---|---|---|
env з одним ключем | Одна іменована змінна середовища | Ні | Точні налаштування запуску | Відсутній ключ блокує контейнер, якщо не необов’язковий |
envFrom | Багато змінних середовища | Ні | Невеликі застосунки з env-конфігурацією | Занадто широке й схильне до конфліктів |
| Повне монтування тому | Каталог файлів | Так, після затримки синхронізації kubelet | Файлова конфігурація та застосунки з перезавантаженням | Монтування приховує наявний вміст каталогу |
Том з items | Вибрані файли та шляхи | Так, якщо не змонтовано через subPath | Кураторське дерево файлів | Хибний ключ або шлях спричиняє відсутній файл |
Монтування файлу subPath | Один точний шлях до файлу | Ні | Заміна одного файлу в наявному каталозі | Застаріла конфігурація після оновлення об’єкта |
Запит для активного навчання: Образ NGINX уже містить кілька файлів у
/etc/nginx/conf.d/, і ви хочете замінити лишеdefault.conf. Який стиль монтування уникає приховування наявного каталогу, і яку операційну ціну ви приймаєте, обираючи його?
Поведінка ConfigMap при оновленні заслуговує на особливу увагу, бо вона дивує і початківців, і досвідчених інженерів, що поспішають. Запущений процес отримує змінні середовища лише при старті процесу, тож зміна ConfigMap не перепише оточення процесу. Повне монтування тому ConfigMap може оновити файли всередині контейнера після того, як kubelet синхронізує новий об’єкт, але застосунок має або перечитати файл, або бути перезавантаженим. Монтування файлу через subPath лишається застарілим, доки Pod не буде перезапущено.
4. Створення та використання Secrets без плутанини між кодуванням і безпекою
Розділ «4. Створення та використання Secrets без плутанини між кодуванням і безпекою»Secret — це об’єкт Kubernetes для чутливих даних, але типове представлення — це не магічне шифрування. Значення в полі data закодовані в base64, бо об’єкти API Kubernetes сумісні з JSON і потребують безпечного текстового представлення для довільних байтів. Base64 захищає формат, а не конфіденційність. Будь-хто, хто може прочитати Secret через API, може його декодувати.
Заради швидкості на іспиті kubectl create secret generic зазвичай найбезпечніший спосіб уникнути ручних помилок кодування. Команда приймає звичайні текстові літерали або файли й зберігає закодовану форму в об’єкті API. Беріть у лапки чутливі для оболонки значення, особливо паролі, що містять !, $, \, пробіли чи інші символи, які оболонка може інтерпретувати.
kubectl create secret generic db-creds \ --from-literal=username=orders_user \ --from-literal=password='example-db-password'Перегляд Secret показує закодовані значення. Це очікувано й не доводить, що значення зашифровано. Це лише доводить, що об’єкт API зберігає значення в мапі data. Використовуйте JSONPath та base64 -d під час діагностики лабораторного значення, але уникайте виведення реальних виробничих секретів у прокручування терміналу, історію оболонки, логи чи спільні екрани.
kubectl get secret db-creds -o jsonpath='{.data.password}' | base64 -dЗаписуючи маніфест Secret вручну, використовуйте stringData, якщо у вас немає конкретної причини надавати вже закодовані дані. Поле stringData приймає звичайний текст, і Kubernetes перетворює його на data, коли об’єкт зберігається. Це зменшує ймовірність випадкового кодування кінцевого символу нового рядка або подвійного кодування значення.
apiVersion: v1kind: Secretmetadata: name: db-credstype: OpaquestringData: username: orders_user password: example-db-passwordЯкщо ви використовуєте поле data, значення мають бути вже закодовані в base64. Використовуйте echo -n, а не echo, бо кінцевий символ нового рядка стане частиною значення Secret. Цей невидимий символ — класична причина збоїв автентифікації: люди бачать той самий пароль, але база даних отримує зайвий байт нового рядка.
echo -n 'example-db-password' | base64apiVersion: v1kind: Secretmetadata: name: db-creds-encodedtype: Opaquedata: username: b3JkZXJzX3VzZXI= password: ZXhhbXBsZS1kYi1wYXNzd29yZA==| Тип Secret | Типові ключі | Основне застосування | Перевага валідації |
|---|---|---|---|
Opaque | Будь-які ключі | Загальні облікові дані застосунку | Мінімальна валідація |
kubernetes.io/tls | tls.crt, tls.key | TLS-сертифікат і приватний ключ | Перевіряє наявність обов’язкових ключів |
kubernetes.io/dockerconfigjson | .dockerconfigjson | Автентифікація в приватному реєстрі образів | Перевіряє очікувану форму ключа |
kubernetes.io/basic-auth | username, password | Базова автентифікація | Чітко документує намір |
kubernetes.io/ssh-auth | ssh-privatekey | Матеріал приватного SSH-ключа | Чітко документує намір |
bootstrap.kubernetes.io/token | Поля bootstrap-токена | Процеси завантаження вузлів | Спеціалізоване використання в кластері |
Монтування Secrets дотримується тих самих патернів зі змінними середовища та томами, що й ConfigMaps, але компроміси щодо безпеки гостріші. Secret, впроваджений як змінна середовища, стає частиною оточення процесу контейнера; якщо застосунок може читати облікові дані з файлів, том Secret лише для читання зазвичай безпечніший за замовчуванням. Secret, змонтований як файл, усе одно потребує доступу до API для створення Pod’а, але всередині контейнера застосунок має навмисно прочитати шлях до файлу.
apiVersion: v1kind: Podmetadata: name: app-secret-envspec: containers: - name: app image: nginx:1.27 env: - name: DATABASE_USERNAME valueFrom: secretKeyRef: name: db-creds key: username - name: DATABASE_PASSWORD valueFrom: secretKeyRef: name: db-creds key: passwordapiVersion: v1kind: Podmetadata: name: app-secret-volumespec: containers: - name: app image: nginx:1.27 volumeMounts: - name: db-creds-volume mountPath: /etc/db-creds readOnly: true volumes: - name: db-creds-volume secret: secretName: db-creds defaultMode: 0400+-----------------------------+ +--------------------------------+| Secret: db-creds | | mountPath: /etc/db-creds ||-----------------------------| |--------------------------------|| username | -------> | /etc/db-creds/username || password | -------> | /etc/db-creds/password || defaultMode: 0400 | -------> | read permission only |+-----------------------------+ +--------------------------------+Для TLS том Secret природно відображається на файли сертифікатів. Застосунок або проксі все одно мають перезавантажити сертифікат після зміни файлу, тож успішне оновлення тому — це лише половина історії ротації. NGINX, Envoy, застосунки Java та сервери Go по-різному перезавантажують сертифікати, а це означає, що патерн монтування Kubernetes і стратегію перезавантаження застосунку треба проєктувати разом.
kubectl create secret tls web-tls \ --cert=tls.crt \ --key=tls.keyapiVersion: v1kind: Podmetadata: name: tls-nginxspec: containers: - name: nginx image: nginx:1.27 volumeMounts: - name: tls-certs mountPath: /etc/nginx/tls readOnly: true volumes: - name: tls-certs secret: secretName: web-tls defaultMode: 0400| Вибір впровадження Secret | Розкриття всередині контейнера | Поведінка при оновленні | Коли надавати перевагу |
|---|---|---|---|
| Змінна середовища | Видима через оточення процесу | Потребує перезапуску контейнера | Застарілі застосунки, що читають лише env-змінні |
| Повне монтування тому | Потрібне читання файлу | Файли можуть оновлюватися після синхронізації | Облікові дані, сертифікати, токени |
Монтування файлу subPath | Потрібне читання файлу | Не оновлюється автоматично | Лише точна заміна файлу |
| Secret для завантаження образу | Використовується kubelet, а не процесом застосунку | Застосовується при завантаженні образу | Автентифікація в приватному реєстрі |
Запит для активного навчання: Рецензент з безпеки каже, що ваш пароль бази даних не повинен з’являтися в
kubectl exec pod -- env. Ваш застосунок може читати або env-змінну, або файл. Який метод впровадження Secret задовольняє рецензента, і які налаштуванняvolumeMountтаsecretроблять дизайн надійнішим?
5. Оновлення, незмінність, проєкція та діагностика
Розділ «5. Оновлення, незмінність, проєкція та діагностика»ConfigMaps та Secrets — це об’єкти API, тож ви можете змінювати їх після створення, якщо вони не позначені незмінними. Складніше питання — чи помічає зміну запущене робоче навантаження. Kubernetes може оновити файли змонтованого тому після того, як kubelet спостерігає зміну об’єкта, але не може переписати оточення процесу. Навіть коли файл змінюється, застосунок може тримати старі значення в пам’яті, доки не перезавантажиться.
kubectl patch configmap app-config \ --type merge \ -p '{"data":{"LOG_LEVEL":"debug"}}'Після цього патчу Pod, який використовує APP_LOG_LEVEL з envFrom, усе ще має старе значення, доки контейнер не перезапуститься. Pod, який використовує повний том ConfigMap, може побачити оновлення вмісту файлу після короткої затримки синхронізації kubelet. Pod, який використовує subPath, лишається застарілим, доки його не перезапустять, бо монтування subPath не отримують оновлень ConfigMap чи Secret.
+----------------------+ +----------------------+ +----------------------+| ConfigMap update | | Injection method | | Running Pod outcome ||----------------------| |----------------------| |----------------------|| LOG_LEVEL=debug | -----> | env / envFrom | -----> | old value until restart || app.yaml changed | -----> | full volume mount | -----> | file refresh after sync || nginx.conf changed | -----> | subPath file mount | -----> | stale until restart |+----------------------+ +----------------------+ +----------------------+Незмінність змінює операційну модель. Коли ви встановлюєте immutable: true, Kubernetes відхиляє подальші оновлення даних об’єкта. Це звучить обмежувально, але може бути бажаним у продакшені, бо запобігає випадковій мутації та зменшує навантаження від спостереження з боку kubelet’ів. Звичайний патерн — створити нове ім’я об’єкта, як-от app-config-v2, та оновити шаблон Деплойменту, щоб Kubernetes виконав контрольоване розгортання.
apiVersion: v1kind: ConfigMapmetadata: name: app-config-v1immutable: truedata: LOG_LEVEL: info CACHE_TTL_SECONDS: "300"apiVersion: apps/v1kind: Deploymentmetadata: name: orders-apispec: replicas: 3 selector: matchLabels: app: orders-api template: metadata: labels: app: orders-api spec: containers: - name: orders-api image: nginx:1.27 envFrom: - configMapRef: name: app-config-v2Проєктовані томи дають змогу об’єднати кілька джерел в один каталог. Це корисно, коли застосунок очікує всю конфігурацію під одним шляхом, але дизайн вашого кластера розділяє нечутливу конфігурацію, чутливі облікові дані та метадані Pod’а на різні джерела Kubernetes. Проєктований том може містити ConfigMaps, Secrets, Downward API та токени сервісного акаунта.
apiVersion: v1kind: Podmetadata: name: projected-config-demospec: containers: - name: app image: nginx:1.27 volumeMounts: - name: combined-config mountPath: /etc/runtime readOnly: true volumes: - name: combined-config projected: sources: - configMap: name: app-config items: - key: LOG_LEVEL path: config/log-level - secret: name: db-creds items: - key: password path: secrets/db-password - downwardAPI: items: - path: pod/name fieldRef: fieldPath: metadata.name+--------------------+ +----------------------------------+| Projected sources | | /etc/runtime inside container ||--------------------| |----------------------------------|| ConfigMap LOG_LEVEL| ----> | /etc/runtime/config/log-level || Secret password | ----> | /etc/runtime/secrets/db-password || Downward API name | ----> | /etc/runtime/pod/name |+--------------------+ +----------------------------------+Діагностика збоїв конфігурації починається зі стану Pod’а та подій. Відсутній ConfigMap, відсутній Secret чи відсутній обов’язковий ключ можуть завадити запуску контейнера й зазвичай проявляються в подіях Pod’а. Хибний шлях може дати змогу контейнеру запуститися, але спричинити пізніший збій застосунку. Погане значення Secret може виглядати як помилка автентифікації застосунку, доки ви не декодуєте фактичні байти.
kubectl get pod broken-app
kubectl describe pod broken-app
kubectl get events --sort-by=.lastTimestampДля відсутніх об’єктів розділ Events зазвичай називає точне посилання, яке Kubernetes не зміг розв’язати. Для хибних ключів порівняйте специфікацію Pod’а з даними об’єкта. Для хибних шляхів до файлів виконайте kubectl exec у контейнер і дослідіть структуру каталогу. Мета — простежити значення від ключа об’єкта до правила впровадження й до розташування під час виконання.
kubectl get configmap app-config -o yaml
kubectl get pod app-config-volume -o yaml
kubectl exec app-config-volume -- ls -la /etc/app
kubectl exec app-config-volume -- cat /etc/app/application.yamlДля проблем з кодуванням Secret декодуйте значення й виявіть приховані символи. cat -e робить кінцевий символ нового рядка видимим як $, а xxd показує побайтове представлення. Використовуйте ці прийоми в лабораторіях та контрольованому налагодженні, а не недбало проти виробничих облікових даних.
kubectl get secret db-creds -o jsonpath='{.data.password}' | base64 -d | cat -e
kubectl get secret db-creds -o jsonpath='{.data.password}' | base64 -d | xxd| Симптом | Імовірна причина | Перша перевірка | Звичайне виправлення |
|---|---|---|---|
CreateContainerConfigError | Відсутній ConfigMap, Secret чи ключ | Події kubectl describe pod | Створити об’єкт або виправити посилання |
| Env-змінна має старе значення | ConfigMap чи Secret змінено після запуску | kubectl exec pod -- env | Перезапустити Pod або прокотити Деплоймент |
| Змонтований файл має старе значення | Використання subPath або застосунок закешував значення | YAML Pod’а та мітка часу файлу | Перезапустити Pod або повний том плюс перезавантаження |
| Файл відсутній у каталозі монтування | Хибний items.key чи зіставлення шляху | Ключі об’єкта та специфікація тому | Виправити ім’я ключа або шлях items |
| Автентифікація падає з правильним на вигляд паролем | Закодований символ нового рядка чи хибне поле | Декодувати через cat -e чи xxd | Перестворити Secret з stringData або echo -n |
| Застосунок не може прочитати файл Secret | Права доступу чи невідповідність користувача | ls -l усередині контейнера | Налаштувати defaultMode, fsGroup чи користувача застосунку |
Дизайн рівня досвідченого оператора часто поєднує кілька ідей: нечутливу конфігурацію в ConfigMap, чутливі значення в Secret, шляхи проєктованого тому, що відповідають очікуванням застосунку, незмінні об’єкти з номером версії в імені для контрольованих розгортань та RBAC, що обмежує, хто може читати Secrets. Іспит може лише попросити вас під’єднати Pod, але ті самі команди підтримують виробничий дизайн, коли ви розумієте семантику оновлення та безпеки.
Патерни та антипатерни
Розділ «Патерни та антипатерни»Найсильніший патерн — ставитися до конфігурації як до невеликого артефакту випуску, а не як до неформальної кластерної нотатки, що про неї легко забути. ConfigMap з іменем app-config дуже легко надрукувати під час іспиту, але реальні виробничі системи значно виграють від таких імен, що чітко виражають власника, версію та намір розгортання, як-от orders-api-config-v2 чи orders-nginx-routes-2026-05. Причина операційна: коли розгортання йде не так, ви хочете, щоб шаблон Деплойменту, події та історія Git показали саме те, яка версія конфігурації була під’єднана до Pod’а. Цей патерн особливо добре працює з незмінними ConfigMaps та Secrets, бо нове ім’я об’єкта вимушує нове посилання в шаблоні Pod’а й перетворює відкат на звичайне розгортання робочого навантаження замість прихованої мутації.
Інший надійний патерн — узгодити метод впровадження з контрактом перезавантаження застосунку ще до написання YAML. Якщо застосунок читає лише змінні середовища під час запуску, то ConfigMap на основі env прийнятний, але ви маєте планувати перезапуск щоразу, коли значення змінюється. Якщо застосунок стежить за файлами або може перезавантажитися за сигналом, повне монтування тому дає чистіший шлях для оновлень під час виконання. Якщо застосунку потрібен один точний шлях до файлу всередині заповненого каталогу образу, subPath корисний, але ви маєте задокументувати, що ротація потребує перезапуску Pod’а. Це різниця між маніфестом, який просто стартує, і маніфестом, який черговий інженер може експлуатувати під тиском.
Для чутливих значень безпечніше за замовчуванням монтувати Secrets як файли лише для читання й тримати RBAC вузьким. Монтування файлів не роблять Secret неможливим для витоку, бо скомпрометований процес усе одно може прочитати будь-який файл, який йому дозволено читати, але вони зменшують випадкове розкриття через виведення оточення процесу та широкі діагностичні команди. Поєднуйте монтування тому з readOnly: true, обмежувальним defaultMode та контекстом безпеки контейнера, що відповідає користувачеві застосунку. Коли застосунки підтримують і env-змінні, і файли, обирайте файли для облікових даних, а env-змінні приберігайте для нечутливих налаштувань запуску, які процес однаково не може перезавантажити.
Проєктовані томи — це патерн, до якого варто звертатися, коли застосунок очікує єдиний каталог конфігурації, але платформа має тримати джерела окремо. Чистий дизайн може розмістити нечутливі налаштування під config/, облікові дані під secrets/, а метадані Pod’а під pod/, монтуючи при цьому один том у /etc/runtime. Це дає застосунку одне дерево для читання, не вимушуючи операторів об’єднувати Secrets та ConfigMaps в один об’єкт API. Компроміс у тому, що зіставлення шляхів стає важливішим, тож кожен items.path слід переглядати так само ретельно, як порт контейнера чи пробу готовності.
Поширений антипатерн — використовувати envFrom як ярлик для всього, бо так специфікація Pod’а коротша. Цей ярлик може бути розумним для крихітного лабораторного застосунку, але стає безладним, коли багато ключів потрапляють до оточення процесу без явного зіставлення в специфікації контейнера. Конфлікти стає важче побачити, застарілі значення легко неправильно діагностувати, а чутливі значення з більшою ймовірністю з’являються у діагностичному виводі. Кращий виробничий стандарт — явний env.valueFrom для тих кількох змінних запуску, які застосунку справді потрібні, з префіксами лише тоді, коли угода застосунку вже їх очікує.
Інший антипатерн — монтувати ConfigMap поверх наявного каталогу застосунку, не перевіривши, що образ уже там містить. Монтування томів Kubernetes приховують початковий вміст каталогу за шляхом монтування, тож монтування в /etc/nginx/conf.d може прибрати запаковані типові налаштування, які автор образу очікував залишити присутніми. Іноді приховування каталогу — це саме те, чого ви хочете, але це має бути навмисною заміною, а не несподіванкою. Коли вам треба замінити лише один файл, використовуйте subPath і прийміть оновлення за рахунок перезапуску, або змонтуйте ConfigMap в окремий каталог і вкажіть застосунку на це розташування.
Найнебезпечніший антипатерн з усіх — ставитися до Secrets Kubernetes як до повноцінної системи керування секретами самої по собі. Об’єкт Secret — це лише об’єкт API зі спеціальною обробкою, а зовсім не гарантія того, що кожна навколишня система є безпечною. Вам усе одно потрібні шифрування в стані спокою, коли цього вимагає політика кластера, RBAC, що запобігає широкому доступу на читання, аудитне логування для чутливих операцій, безпечна обробка GitOps, що уникає коміту відкритого тексту, та процедура ротації, яка перезапускає чи перезавантажує споживачів. У реальних платформах Secrets Kubernetes часто стають точкою доставки облікових даних, якими керують деінде, тоді як зовнішнє сховище секретів, контролер чи сервіс хмарного провайдера володіють генерацією та ротацією.
| Патерн чи антипатерн | Використовуйте, коли | Операційний наслідок |
|---|---|---|
| Версіоновані незмінні ConfigMaps | Хочете аудитованих змін і контрольованих розгортань | Кожна зміна конфігурації стає новим посиланням на об’єкт |
Явні зіставлення env.valueFrom | Потрібно лише кілька налаштувань запуску | Специфікації Pod’а довші, але їх легше діагностувати |
| Монтування файлів Secret | Застосунок може читати файли облікових даних | Менше випадкового розкриття оточення процесу |
| Проєктований каталог часу виконання | Кілька джерел мають з’явитися під одним шляхом | Зіставлення шляхів потребує ретельного перегляду |
Широкий envFrom усюди | Ви поспішаєте чи копіюєте лабораторний ярлик | Зростають конфлікти, застарілі значення й випадкове розкриття |
| Сліпі монтування каталогів | Ви не перевірили шлях образу спочатку | Наявні файли образу можуть зникнути за томом |
Рамка прийняття рішень
Розділ «Рамка прийняття рішень»Починайте кожен дизайн із класифікації кожного окремого значення за двома осями: чутливістю та поведінкою під час оновлення. Чутливість підказує, чи належить значення радше до ConfigMap, чи до Secret. Поведінка під час оновлення підказує, чи має значення бути змінною середовища, повним монтуванням тому, проєктованим файлом чи навмисно орієнтованою на перезапуск заміною через subPath. Ця класифікація звучить просто, але запобігає більшості поганих дизайнів, бо змушує вас запитати, як застосунок насправді споживає значення, а не обирати найкоротший YAML.
Для нечутливого значення, яке читається раз під час запуску, використовуйте ConfigMap з env чи envFrom і плануйте перезапуск Pod’а при його зміні. Рівень логування, прапорець функціональності чи TTL кешу часто пасують до цього шляху, якщо застосунок не підтримує перезавантаження. Для нечутливого файлу, який застосунок може перечитати, монтуйте ConfigMap як повний том і покладіть файл під шлях, який застосунок уже розуміє. Якщо шлях має замінити один запакований файл, використовуйте subPath, але зробіть процедуру розгортання явною, бо оновлення файлів не пройдуть через це монтування.
Для чутливих значень спершу вирішіть, чи може застосунок читати з файлів. Якщо так, монтуйте том Secret з readOnly: true, встановіть обмежувальний defaultMode і тримайте шлях вузьким. Якщо застосунок підтримує лише змінні середовища, використовуйте secretKeyRef, а не envFrom, щоб специфікація Pod’а точно показувала, які ключі розкриваються. В обох випадках пам’ятайте, що зміна об’єкта Secret не означає автоматично, що застосунок використовує нові облікові дані. Змінні середовища потребують перезапуску, повні монтування томів потребують синхронізації kubelet плюс перечитування застосунком, а зовнішні системи можуть потребувати перекриття старих і нових облікових даних під час ротації.
Для значень, спільних для багатьох Pod’ів, вирішіть, що безпечніше — змінювати об’єкт на місці чи створювати нові версії. Змінні ConfigMaps зручні під час розробки, бо одне ім’я об’єкта може лишатися сталим, поки значення змінюються. Виробничі розгортання часто надають перевагу незмінним об’єктам із номером версії в імені, бо шаблон Деплойменту фіксує точну версію конфігурації, а старий об’єкт лишається доступним для відкату. Ціна — додаткова дисципліна іменування та прибирання, але ця ціна зазвичай менша за діагностику флоту Pod’ів, які всі посилаються на той самий змінний об’єкт, поки різні вузли оновлюються в різний час.
Використовуйте подану нижче матрицю як швидку перевірку дизайну перед написанням специфікації Pod’а. Це не заміна знання застосунку, але вона ловить найважливішу механіку Kubernetes. Якщо рядок пропонує два можливі варіанти, обирайте той, що робить збій легшим для спостереження, а відкат — легшим для виконання.
| Тип значення | Застосунок читає | Рекомендований об’єкт | Рекомендоване впровадження | Чи потрібен перезапуск для змін |
|---|---|---|---|---|
| Рівень логування при запуску | Змінна середовища | ConfigMap | env.valueFrom або префіксований envFrom | Так |
| Перезавантажуваний YAML застосунку | Файл | ConfigMap | Повне монтування тому з items | Можливо, залежить від перезавантаження застосунку |
| TLS-сертифікат і ключ | Файли | Secret | Том Secret лише для читання | Можливо, залежить від перезавантаження проксі |
| Пароль бази даних | Бажано файл | Secret | Том Secret лише для читання | Зазвичай так під час ротації |
| Облікові дані приватного реєстру | Конфігурація завантаження kubelet | Secret | imagePullSecrets | Використовується при завантаженні образу |
| Один файл-заміна NGINX | Точний шлях до файлу | ConfigMap | Монтування subPath | Так |
Зупиніться та передбачте: якщо Деплоймент використовує змінний ConfigMap через envFrom, ви застосовуєте до ConfigMap патч, а потім масштабуєте Деплоймент із трьох реплік до п’яти, які Pod’и бачать старе значення, а які — нове? Наявні три Pod’и зберігають своє старе оточення процесу, тоді як два нові Pod’и стартують уже з оновленим значенням. Цей змішаний стан — одна з причин, чому імена з номером версії та розгортання легше осмислити для виробничих змін.
Перш ніж обрати підхід, також вирішіть, як ви доведете, що він спрацював. Для env-змінних доказом зазвичай є kubectl exec <pod> -- env плюс перевірка перезапуску чи розгортання. Для змонтованих файлів доказом є kubectl exec <pod> -- ls -l <path> і читання шляху до файлу, який використовує застосунок. Для байтів Secret доказом може бути контрольоване декодування через cat -e чи xxd, але лише в лабораторії чи схваленій сесії налагодження. Хороший дизайн включає команду перевірки в runbook, бо різниця між робочим об’єктом і робочим представленням під час виконання — це саме те місце, де ховаються інциденти конфігурації.
Чи знали ви?
Розділ «Чи знали ви?»- Secrets за замовчуванням закодовані в base64, а не зашифровані за замовчуванням. Шифрування в стані спокою має бути налаштоване для кластера, а RBAC усе одно контролює, хто може читати об’єкти Secret через API.
- Оновлення томів ConfigMap і Secret зрештою відображаються через керовані kubelet’ом проєктовані файли, але змінні середовища ніколи не оновлюються всередині процесу, що вже працює. Застосунок також має перечитати чи перезавантажити файл, щоб використати нове значення.
- Об’єкти, позначені
immutable: true, не можна редагувати на місці, що корисно, коли ви хочете, щоб зміни конфігурації відбувалися лише через імена об’єктів із номером версії та контрольовані розгортання Pod’ів. - Проєктований том може поєднувати ConfigMaps, Secrets, дані Downward API та токени сервісного акаунта в одне дерево каталогів, що допомагає застосункам, які очікують єдиний шлях конфігурації часу виконання.
Типові помилки
Розділ «Типові помилки»| Помилка | Чому це трапляється | Як виправити |
|---|---|---|
Використання --from-file, коли кожен рядок має стати окремою змінною середовища | Весь файл стає одним ключем, тож envFrom не створює очікуваних змінних | Використовуйте --from-env-file для файлів KEY=value, які мають розбитися на окремі ключі |
Запис відкритого тексту під data Secret | Поле data очікує значення, закодовані в base64, тож застосунок може отримати некоректні байти | Використовуйте stringData для написаного вручну YAML або дайте kubectl create secret закодувати значення |
Кодування Secrets простим echo | Кінцевий символ нового рядка стає частиною облікових даних і може зламати автентифікацію | Використовуйте echo -n, printf, stringData чи kubectl create secret --from-literal |
| Очікування, що env-змінні оновляться після зміни ConfigMap чи Secret | Змінні середовища копіюються в процес при старті контейнера | Перезапустіть Pod або використайте монтування тому зі стратегією перезавантаження застосунку |
Використання subPath для файлів, які мають ротуватися автоматично | Монтування subPath не отримують оновлень ConfigMap чи Secret | Змонтуйте повний каталог тому або перезапускайте Pod’и під час ротації |
| Монтування ConfigMap поверх заповненого каталогу застосунку | Том приховує файли, які вже були присутні в образі за цим шляхом | Монтуйте в порожній каталог конфігурації або використовуйте subPath, коли прийнятна точна заміна |
Впровадження чутливих значень через envFrom за замовчуванням | Secrets стають широкими даними оточення процесу, які легше витекти в логи чи діагностику | Надавайте перевагу монтуванню томів Secret лише для читання для облікових даних, коли застосунок підтримує файли |
| Надання широким користувачам чи сервісним акаунтам права читати всі Secrets | Будь-хто з доступом на читання може отримати й декодувати значення Secret | Звужуйте RBAC і поєднуйте його з шифруванням у стані спокою та аудитним логуванням |
Тест
Розділ «Тест»Питання 1
Розділ «Питання 1»Ваша команда створила settings.env з десятьма рядками KEY=value, а потім виконала kubectl create configmap web-settings --from-file=settings.env. Pod використовує envFrom.configMapRef.name: web-settings, але застосунок повідомляє, що LOG_LEVEL та CACHE_TTL_SECONDS не встановлені. Що сталося, і як би ви виправили команду створення ConfigMap?
Показати відповідь
--from-file=settings.env зберіг увесь файл під одним ключем з іменем settings.env; Kubernetes не розбив рядки на окремі ключі. Коли envFrom спробував створити змінні середовища, ім’я ключа не було корисним налаштуванням застосунку, а очікувані ключі на кшталт LOG_LEVEL не існували. Перестворіть ConfigMap з --from-env-file=settings.env, щоб кожен валідний рядок KEY=value став власним ключем. Якщо Pod уже існує, перезапустіть його після перестворення ConfigMap, бо змінні середовища встановлюються лише при старті контейнера.
Питання 2
Розділ «Питання 2»Pod монтує ConfigMap у /etc/app, а ConfigMap містить ключі application.yaml та routes.yaml. Колега очікує, що файли з’являться безпосередньо як /application.yaml та /routes.yaml, бо такими є імена ключів. Застосунок падає з помилкою «file not found» за шляхом /etc/app/application.yaml. Як ви поясните зіставлення шляхів і перевірите реальні файли?
Показати відповідь
Для повного монтування тому ConfigMap кожен ключ стає файлом під mountPath. Ключ application.yaml стає /etc/app/application.yaml, а routes.yaml стає /etc/app/routes.yaml. Файли не з’являються в корені файлової системи, доки том не змонтовано в /, що було б поганим дизайном. Перевірте зіставлення через kubectl exec <pod> -- ls -la /etc/app, а потім прочитайте очікуваний файл за допомогою kubectl exec <pod> -- cat /etc/app/application.yaml. Якщо застосунок шукає деінде, змініть конфігурацію застосунку або скоригуйте mountPath та items.path.
Питання 3
Розділ «Питання 3»Pod NGINX використовує subPath, щоб змонтувати один ключ ConfigMap на /etc/nginx/conf.d/default.conf. Ви застосовуєте до ConfigMap патч, щоб додати нову локацію /api, але трафік усе ще йде за старою конфігурацією через кілька хвилин. Які дві окремі причини того, що цей дизайн може не оновити поведінку негайно?
Показати відповідь
По-перше, монтування subPath не отримують автоматичних оновлень ConfigMap, тож файл, змонтований у /etc/nginx/conf.d/default.conf, лишається застарілим, доки Pod не перезапустять. По-друге, навіть якби файл оновився через повне монтування тому, NGINX може тримати свою стару конфігурацію в пам’яті, доки його не перезавантажать. Зручне для іспиту виправлення — перезапустити чи перестворити Pod. Виробничий дизайн зазвичай монтував би повний каталог конфігурації або використовував би імена ConfigMap із номером версії, а потім поєднував би зміни файлів із явним перезавантаженням NGINX чи поетапним оновленням Деплойменту.
Питання 4
Розділ «Питання 4»Розробник пише маніфест Secret із data.password: example-db-password і застосовує його. Pod стартує, але автентифікація бази даних падає. Він стверджує, що kubectl get secret -o yaml чітко показує, що поле password існує. Що слід перевірити, і як слід переписати маніфест?
Показати відповідь
Проблема, ймовірно, в тому, що data містить відкритий текст замість даних, закодованих у base64. Наявність ключа лише доводить, що Kubernetes щось зберіг; вона не доводить, що декодовані байти — це бажаний пароль. Перевірте декодоване значення контрольованою командою на кшталт kubectl get secret <name> -o jsonpath='{.data.password}' | base64 -d | cat -e. Перепишіть маніфест, використовуючи stringData.password: example-db-password, або закодуйте значення правильно через echo -n 'example-db-password' | base64 і розмістіть результат під data.password.
Питання 5
Розділ «Питання 5»Аудит безпеки виявляє, що облікові дані бази даних видимі через kubectl exec orders-api -- env. Застосунок може читати облікові дані або зі змінних середовища, або з файлів. Яка зміна Kubernetes зменшила б випадкове розкриття, і які налаштування посилення слід додати?
Показати відповідь
Облікові дані наразі впроваджуються як змінні середовища через env, envFrom чи secretKeyRef. Перейдіть на монтування тому Secret, щоб застосунок читав файли на кшталт /etc/db-creds/username та /etc/db-creds/password. Встановіть readOnly: true на volumeMount і використовуйте обмежувальний defaultMode, наприклад 0400, у томі Secret. Це не усуває потреби в RBAC і шифруванні в стані спокою, але уникає розкриття значень через звичайний огляд оточення процесу.
Питання 6
Розділ «Питання 6»Ваша команда позначає app-config незмінним, щоб запобігти випадковим правкам. За тиждень продакшену потрібен LOG_LEVEL=debug для інциденту. Колега намагається kubectl patch configmap app-config, але Kubernetes відхиляє зміну. Яку процедуру розгортання слід використати натомість?
Показати відповідь
Незмінні ConfigMaps не можна змінити на місці. Створіть новий ConfigMap з іменем, що містить номер версії, як-от app-config-v2, із оновленим значенням. Потім оновіть шаблон Pod’а Деплойменту, щоб він посилався на app-config-v2, що запускає розгортання й робить зміну аудитованою. Після інциденту створіть ще одну версію або відкотіть Деплоймент до попереднього імені ConfigMap. Ця процедура ставиться до змін конфігурації як до артефактів випуску замість змінного спільного стану.
Питання 7
Розділ «Питання 7»Pod падає з CreateContainerConfigError після того, як ви додали обов’язкове посилання на ключ Secret. Secret існує, а специфікація Pod’а посилається на правильне ім’я Secret. Які перевірки рівня Kubernetes ви б виконали, перш ніж звинувачувати образ застосунку?
Показати відповідь
Почніть з kubectl describe pod <pod> і прочитайте розділ Events, бо Kubernetes часто повідомляє про відсутній ключ чи некоректне посилання саме там. Потім дослідіть ключі Secret за допомогою kubectl get secret <secret> -o yaml і точно порівняйте їх із secretKeyRef.key Pod’а; імена ключів чутливі до регістру. Також підтвердьте, що Pod і Secret перебувають в одному просторі імен, бо посилання Pod’а не перетинають простори імен. Якщо ключ необов’язковий, контейнер може стартувати без значення, але для обов’язкових посилань Kubernetes блокує створення контейнера, доки посилання не стане валідним.
Практична вправа
Розділ «Практична вправа»Сценарій: Налаштування та діагностика вебзастосунку
Розділ «Сценарій: Налаштування та діагностика вебзастосунку»Ви — інженер платформи на чергуванні для невеликого вебзастосунку. Застосунку потрібні нечутливі налаштування часу виконання, конфігураційний файл NGINX та облікові дані бази даних. Ви створите об’єкти, змонтуєте їх у Pod, перевірите представлення під час виконання, навмисно оновите конфігурацію та поясните, які значення змінюються без перезапуску.
Крок 1: Підготовка простору імен та нечутливих налаштувань
Розділ «Крок 1: Підготовка простору імен та нечутливих налаштувань»Створіть простір імен для лабораторії, щоб прибирання було безпечним, а посилання на об’єкти — легкими для дослідження. Перший ConfigMap використовує літерали, бо значення короткі й природно відображаються на змінні середовища. Другий ConfigMap використовує файл, бо NGINX очікує повний конфігураційний файл сервера.
kubectl create namespace config-demo
kubectl create configmap app-settings -n config-demo \ --from-literal=LOG_LEVEL=info \ --from-literal=CACHE_TTL_SECONDS=300 \ --from-literal=FEATURE_CHECKOUT_V2=truecat > /tmp/kubedojo-nginx.conf <<'EOF'server { listen 80;
location / { return 200 'KubeDojo config demo\n'; add_header Content-Type text/plain; }
location /health { return 200 'OK\n'; add_header Content-Type text/plain; }}EOF
kubectl create configmap nginx-config -n config-demo \ --from-file=nginx.conf=/tmp/kubedojo-nginx.confКрок 2: Створення облікових даних бази даних як Secret
Розділ «Крок 2: Створення облікових даних бази даних як Secret»Створіть Secret імперативно, щоб Kubernetes обробив кодування. Це найбезпечніший іспитовий шлях, коли значення містить пунктуацію. У продакшені уникайте розміщення реальних секретів безпосередньо в історії оболонки; ця лабораторія використовує одноразові значення в локальному просторі імен.
kubectl create secret generic db-creds -n config-demo \ --from-literal=username=orders_user \ --from-literal=password='example-lab-password'Дослідіть форму об’єкта без зайвого виведення декодованих значень. Ви маєте побачити рядки base64 під data, що підтверджує формат зберігання, але не шифрування.
kubectl get secret db-creds -n config-demo -o yamlКрок 3: Розгортання Pod’а зі змінними середовища та змонтованими файлами
Розділ «Крок 3: Розгортання Pod’а зі змінними середовища та змонтованими файлами»Застосуйте Pod, що використовує три різні патерни впровадження. app-settings завантажується через envFrom із префіксом, nginx-config монтується через subPath, щоб замінити один точний файл, а db-creds монтується як файли лише для читання з обмежувальними правами. Цей змішаний дизайн реалістичний, бо різні значення мають різних споживачів і ризики.
cat > /tmp/kubedojo-webapp.yaml <<'EOF'apiVersion: v1kind: Podmetadata: name: webapp namespace: config-demo labels: app: webappspec: containers: - name: nginx image: nginx:1.27 ports: - containerPort: 80 envFrom: - configMapRef: name: app-settings prefix: APP_ volumeMounts: - name: nginx-config mountPath: /etc/nginx/conf.d/default.conf subPath: nginx.conf - name: db-creds mountPath: /etc/db-creds readOnly: true volumes: - name: nginx-config configMap: name: nginx-config items: - key: nginx.conf path: nginx.conf - name: db-creds secret: secretName: db-creds defaultMode: 0400EOF
kubectl apply -f /tmp/kubedojo-webapp.yaml
kubectl wait --for=condition=ready pod/webapp -n config-demo --timeout=90sКрок 4: Перевірка представлення під час виконання
Розділ «Крок 4: Перевірка представлення під час виконання»Перевірте кожен шлях впровадження окремо. Мета — не просто довести, що Pod запущений; мета — простежити кожен ключ об’єкта до того, що контейнер насправді може побачити. Це та сама звичка діагностики, яка вам потрібна, коли Pod стартує, але застосунок поводиться неправильно.
kubectl exec webapp -n config-demo -- env | grep '^APP_'
kubectl exec webapp -n config-demo -- cat /etc/nginx/conf.d/default.conf
kubectl exec webapp -n config-demo -- ls -l /etc/db-creds
kubectl exec webapp -n config-demo -- sh -c 'curl -s localhost/health'Вивід оточення має містити APP_LOG_LEVEL=info, APP_CACHE_TTL_SECONDS=300 та APP_FEATURE_CHECKOUT_V2=true. Конфігурація NGINX має відповідати файлу, який ви створили під /tmp, але пам’ятайте, що його змонтовано через subPath. Файли Secret мають існувати під /etc/db-creds, а режим має відображати обмежувальне налаштування тому Secret.
Крок 5: Оновлення ConfigMap та спостереження за застарілими значеннями
Розділ «Крок 5: Оновлення ConfigMap та спостереження за застарілими значеннями»Застосуйте патч до ConfigMap app-settings, а потім перевірте оточення запущеного процесу. Значення не зміниться всередині наявного контейнера, бо змінні середовища копіюються при старті процесу. Це не баг; це очікуваний контракт часу виконання.
kubectl patch configmap app-settings -n config-demo \ --type merge \ -p '{"data":{"LOG_LEVEL":"debug"}}'
kubectl exec webapp -n config-demo -- env | grep '^APP_LOG_LEVEL='Тепер перезапустіть Pod, замінивши його з того самого маніфесту. Це проста лабораторія з Pod’ом, тож replace --force прийнятний. У Деплойменті ви б натомість оновили шаблон Pod’а або перезапустили розгортання.
kubectl replace --force -f /tmp/kubedojo-webapp.yaml
kubectl wait --for=condition=ready pod/webapp -n config-demo --timeout=90s
kubectl exec webapp -n config-demo -- env | grep '^APP_LOG_LEVEL='Крок 6: Діагностика збою через відсутній ключ
Розділ «Крок 6: Діагностика збою через відсутній ключ»Створіть навмисно зламаний маніфест Pod’а, що посилається на ключ, який не існує. Не витрачайте час на здогадки з пам’яті; використайте події Kubernetes, щоб визначити точний збій. Цей крок практикує швидкий шлях діагностики CKA для посилань на конфігурацію.
cat > /tmp/kubedojo-broken.yaml <<'EOF'apiVersion: v1kind: Podmetadata: name: broken-webapp namespace: config-demospec: containers: - name: nginx image: nginx:1.27 env: - name: APP_REQUIRED_SETTING valueFrom: configMapKeyRef: name: app-settings key: DOES_NOT_EXISTEOF
kubectl apply -f /tmp/kubedojo-broken.yaml
kubectl get pod broken-webapp -n config-demo
kubectl describe pod broken-webapp -n config-demoПрочитайте розділ Events і визначте відсутній ключ. Потім полагодьте Pod, або змінивши ключ-посилання на наявний ключ, або додавши відсутній ключ до ConfigMap. Для цієї лабораторії додайте відсутній ключ і поспостерігайте, як Pod відновлюється.
kubectl patch configmap app-settings -n config-demo \ --type merge \ -p '{"data":{"DOES_NOT_EXIST":"now-present"}}'
kubectl wait --for=condition=ready pod/broken-webapp -n config-demo --timeout=90s
kubectl exec broken-webapp -n config-demo -- env | grep APP_REQUIRED_SETTINGКрок 7: Перевірка байтів Secret, коли автентифікація виглядає хибною
Розділ «Крок 7: Перевірка байтів Secret, коли автентифікація виглядає хибною»Створіть Secret із кінцевим символом нового рядка, щоб побачити, чому невидимі байти мають значення. Це контрольована вправа з налагодження; суть у тому, щоб вивчити симптом без використання реальних облікових даних. Команда навмисно використовує простий echo, який додає символ нового рядка.
echo 'bad-password' | base64
cat > /tmp/kubedojo-bad-secret.yaml <<'EOF'apiVersion: v1kind: Secretmetadata: name: bad-db-creds namespace: config-demotype: Opaquedata: password: YmFkLXBhc3N3b3JkCg==EOF
kubectl apply -f /tmp/kubedojo-bad-secret.yaml
kubectl get secret bad-db-creds -n config-demo \ -o jsonpath='{.data.password}' | base64 -d | cat -eМаркер $ у кінці показує, що декодоване значення містить символ нового рядка. Перестворіть Secret, використовуючи stringData або метод кодування без символу нового рядка. У реальній роботі ця невелика побайтова перевірка часто заощаджує час, коли кожен видимий символ здається правильним.
cat > /tmp/kubedojo-good-secret.yaml <<'EOF'apiVersion: v1kind: Secretmetadata: name: good-db-creds namespace: config-demotype: OpaquestringData: password: bad-passwordEOF
kubectl apply -f /tmp/kubedojo-good-secret.yaml
kubectl get secret good-db-creds -n config-demo \ -o jsonpath='{.data.password}' | base64 -d | cat -eКритерії успіху
Розділ «Критерії успіху»- Ви створили простір імен, ConfigMap із літералів, ConfigMap із файлу та generic Secret, не використовуючи жорстко закодованих виробничих облікових даних.
- Pod
webappдосяг стануReadyі показав змінні середовищаAPP_з ConfigMap. - Конфігурація NGINX з’явилася за шляхом
/etc/nginx/conf.d/default.confчерез монтуванняsubPath, і ви можете пояснити, чому цей файл не оновлюється автоматично. - Файли облікових даних бази даних з’явилися під
/etc/db-credsз поведінкою монтування лише для читання та обмежувальними правами тому Secret. - Після застосування патчу до
app-settingsви спостерігали, що змінна середовища запущеного процесу лишилася застарілою, доки Pod не перезапустили. - Ви діагностували
CreateContainerConfigError, спричинений відсутнім ключем ConfigMap, за допомогоюkubectl describe pod. - Ви декодували значення Secret через
cat -eі визначили різницю між паролем із кінцевим символом нового рядка та без нього.
Прибирання
Розділ «Прибирання»kubectl delete namespace config-demo
rm -f /tmp/kubedojo-nginx.conf \ /tmp/kubedojo-webapp.yaml \ /tmp/kubedojo-broken.yaml \ /tmp/kubedojo-bad-secret.yaml \ /tmp/kubedojo-good-secret.yamlДжерела
Розділ «Джерела»- ConfigMaps — Основне джерело щодо нечутливої конфігурації, впровадження через env-змінні та файли, незмінності, структури «ключ-значення», обмежень розміру та поведінки поширення оновлень для змонтованих ConfigMaps.
- Secrets — Основне джерело щодо семантики Secret, застережень безпеки, споживання через env-змінні та томи, поведінки необов’язкових і відсутніх ключів, незмінності, поширення оновлень та застережень щодо оновлення
subPath. - kubernetes.io: kubectl create configmap — Довідник команди kubectl безпосередньо документує семантику
--from-fileта--from-env-file. - kubernetes.io: kubectl create secret generic — Довідник команди для створення generic Secret з літералів, файлів та env-файлів.
- kubernetes.io: kubectl create secret tls — Довідник команди для створення TLS Secret із файлів сертифіката та приватного ключа.
- kubernetes.io: projected volumes — Сторінка концепції проєктованих томів безпосередньо перелічує ці типи джерел для єдиного проєктованого каталогу.
- Kubernetes volumes: ConfigMap — Довідник концепції зберігання щодо поведінки тому ConfigMap та необов’язкових ключів.
- Kubernetes volumes: Secret — Довідник концепції зберігання щодо поведінки тому Secret, режимів файлів та доставки на основі tmpfs.
- Encrypting Secret Data at Rest — Документація завдання Kubernetes щодо налаштування провайдерів шифрування API-сервера для даних Secret.
- RBAC Good Practices — Рекомендації Kubernetes щодо обмеження потужних дозволів, зокрема доступу до об’єктів Secret.
- Downward API — Основна документація щодо розкриття метаданих Pod’а та контейнера для робочих навантажень, зокрема через шляхи проєктованого тому.
- Configure a Pod to Use a ConfigMap — Документація завдання з прикладами споживання ConfigMaps через змінні середовища та томи.
- kubernetes.io: distribute credentials secure — Сторінка завдання Secret безпосередньо показує імперативне створення та попередження про екранування в оболонці для спеціальних символів.
- kubernetes.io: volumes — Сторінка концепції томів пояснює, що томи монтуються у файлову систему контейнера за вказаними шляхами, що є розумним опертям для цього операційного попередження, навіть якщо вона не констатує наслідок з прихованими файлами дослівно.
Наступний модуль
Розділ «Наступний модуль»Ви завершили Частину 2: Workloads & Scheduling. Продовжуйте з Підсумковим тестом Частини 2, щоб перевірити патерни робочих навантажень разом перед переходом до Services & Networking.