ConfigMap, Secret и тома в Kubernetes
Секрет и конфигурация - это отдельные объекты кластера, в которых лежат значения для приложений; под, то есть запущенный экземпляр приложения, подключает их к себе. Положил пароль в секрет кластера и посмотрел, как он хранится. В описании объекта лежит строка 0KHRg9C/0LXRgNCh0LXQutGA0LXRgi0yMDI2, а одна команда раскодирования превращает её обратно в «СуперСекрет-2026». Это не шифрование, а кодирование - оно защищает от случайного взгляда и ни от чего больше.
Стержень: конфигурация и секреты - отдельные объекты кластера; способ подключения решает, обновятся ли они без перезапуска.
// Формулировки: «чем секрет отличается от конфигурации?», «обновится ли значение без перезапуска пода?», «как хранить секреты по-настоящему?»
Переменная против файла
Подключить значение можно двумя способами: переменной окружения или файлом в примонтированном каталоге. Разница между ними принципиальная, и я её замерил.
Поднял под, где один и тот же ключ подключён обоими способами, и поменял значение в кластере с production на staging. Файл в поде обновился САМ через 61 секунду - никто под не трогал. А переменная окружения так и осталась со старым значением: переменные читаются один раз при запуске процесса, и поменять их можно только перезапуском пода.
// Отсюда практика. Если значение может меняться на ходу и приложение умеет перечитывать файл - подключайте файлом. Если приложение читает настройки только при старте (а таких большинство), честнее подключать переменными и явно перезапускать поды при изменении. Обычный приём для этого - положить в описание пода отпечаток конфигурации: изменилась она - изменилось описание - кластер сам катит обновление.
- подключение переменной
- значение читается один раз при старте; меняется только перезапуском
- подключение файлом
- файл в поде обновляется сам, с задержкой около минуты
Секрет - это не защита
Секрет отличается от обычной конфигурации тремя вещами: значения хранятся закодированными, у объекта есть тип, и кластер обращается с ним чуть аккуратнее - не показывает содержимое в общих списках. На этом отличия заканчиваются.
Мой замер: значение достаётся одной командой и раскодируется второй. Любой, у кого есть право читать секреты в этом пространстве, видит пароль. Более того, по умолчанию содержимое лежит в хранилище кластера как есть, без шифрования на диске.
// Отсюда набор мер, который делает секреты действительно секретами. Права: читать секреты можно не всем и не везде - это настраивается ролями. Шифрование хранилища кластера - отдельная настройка, которую включают руками. Внешнее хранилище секретов, из которого значения приезжают в под на время работы. И отдельно - не класть секреты в описания, которые лежат в репозитории: там им не место независимо от того, как называется объект.
- кодирование
- обратимое преобразование текста; снимается одной командой
- шифрование хранилища
- отдельная настройка кластера; по умолчанию выключена
Пространства имён и порядок
Пространство имён - это отдельный отсек кластера. Объекты в нём не видят объектов другого отсека: сервис из одного пространства не найдётся по короткому имени из другого, конфигурация и секреты не подключатся через границу.
Используют их для разделения по средам, по командам или по приложениям. Заодно к ним привязывают три полезные вещи: права (кто что может делать именно тут), квоты на суммарные ресурсы отсека и пределы по умолчанию для подов без явных запросов.
// Практическая привычка: не работать в пространстве по умолчанию. Оно общее, и там быстро копится мусор, который никто не рискует удалять, потому что непонятно, чьё. Пространство под приложение или под команду решает это одним движением - удалили отсек, удалилось всё, что в нём.
- пространство имён
- отсек кластера; объекты разных отсеков не видят друг друга
- квота
- предел суммарных ресурсов, которые может занять отсек
Как отвечать: «Поменяли значение в конфигурации. Приложение подхватит его само?»
Зависит от способа подключения, и я это специально мерил на стенде. Если значение подключено файлом, то файл в поде обновляется сам - у меня это заняло 61 секунду, под никто не трогал. Но подхватит его приложение только если умеет перечитывать файл; большинство читает настройки один раз при старте. Если значение подключено переменной окружения, оно не обновится вообще: переменные читаются при запуске процесса, и поменять их можно только перезапуском пода - я проверял, значение осталось прежним. Поэтому на практике я делаю так: кладу в описание пода отпечаток конфигурации, тогда её изменение меняет описание, и кластер сам катит обновление по обычным правилам. Это надёжнее, чем надеяться, что приложение перечитает файл.
Ответ разводит два способа с измеренным поведением каждого и заканчивается приёмом, который работает независимо от приложения. Отпечаток конфигурации в описании - признак практики.
На чём валятся
- −Ждут, что переменная окружения обновится без перезапуска пода.
- −Считают секрет защищённым хранилищем: значение раскодируется одной командой.
- −Не включают шифрование хранилища кластера и не ограничивают права на чтение секретов.
- −Кладут секреты в описания, которые лежат в репозитории.
- −Работают в пространстве по умолчанию и копят там объекты без хозяина.
Проверьте себя
Пять вопросов из банка по этой подтеме. Всего их 6, остальные разбираются в тренажёре.
- Обновили ConfigMap, приложение работает со старыми значениями. Что происходит?A)ConfigMap кэшируется на ноде до перезапуска kubeletB)Изменения применяются только при следующем создании namespaceC)Переменные снимаются на старте, файл не перечитанD)Правки ConfigMap применяются лишь через rollout restart в самом объекте
показать ответ и разбор
+C)Переменные снимаются на старте, файл не перечитан// разбор: Значения, проброшенные через env, снимаются один раз при запуске контейнера и живут до его пересоздания. Смонтированный файл kubelet обновит через десятки секунд, но приложение обязано его перечитать само — большинство сервисов этого не делает. Практика: хэш конфига в аннотации шаблона пода, тогда изменение ConfigMap меняет шаблон и вызывает штатную выкатку.
- Под со свежим PVC висит в Pending, в событиях — про несовпадение топологии тома. Что произошло?A)Классу хранилища не хватило квоты, и том не созданB)PVC запросил больше места, чем есть в классе хранилищаC)Том смонтирован другим подом: режим доступа занятD)Диск создан в одной зоне, а планировщик тянет под в другую
показать ответ и разбор
+D)Диск создан в одной зоне, а планировщик тянет под в другую// разбор: Блочный том живёт в конкретной зоне доступности и монтируется только на ноду из этой зоны. Если том создан заранее (немедленная привязка), планировщик обязан искать ноду там же — при нехватке места под зависает. Лечится классом с volumeBindingMode: WaitForFirstConsumer: сначала выбирается нода, потом создаётся том рядом. Отсюда же правило не размазывать реплики базы одним PVC на несколько зон.
- ConfigMap, смонтированный как файл-том, обновился в поде без рестарта, а тот же ConfigMap через env — нет. Почему?A)Env снимается один раз на старте; том с ConfigMap kubelet обновляетB)Файловый том кэшируется, а env читается из etcd на каждый запросC)env обновился бы тоже, просто с задержкой в пару минутD)Том обновляется, только если у пода есть readiness-проба
показать ответ и разбор
+A)Env снимается один раз на старте; том с ConfigMap kubelet обновляет// разбор: Переменные окружения из ConfigMap/Secret инжектятся при старте контейнера и не меняются до рестарта. ConfigMap/Secret, смонтированный как том, kubelet освежает при изменении источника (с задержкой и кроме subPath-монтирований). Поэтому конфиг-в-томе может обновиться на месте, а env — нет. Оговорка: приложение должно перечитать файл, чтобы реально подхватить изменение.
- Пароль в Secret — «всего лишь base64». Как по-настоящему защитить его в кластере?A)Перекодировать значение из base64 в base32 для надёжностиB)Перенести пароль из Secret в ConfigMap с правами 600C)Шифрование etcd at-rest плюс RBAC на доступ к SecretD)Достаточно base64: снаружи кластера его всё равно не прочитать
показать ответ и разбор
+C)Шифрование etcd at-rest плюс RBAC на доступ к Secret// разбор: Secret лишь закодирован base64 и лежит в etcd; настоящая защита — это: шифрование etcd at-rest (EncryptionConfiguration с KMS/aescbc-провайдером), чтобы украденный снапшот не был открытым текстом; RBAC, ограничивающий, кто читает Secret'ы; отказ от коммита их в git (sealed-secrets/внешние хранилища); ограничение монтирований. base32 и перенос в ConfigMap не помогают.
- Приложение читает конфиг из смонтированного ConfigMap. Как подхватывать изменения без рестарта пода?A)Kubernetes сам перезапускает процесс в поде при смене ConfigMapB)Достаточно смонтировать ConfigMap как env вместо файлаC)Изменения подхватятся, если задать поду restartPolicy: AlwaysD)Приложение само перечитывает файл (watch/SIGHUP)
показать ответ и разбор
+D)Приложение само перечитывает файл (watch/SIGHUP)// разбор: kubelet обновляет смонтированный файл, но работающий процесс не заметит правки, пока сам не перечитает файл — через watcher (inotify), reload-эндпоинт или обработку SIGHUP. Сам Kubernetes процесс при смене ConfigMap не перезапускает; инструменты вроде Reloader могут дёрнуть rollout по изменению ConfigMap. env-конфиг замерзает на старте (хуже), а restartPolicy на правку не реагирует.
дальше
Теорию прочитали. Навык ставится повторением
В Сеньорчике эта подтема идёт в ежедневных сессиях: движок возвращает её, пока ответы не станут уверенными, и ведёт прогресс отдельно по каждой подтеме. Теория внутри тоже бесплатна, лимит только на количество вопросов в день.