В чому різниця між ConfigMap та Secret
І ConfigMap, і Secret — це об'єкти Kubernetes, призначені для відокремлення конфігурації та параметрів оточення від скомпільованого коду застосунку (згідно з III фактором методо...
🟢 Junior Level
30-секундна відповідь
І ConfigMap, і Secret — це об’єкти Kubernetes, призначені для відокремлення конфігурації та параметрів оточення від скомпільованого коду застосунку (згідно з III фактором методології Twelve-Factor App).
Головна відмінність між ними полягає в ступені конфіденційності даних:
ConfigMap: призначений для відкритих, неконфіденційних налаштувань (URL баз даних, порти сервісів, прапорці фіч, рівні логування). Дані зберігаються у вигляді звичайного відкритого тексту.Secret: призначений для чутливих даних та облікових записів (паролі СУБД, приватні SSH/TLS-ключі, API-токени, облікові дані Docker Registry). У маніфестах значення кодуються у формат Base64.
Наочна аналогія з життя
- ConfigMap — це стікер на моніторі співробітника: на ньому написано внутрішній телефон їдальні та номер кабінету бухгалтерії. Будь-який колега, який проходить повз, може прочитати цю інформацію, у цьому немає загрози безпеці.
- Secret — це замкнений сейф під столом: усередині лежать печатки компанії, трудові книжки та банківські ключі. Доступ до нього дозволений лише уповноваженим особам за суворим регламентом.
Приклади базових маніфестів
1. ConfigMap (Відкритий текст)
apiVersion: v1
kind: ConfigMap
metadata:
name: order-service-config
data:
DB_HOST: "postgres.prod.svc.cluster.local"
DB_PORT: "5432"
SPRING_PROFILES_ACTIVE: "prod"
2. Secret (Base64 кодування)
apiVersion: v1
kind: Secret
metadata:
name: order-service-secret
type: Opaque
data:
# echo -n "secret123" | base64 -> c2VjcmV0MTIz
DB_PASSWORD: c2VjcmV0MTIz
[!WARNING] Base64 — це НЕ шифрування! Це лише зворотний алгоритм кодування двійкових даних у текст. Будь-який розробник, який має доступ до читання секретів у кластері, може миттєво декодувати пароль командою
echo "c2VjcmV0MTIz" | base64 -d.
🟡 Middle Level
Способи впровадження в Pod: Змінні оточення vs Томи
[ ConfigMap / Secret ]
│
┌──────────────────────────┴──────────────────────────┐
▼ ▼
[ 1. Environment Variables ] [ 2. Volume Mount ]
- Значення фіксуються під час старту - Монтується як каталог із файлами
- ❌ Не оновлюються без перезапуску пода - 🟢 Оновлюються на льоту без перезапуску!
1. Через змінні оточення (env / envFrom)
containers:
- name: java-app
image: order-service:1.0
env:
- name: DATABASE_HOST
valueFrom:
configMapKeyRef:
name: order-service-config
key: DB_HOST
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: order-service-secret
key: DB_PASSWORD
Критичний недолік: якщо ви зміните пароль у Secret, значення змінної оточення в працюючому Linux-процесі НЕ зміниться. Потрібен перезапуск пода (kubectl rollout restart).
2. Через монтування тому (Volume Mounts)
containers:
- name: java-app
volumeMounts:
- name: config-dir
mountPath: /app/config
readOnly: true
volumes:
- name: config-dir
configMap:
name: order-service-config
Перевага: Kubelet автоматично відстежує зміни в ConfigMap та оновлює файли на диску пода без перезапуску контейнера!
Секція stringData в Secret
Щоб інженерам не доводилося вручну кодувати кожен рядок через base64, Kubernetes підтримує поле stringData:
apiVersion: v1
kind: Secret
metadata:
name: my-secret
type: Opaque
stringData:
DB_PASSWORD: "plain-text-password-here" # Пишеться відкритим текстом!
Під час збереження маніфесту API-сервер сам автоматично переводить усі значення зі stringData в Base64 і записує їх у поле data.
Прапорець immutable: true
Починаючи з Kubernetes 1.21, для обох об’єктів доступний прапорець незмінності:
immutable: true
- Захист від випадкових правок: захищає продакшен-бази даних від збоїв через помилкову зміну конфігурації.
- Зниження навантаження на кластер: Kubelet припиняє безперервно опитувати API Server у пошуках змін у файлах конфігурації, радикально заощаджуючи CPU та пам’ять у кластерах із тисячами подів.
🔴 Senior Level
Ілюзія безпеки Secret та Encryption at Rest
За замовчуванням Kubernetes зберігає всі об’єкти Secret у базі даних etcd у відкритому незашифрованому вигляді (тільки Base64).
Зловмисник, який отримав доступ до резервної копії etcd або диска майстер-ноди, отримує доступ до всіх секретів кластера.
Як увімкнути реальне шифрування (Encryption at Rest)
Налаштовується на рівні kube-apiserver через конфігураційний файл --encryption-provider-config:
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
# Рекомендований enterprise-стандарт: апаратний KMS хмари
- kms:
apiVersion: v2
name: aws-kms-provider
endpoint: unix:///var/run/kmsplugin/socket.sock
# Або локальне симетричне AES-GCM/AES-CBC шифрування
- aescbc:
keys:
- name: key1
secret: <32-byte-base64-key>
- identity: {} # Запасний провайдер для читання незашифрованих старих даних
Атомарне оновлення файлів конфігурації через Симлінки (Symlink Swapping)
Коли Kubelet оновлює змонтований ConfigMap на диску контейнера, він не перезаписує файли безпосередньо. Якби процес Java читав файл у момент перезапису, виникла б помилка часткового читання (Torn Read).
Kubernetes вирішує це за допомогою трирівневої структури символічних посилань:
/app/config/
├── application.yaml -> ..data/application.yaml
├── ..data -> ..2026_09_26_14_30_00.123456789 (Симлінк на актуальну папку)
└── ..2026_09_26_14_30_00.123456789/ (Каталог із реальними файлами)
└── application.yaml
Під час оновлення конфігурації Kubelet завантажує нові файли в каталог із новою часовою міткою та виконує одну атомарну системну операцію заміни симлінка ..data (rename()).
Production-стандарт: External Secrets Operator (ESO)
У зрілих enterprise-архітектурах секрети ніколи не створюються вручну через YAML і не зберігаються в Git. Використовується External Secrets Operator:
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: order-db-secret
spec:
secretStoreRef:
name: hashicorp-vault # Інтеграція з Vault, AWS Secrets Manager або GCP Secret Manager
kind: ClusterSecretStore
target:
name: order-service-db-creds # Ім'я створюваного нативного K8s Secret
data:
- secretKey: password
remoteRef:
key: secret/data/production/database
property: password
ESO самостійно здійснює ротацію ключів, синхронізацію та відкликання прав без втручання розробника.
4 Tricky Questions
1. Якщо оновити значення в об’єкті ConfigMap, чи оновляться автоматично змінні оточення (env) та змонтовані томи (volumeMounts) усередині вже працюючого контейнера?
Відповідь:
- Змінні оточення (
env/envFrom): НЕ оновляться ніколи. Змінні оточення формуються ядром Linux у момент створення процесу контейнера (execve) і залишаються незмінними до повної загибелі процесу. Щоб застосунок підхопив нові змінні, под необхідно примусово перезапустити (kubectl rollout restart). - Змонтовані томи (
volumeMounts): оновляться автоматично. Kubelet у межах циклу синхронізації (зазвичай від 10 до 60 секунд) оновить симлінк..dataу змонтованій директорії. Проте сам застосунок (наприклад, Spring Boot) повинен уміти перечитувати файли з диска (через@RefreshScope, Spring Cloud Kubernetes або власний файловий вотчер).
2. У чому різниця між полями data та stringData у специфікації Secret, і що станеться, якщо одне й те саме ім’я ключа вказано в обох полях одночасно?
Відповідь:
data: приймає значення, строго закодовані в Base64. Застосовується в автоматизованих пайплайнах CI/CD.stringData: приймає значення у вигляді звичайного відкритого тексту (Plain Text). Це допоміжне поле «тільки для запису» (Write-Only), створене для зручності людини.- Конфлікт ключів: якщо один і той самий ключ оголошений і в
data, і вstringData, значення зіstringDataмає абсолютний пріоритет і перезаписує значення зdata. Під час читання секрету з API полеstringDataзавжди видаляється, а підсумковий результат повертається строго в поліdataв Base64.
3. Чому Java-бібліотека java.nio.file.WatchService, налаштована на конкретний файл конфігурації /app/config/application.properties, припиняє отримувати події оновлення після першої ж зміни ConfigMap?
Відповідь:
Kubelet оновлює файли тому не модифікацією байтів усередині наявного дескриптора файлу, а атомарною підміною симлінка ..data на нову директорію.
Старий файл, на який був підписаний WatchService Java за його Linux Inode, фактично видаляється з дерева директорій. Посилання на старий Inode стає «осиротілим», і операційна система більше ніколи не генерує для нього подій ENTRY_MODIFY.
Рішення: підписувати WatchService не на конкретний цільовий файл, а на батьківську директорію /app/config/, відстежувати подію перестворення симлінка та повторно відкривати файловий потік.
4. Які жорсткі обмеження на максимальний розмір даних в одному об’єкті ConfigMap або Secret, і чим обумовлений цей ліміт?
Відповідь:
Максимальний розмір будь-якого об’єкта ConfigMap або Secret становить строго 1 Мегабайт (1 MiB).
Це обмеження продиктоване архітектурою сховища бази даних etcd:
- За замовчуванням максимальний розмір одного gRPC-запиту та однієї транзакції в
etcdжорстко обмежений 1.5 МБ. - Зберігання великих конфігураційних файлів, сертифікатів або бінарних файлів у
ConfigMapпризводить до катастрофічної фрагментації бази данихetcd, падіння продуктивності консенсусу Raft та деградації всього кластера. Великі файли повинні передаватися через постійні дискові томи (PersistentVolumes) або зовнішні об’єктні сховища (S3, MinIO).
🎯 Шпаргалка для інтерв’ю
Головне про ConfigMap та Secret
- ConfigMap: відкриті налаштування (URL, порти, параметри); зберігається у відкритому тексті.
- Secret: конфіденційні дані (паролі, сертифікати, токени); у YAML пишеться в Base64.
- Безпека: Base64 $\ne$ шифрування! Для безпеки etcd потрібне Encryption at Rest.
- Ліміт розміру: строго 1 МБ (обмеження etcd).
- Змінні оточення (
env): фіксуються під час старту пода; не оновлюються без перезапуску. - Томи (
volumes): оновлюються на льоту Kubelet’ом через заміну симлінків..data. stringData: дозволяє писати секрети звичайним текстом; API-сервер сам зробить Base64.- Enterprise-стандарт: External Secrets Operator (ESO) + HashiCorp Vault.
Порівняльна таблиця
| Параметр | ConfigMap | Secret |
| :— | :— | :— |
| Формат у маніфесті | Відкритий текст UTF-8 | Base64 (data) або текст (stringData) |
| Зберігання в etcd | Plain Text | Plain Text (за замовчуванням) / Зашифровано (AES/KMS) |
| Вбудовані типи | Немає (універсальний) | Opaque, kubernetes.io/tls, dockerconfigjson |
| Призначення | Змінні середовищ, конфіги Spring | Паролі БД, токени, SSL-сертифікати |
Червоні прапорці на співбесіді (Чого говорити не можна)
- ❌ «Kubernetes Secret надійно шифрує паролі за допомогою Base64» — Base64 це кодування, декодується в один рядок.
- ❌ «Якщо змінити ConfigMap, змінні оточення в працюючому Java-контейнері оновляться автоматично» — env vars не оновлюються без рестарту пода.
- ❌ «У ConfigMap можна покласти JAR-файл або відеоролик розміром 50 МБ» — ліміт будь-якого об’єкта дорівнює рівно 1 МБ.