Learning Platform
Глоссарий Troubleshooting
Урок 07.01 · 18 мин
Средний
ConfigMapdatabinaryDataimmutablekubectl create configmap

ConfigMap: основы и создание

Любое приложение нужно как-то конфигурировать: URL базы, log level, feature flags, имена кластеров, пути. Запекать всё это в Docker image — анти-паттерн: один и тот же image должен работать в dev/staging/prod без пересборки. В Twelve-Factor App конфигурация хранится в окружении. В Kubernetes для этого есть ConfigMap — API-объект, который хранит ключи и значения и подключается к Pod через env-переменные или volume-файлы.

ConfigMap — для non-sensitive данных. Для паролей, ключей, токенов — Secret (отдельный объект, разбираем в следующих уроках). Снаружи они похожи, но Secret имеет дополнительные механизмы защиты (encryption at rest, более строгий RBAC, отдельные типы).


.env, env_file и приоритеты переменных в Compose

Структура ConfigMap

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  namespace: production
data:
  log_level: "debug"
  database_host: "db.production.svc.cluster.local"
  feature_flags: "new_ui=true,beta_search=false"
  app.properties: |
    server.port=8080
    server.compression.enabled=true
    spring.datasource.url=jdbc:postgresql://db:5432/app
binaryData:
  cert.pfx: bWFnaWMgbnVtYmVycyBoZXJlIGxvbA==

ConfigMap живёт в группе core API (apiVersion: v1), не в apps/v1 как Deployment. Это значит — namespaced (привязан к namespace), доступен через kubectl get cm (короткое имя cm).

Два поля для данных:

  • data — словарь string → string. Ключи — DNS subdomain (regex [a-zA-Z0-9._-]+), значения — UTF-8 строки. Если значение содержит multiline-контент или binary — используется blockstyle | или binaryData.
  • binaryData — словарь string → base64-encoded bytes. Для бинарных данных (certificates, jks-keystores, gzip-архивы). При mount как volume — kubelet декодирует base64 и кладёт raw bytes в файл.

Один ключ не может одновременно быть в data и binaryData — API server отклонит такой ConfigMap.

NOTE

ConfigMap не имеет spec секции (в отличие от Deployment, Pod, и почти всего остального в Kubernetes). Это reflection факта, что ConfigMap — это не желаемое состояние с reconcile-loop, а просто store-объект. Reconcile делает потребитель (Pod через kubelet), не controller.


Лимит размера: 1 MiB

ConfigMap хранится в etcd как одиночный объект. У etcd жёсткий лимит — --max-request-bytes (default 1.5 MiB на запрос), плюс лимит на размер value в kv-store. Поэтому Kubernetes ограничивает размер ConfigMap (data + binaryData + metadata) в 1 MiB.

API server отклонит ConfigMap больше лимита:

The ConfigMap "huge-config" is invalid: []: Too long: must have at most 1048576 bytes

Что делать с большими конфигами:

  • Разбить на несколько ConfigMap-ов и mount как разные volumes
  • Положить в Secret — у Secret такой же лимит, не поможет
  • Использовать volume другого типа: PVC с pre-baked файлом, init-container, который скачивает конфиг из S3
  • External config service: Spring Cloud Config, Consul KV, etcd как app-storage — Pod читает напрямую при старте
WARNING

В практике лимит 1 MiB не достигается случайно — он чувствуется только когда кто-то пытается хранить в ConfigMap бинарь приложения, ML-модель или огромный JSON. Для нормальных конфигов хватает с большим запасом. Но в CKAD ответ “разбить на несколько CM или использовать другой механизм” — обязательное знание.


Imperative create: kubectl create configmap

CKAD-эксперты пишут ConfigMap через kubectl create, не через YAML — это быстрее. На экзамене это критично.

# Из inline key=value пар
kubectl create configmap app-config \
  --from-literal=log_level=debug \
  --from-literal=database_host=db.example.com

# Из файла: ключ = basename файла, значение = содержимое
kubectl create configmap nginx-config --from-file=nginx.conf
# Создаст ключ "nginx.conf"

# Из файла с переименованием ключа
kubectl create configmap nginx-config --from-file=server.conf=nginx.conf
# Создаст ключ "server.conf" со значением из nginx.conf

# Из целого каталога: каждый файл = отдельный ключ
kubectl create configmap nginx-bundle --from-file=./conf.d/
# Создаст столько ключей, сколько файлов в conf.d/

# Из env-file (формат KEY=VALUE на строку, как .env)
kubectl create configmap app-env --from-env-file=app.env
# Каждая строка KEY=VALUE станет отдельным ключом в data

# Комбинируем источники
kubectl create configmap mixed \
  --from-literal=ENV=production \
  --from-file=schema.sql \
  --from-env-file=overrides.env

Все эти команды поддерживают --dry-run=client -o yaml — генерация YAML без отправки в API server:

kubectl create configmap app-config \
  --from-literal=log_level=debug \
  --dry-run=client -o yaml > app-config.yaml

Это — основной workflow на CKAD: сгенерировать YAML, отредактировать, применить через kubectl apply -f.

Источники данных в ConfigMap
--from-literalСамый простой источник. key=value передаётся прямо в командной строке. Удобно для коротких параметров.
--from-file=pathФайл с указанным путём. Ключ — basename файла (имя файла без директории). Значение — содержимое.
--from-file=key=pathФайл с переименованием. Ключ задан явно, значение — содержимое файла. Удобно когда имя файла на диске и в ConfigMap должны различаться.
--from-file=dir/Каталог целиком. Каждый файл в каталоге становится отдельным ключом. Используется для bundle конфигов: conf.d/, nginx-snippets/.
--from-env-fileФайл в формате .env (KEY=VALUE на строку). Каждая строка парсится и становится отдельным ключом в data. Игнорируются пустые строки и комментарии (# в начале).

Declarative YAML

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  namespace: production
data:
  log_level: "debug"
  app.properties: |
    server.port=8080
    server.tomcat.max-threads=200
    logging.level.root=INFO
  redis_url: "redis://cache:6379/0"

Применяется через kubectl apply -f app-config.yaml. При повторном apply Kubernetes делает merge-patch — обновляет только изменённые ключи. Удалённые из YAML ключи не удаляются автоматически из ConfigMap, если использован apply — потому что apply делает strategic merge patch без удалений. Для синхронного state нужен kubectl replace или --prune флаг.

TIP

Multiline-значения через YAML | (literal block scalar) — самый чистый способ хранить целые конфиги (nginx.conf, application.properties, JSON-документы). Сохраняется и индентация, и переводы строк. Альтернатива > (folded block scalar) превращает переводы строк в пробелы — почти никогда не нужно для конфигов.


Immutable ConfigMap (v1.21 GA)

С Kubernetes v1.21 в API ConfigMap появилось поле immutable: true:

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config-v1
data:
  log_level: "info"
immutable: true

Что это даёт:

  1. API server отклоняет любые update на такой ConfigMap. Только delete + create нового объекта.
  2. kubelet не watch-ит изменения — а это означает существенно меньшую нагрузку на API server в кластерах с тысячами Pod-ов и сотнями ConfigMap-ов.

Зачем нужно поле immutable. По умолчанию каждый kubelet, который смонтировал ConfigMap в Pod-volume, подписан на watch — чтобы получать уведомление о изменениях и обновлять файлы в volume. Если в кластере 5000 Pod-ов смонтировали один CM, это 5000 активных watch-сессий. Для статичных конфигов это лишняя работа.

# Создать immutable ConfigMap
kubectl create configmap app-config-v1 --from-literal=log_level=info
kubectl patch configmap app-config-v1 -p '{"immutable":true}'

# Попытка update — ошибка
kubectl edit configmap app-config-v1
# error: ConfigMap "app-config-v1" is invalid: data: Forbidden: field is immutable when `immutable` is set

Best practice для production: версионируйте имена ConfigMap (app-config-v1, app-config-v2, …) и ставьте immutable: true. Это даёт два бонуса:

  • kubelet работает быстрее (нет watch-нагрузки)
  • Понятная история через имена объектов: какая версия конфига в какой версии Deployment

Обновление: создать новый CM (app-config-v2), обновить ссылку в Deployment.template (что триггерит rolling update), потом удалить старый.

WARNING

immutable: true можно установить, но НЕЛЬЗЯ снять обратно. Если поставили — это навсегда для этого объекта. Хочется снять — удалить и создать заново.


Проверка и inspection

# Список ConfigMap-ов в namespace
kubectl get cm

# Детально
kubectl describe cm app-config

# Получить значение конкретного ключа
kubectl get cm app-config -o jsonpath='{.data.log_level}'

# Весь ConfigMap в YAML
kubectl get cm app-config -o yaml

# Только data часть
kubectl get cm app-config -o jsonpath='{.data}' | jq

kubectl describe cm показывает имя, метаданные, и все ключи с их значениями (с обрезкой длинных).


Проверка знанийKnowledge check
Команда `kubectl create configmap big-config --from-file=./assets/` была выполнена в каталоге, где лежит 200 файлов общим объёмом 2 MiB. Что вернёт API server, и почему?
ОтветAnswer
API server вернёт ошибку 'Too long: must have at most 1048576 bytes' и не создаст ConfigMap. Причина — лимит размера ConfigMap в 1 MiB (1048576 байт). Этот лимит идёт от etcd: ConfigMap хранится как одиночный value в etcd kv-store, у которого жёсткий лимит на размер value. Лимит проверяется на стороне API server до записи в etcd. Что делать: разбить на несколько ConfigMap (logically группированных), использовать другой механизм (PVC с pre-baked файлом, init-container скачивает из S3, external config service типа Consul KV). Размер ConfigMap при этом считается как сумма ключей + значений + metadata — поэтому накладные расходы тоже учитываются. binaryData данные хранятся в base64, что увеличивает размер в ~1.33 раза.

Проверьте понимание

Результат: 0 из 0
Прикладной
Вопрос 1 из 5. Команда `kubectl create configmap nginx-config --from-file=server.conf=./nginx.conf` была выполнена. Какой ключ появится в data ConfigMap?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 5