Урок 05 · Kubernetes на практике
ConfigMap и Secret
Что-то не запустилось или осталось непонятным? Задайте вопрос в комментариях к разбору этого урока в канале — разберёмся вместе.
Образ hello-fastapi из урока 1 — один и тот же файл, неизменный после сборки. Но приветствие на проде и на тесте вы наверняка захотите разное, а ключ от внешнего API уж точно не один и тот же для всех окружений. Пересобирать образ под каждое окружение — плохая идея: вы теряете смысл слоёв и кеша сборки, о которых говорили в уроке 1. Правильный путь — вынести настройки наружу образа и подложить их уже в кластере. Для обычных настроек это ConfigMap, для чувствительных — Secret.
ConfigMap — обычные настройки
ConfigMap — это просто набор пар ключ-значение, который живёт в кластере отдельно от образа. Значения из него можно подложить в Pod несколькими способами; в этом уроке — самый простой: как переменные окружения. Приложение внутри контейнера ничего не знает про Kubernetes — оно просто читает os.environ, как читало бы их локально.
Secret — то же самое, но для чувствительного
Secret устроен буквально так же, как ConfigMap, — тот же набор ключ-значение, тот же способ подключения к Pod'у. Разница не в механике, а в договорённости: Secret — это место, куда Kubernetes и инструменты вокруг него (RBAC, аудит, сканеры) относятся строже, потому что там ожидаются пароли, токены, ключи API.
Практика: подключите настройки к сервису
Понадобится приложение из урока 1 и Deployment из урока 3.
-
Откройте
main.pyиз урока 1 и добавьте чтение переменных окружения плюс эндпоинт, который их показывает:import os GREETING = os.environ.get("GREETING", "Привет") API_KEY = os.environ.get("API_KEY") @app.get("/config") def config(): return {"greeting": GREETING, "api_key_is_set": API_KEY is not None}Обратите внимание: эндпоинт подтверждает, что ключ задан, но не возвращает его значение целиком — секреты не стоит светить даже в собственном debug-эндпоинте.
-
Пересоберите образ под новым тегом и загрузите его в minikube — так же, как в уроке 3:
docker build -t hello-fastapi:0.2 . minikube image load hello-fastapi:0.2 -
Создайте
configmap.yaml:apiVersion: v1 kind: ConfigMap metadata: name: hello-fastapi-config data: GREETING: "Привет из ConfigMap" -
Создайте
secret.yaml. ПолеstringDataпозволяет писать значение обычным текстом — Kubernetes сам закодирует его в base64 при сохранении, вручную кодировать не нужно:apiVersion: v1 kind: Secret metadata: name: hello-fastapi-secret type: Opaque stringData: API_KEY: "demo-key-12345"Это учебное значение для примера — в реальном проекте такой файл с настоящим ключом никогда не попадает в git, ровно по той же причине, по которой в
github_pages/этого курса нет ничего чувствительного. -
В
deployment.yamlиз урока 3 обновите тег образа на0.2и добавьте блокenvFromвнутрь описания контейнера:containers: - name: hello-fastapi image: hello-fastapi:0.2 ports: - containerPort: 8000 envFrom: - configMapRef: name: hello-fastapi-config - secretRef: name: hello-fastapi-secret -
Примените все три манифеста и дождитесь, пока Deployment обновится:
kubectl apply -f configmap.yaml kubectl apply -f secret.yaml kubectl apply -f deployment.yaml kubectl rollout status deployment/hello-fastapi -
Откройте сервис так же, как в уроке 4, и проверьте новый эндпоинт:
Добавьте к полученному адресуminikube service hello-fastapi --url/config— увидите{"greeting": "Привет из ConfigMap", "api_key_is_set": true}.
kubectl get secret hello-fastapi-secret -o yaml
В поле data.API_KEY — не осмысленная строка, а base64. Раскодируйте её и убедитесь, что это тот же самый текст, который вы писали в stringData, без какого-либо шифрования:
echo "<значение из data.API_KEY>" | base64 -d
secret.yaml из этого урока — учебное исключение: значение в нём фиктивное, и его можно свободно коммитить.
Проверьте себя
В чём главное отличие Secret от ConfigMap на уровне самого Kubernetes (без дополнительной настройки кластера)?
Напишите команду, которая одной строкой применит сразу три манифеста — configmap.yaml, secret.yaml и deployment.yaml:
Напишите команду, которая покажет, завершилось ли обновление Deployment'а hello-fastapi: