Зачем выносить конфигурацию:
Образ собирается один раз. Все, что отличается между окружениями (хост базы, флаги, токены), должно приходить снаружи. В Kubernetes для этого два объекта: ConfigMap для обычных настроек и Secret для всего, что нельзя светить в логах и в git.
ConfigMap:
ConfigMap это просто набор пар ключ-значение, никакой магии:
Код: Выделить всё
# backend-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: backend-config
data:
APP_ENV: "production"
LOG_LEVEL: "info"
DB_HOST: "postgres.default.svc.cluster.local"
DB_PORT: "5432"
Все значения тут строки. Даже порт 5432 пишем в кавычках, иначе apply упадет на валидации. И ConfigMap не резиновый: лимит 1 МиБ, большие файлы туда пихать не надо.
Подключаем к Deployment:
Контейнер получает данные двумя способами: через переменные окружения или через файлы из volume. Если приложение читает env, хватит envFrom:
Код: Выделить всё
spec:
containers:
- name: backend
image: cr.yandex/myteam/backend:1.4.2
envFrom:
- configMapRef:
name: backend-config
volumeMounts:
- name: nginx-conf
mountPath: /etc/nginx/conf.d
readOnly: true
volumes:
- name: nginx-conf
configMap:
name: nginx-conf
Secret:
Secret устроен почти так же, но значения в поле data хранятся в base64. Чтобы не кодировать руками, пишите в stringData, при сохранении Kubernetes сам переложит все в data в закодированном виде:
Код: Выделить всё
apiVersion: v1
kind: Secret
metadata:
name: backend-secrets
type: Opaque
stringData:
DB_PASSWORD: "Xk29!vLm"
API_TOKEN: "tok-7f3a9c"
Ключевой момент: base64 это не шифрование, а кодирование. Любой, у кого есть права читать секреты, достанет значение одной командой:
Код: Выделить всё
kubectl get secret backend-secrets -o jsonpath='{.data.DB_PASSWORD}' | base64 -d
Типичные грабли:
Самая частая беда связана с обновлением. Поменяли ConfigMap, сделали apply, а под живет со старыми значениями. Переменные окружения читаются один раз при старте контейнера и не обновляются никогда. Файлы из volume kubelet обновит сам, обычно в течение минуты-другой, но приложение должно уметь перечитывать их без рестарта, а это умеют далеко не все. Рабочее решение для env: после изменения конфига дергать kubectl rollout restart для деплоймента. В Helm (глава 12) это автоматизируют аннотацией с хэшем конфига.
Вторая ловушка: если монтируете ключ через subPath, файл не обновится вообще, даже через час.
Третья: путаница data и stringData. Положили в data незакодированное значение, получили ошибку про illegal base64 data. Или наоборот, закодировали уже закодированное и потом полчаса дебажите неверный пароль. Правило простое: руками пишем только в stringData.
Итог:
Конфигурация теперь живет отдельно от образа: обычные настройки в ConfigMap, чувствительные в Secret, в контейнер они попадают через env или файлы. Образ один, окружений сколько угодно. В следующей главе пустим трафик снаружи через Ingress, и там Secret снова пригодится: именно в нем хранят TLS-сертификаты.