После изменения значения в ConfigMap переменная окружения в уже запущенном поде не изменилась. Какой механизм объясняет это поведение?
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
MODE: prod
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
spec:
selector:
matchLabels:
app: app
template:
metadata:
labels:
app: app
spec:
containers:
- name: app
image: example/app:1.0
env:
- name: MODE
valueFrom:
configMapKeyRef:
name: app-config
key: MODE
Значение ConfigMap, переданное через env, считывается при создании процесса контейнера и становится обычной переменной окружения. Изменение ConfigMap не изменяет окружение уже запущенного процесса, поэтому для применения нового значения нужно пересоздать под или иным способом перезапустить контейнер.
Вынесение конфигурации из образа позволяет собирать один неизменяемый артефакт и запускать его с разными настройками в тестовой, staging- и production-среде. ConfigMap решает задачу передачи несекретной конфигурации без пересборки контейнерного образа.
Такое разделение уменьшает связанность между кодом и окружением, но не означает автоматического обновления всех способов доставки конфигурации. Поведение зависит от того, передана ли конфигурация как переменная окружения или смонтирована как файл.
В примере Deployment получает MODE через valueFrom. После изменения ключа MODE в ConfigMap ожидается, что приложение начнёт использовать новое значение, однако работающий процесс продолжает видеть старое.
Если ошибочно считать ConfigMap динамическим источником переменных окружения, можно изменить конфигурацию в control plane, не обновив фактическое поведение приложения. Это особенно опасно для переключателей функций, адресов зависимостей и параметров совместимости.
При создании пода kubelet получает содержимое ConfigMap, формирует окружение контейнера и запускает процесс. Переменная окружения принадлежит уже запущенному процессу; Kubernetes не может изменить её внутри процесса после старта.
Чтобы применить новое значение, обычно изменяют шаблон Deployment или инициируют контролируемый рестарт подов. Частый практический приём — добавить в шаблон аннотацию с хешем конфигурации: при изменении хеша меняется PodTemplate, и Deployment выполняет rolling update.
Если конфигурация смонтирована как volume, поведение другое: kubelet обычно обновляет содержимое смонтированных файлов с некоторой задержкой. Но само приложение должно перечитать файл или поддерживать механизм отслеживания изменений; уже прочитанная конфигурация в памяти автоматически не обновится.
Важно не путать ConfigMap с Secret: ConfigMap предназначен для несекретных данных. Секреты требуют отдельного контроля доступа и безопасного обращения, но передача секрета через переменную окружения всё равно не делает его динамически изменяемым для работающего процесса.
Минимальный способ явно применить изменение — пересоздать поды Deployment:
Плюс рестарта — предсказуемое применение всей конфигурации. Минус — кратковременная нагрузка на запуск новых экземпляров и риск прерываний, если не настроены readiness-пробы, достаточная репликация и корректная стратегия обновления.
В сервисе флаг MODE передавался через ConfigMap как переменная окружения. Команда изменила значение ConfigMap во время инцидента, но часть подов продолжила работать со старым режимом, поскольку рестарт не выполнялся. В результате поведение сервиса зависело от момента запуска экземпляра.
Рассматривались три варианта. Ручной rollout restart прост, но зависит от дисциплины оператора. Передача конфигурации файлом позволяет обновлять содержимое без пересоздания пода, однако приложение должно безопасно перечитывать файл, а обновление происходит не мгновенно. Автоматический рестарт по хешу ConfigMap даёт воспроизводимый rollout, но любое изменение конфигурации вызывает перезапуск всех реплик.
Выбрали хеширование конфигурации в шаблоне Deployment и readiness-пробу, чтобы новый под получал трафик только после успешной загрузки настроек. Это устранило расхождение между репликами и сохранило контролируемое постепенное обновление.
Содержимое volume, связанного с ConfigMap, обычно синхронизируется kubelet с задержкой, поэтому файл может измениться без пересоздания пода. Однако приложение должно перечитать файл или обработать событие изменения; Kubernetes не обновляет автоматически значения, уже загруженные приложением в память.
Deployment отслеживает изменения собственного spec.template, а не произвольные изменения объектов, на которые этот шаблон ссылается. Поэтому изменение ConfigMap само по себе не меняет PodTemplate и не запускает новый rollout. Для автоматизации в шаблон добавляют хеш конфигурации либо используют внешний контроллер, который инициирует обновление.
Уже запущенный контейнер обычно продолжит использовать ранее сформированное окружение. Но новые поды, которым требуется этот ConfigMap, не смогут корректно получить конфигурацию и могут не запуститься или перейти в ошибочное состояние в зависимости от способа ссылки и поведения workload. Поэтому удаление или переименование ConfigMap следует выполнять как совместимое изменение с заранее подготовленным rollout.