Конфигурация не должна быть зашита в Docker-образ. Разные окружения (dev, staging, production) требуют разных значений. K8s решает это через ConfigMap и Secret.
Почему конфиг не должен быть в образе
Если хардкодить конфиг в образ:
- Нужно пересобирать образ для каждого окружения
- Секреты попадают в историю слоёв образа
- Нет возможности обновить конфиг без пересборки
Правило: образ — неизменяемый артефакт. Конфиг и секреты — внешние зависимости, которые монтируются при запуске.
ConfigMap: несекретные данные
ConfigMap хранит несекретные настройки: URL сервисов, имена баз данных, параметры приложения.
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
DATABASE_HOST: postgres-service
DATABASE_PORT: "5432"
DATABASE_NAME: myapp
LOG_LEVEL: info
APP_ENV: production
# Применить
kubectl apply -f configmap.yaml
# Создать императивно
kubectl create configmap app-config \
--from-literal=DATABASE_HOST=postgres-service \
--from-literal=LOG_LEVEL=info
# Создать из файла
kubectl create configmap nginx-config --from-file=nginx.conf
# Просмотреть
kubectl get configmap app-config -o yaml
kubectl describe configmap app-config
Secret: секретные данные
Secret хранит чувствительные данные: пароли, API-ключи, токены. Данные хранятся в base64 (это не шифрование, а кодирование — только для JSON/YAML совместимости).
# secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: app-secrets
type: Opaque
data:
DATABASE_PASSWORD: cGFzc3dvcmQxMjM= # base64("password123")
API_KEY: c2VjcmV0LWFwaS1rZXk= # base64("secret-api-key")
JWT_SECRET: bXlzdXBlcnNlY3JldA== # base64("mysupersecret")
# Закодировать в base64
echo -n "password123" | base64
# cGFzc3dvcmQxMjM=
# Декодировать
echo "cGFzc3dvcmQxMjM=" | base64 -d
# password123
# Создать Secret императивно (более безопасно — не оставляет значений в shell history)
kubectl create secret generic app-secrets \
--from-literal=DATABASE_PASSWORD=password123 \
--from-literal=API_KEY=secret-api-key
# Просмотр (значения скрыты)
kubectl get secret app-secrets -o yaml
# data:
# DATABASE_PASSWORD: cGFzc3dvcmQxMjM=
Специальные типы Secret:
# TLS-сертификат
kubectl create secret tls tls-secret \
--cert=tls.crt \
--key=tls.key
# Docker registry credentials
kubectl create secret docker-registry registry-creds \
--docker-server=registry.example.com \
--docker-username=user \
--docker-password=pass
Монтирование как переменные окружения
# deployment-with-config.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 2
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: app
image: my-app:1.0
env:
# Из ConfigMap — конкретное значение
- name: DATABASE_HOST
valueFrom:
configMapKeyRef:
name: app-config
key: DATABASE_HOST
# Из Secret — конкретное значение
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: app-secrets
key: DATABASE_PASSWORD
# Все ключи ConfigMap сразу
envFrom:
- configMapRef:
name: app-config
- secretRef:
name: app-secrets
Монтирование как файлы (volume)
Удобно для конфигурационных файлов (nginx.conf, .env, application.yaml).
spec:
containers:
- name: app
image: nginx:1.25
volumeMounts:
- name: nginx-config
mountPath: /etc/nginx/conf.d
readOnly: true
- name: tls-certs
mountPath: /etc/ssl/certs
readOnly: true
volumes:
- name: nginx-config
configMap:
name: nginx-config-map
- name: tls-certs
secret:
secretName: tls-secret
При монтировании в директорию каждый ключ ConfigMap/Secret становится отдельным файлом.
# Внутри контейнера:
ls /etc/nginx/conf.d/
# default.conf upstream.conf
cat /etc/ssl/certs/tls.crt
# -----BEGIN CERTIFICATE-----
# ...
Обновление конфига без перезапуска
При изменении ConfigMap или Secret, смонтированных как volume, файлы обновляются автоматически (с небольшой задержкой ~1 мин). Переменные окружения (env) не обновляются — нужен рестарт пода.
# Обновить ConfigMap
kubectl edit configmap app-config
# Или через patch
kubectl patch configmap app-config \
--patch '{"data":{"LOG_LEVEL":"debug"}}'
# Принудительно перезапустить поды Deployment
kubectl rollout restart deployment/my-app
💬 Комментарии (0)
Комментариев пока нет
Станьте первым, кто поделится мнением об этой статье!