Настройка приложений с помощью секретов (Secrets)

KubernetesBeginner
Практиковаться сейчас

Введение

Приложениям часто требуются данные, которые не следует размещать непосредственно в образе контейнера или в обычном манифесте, например, пароли, токены или учетные данные для доступа к базам данных. Kubernetes Secrets хранят такие конфиденциальные параметры конфигурации как отдельные объекты и позволяют подам использовать их при запуске.

В этой лабораторной работе вы создадите секрет, внимательно изучите его закодированные данные, подключите его к поду приложения, обновите секрет и пересоздадите под, чтобы приложение считало новые значения. Эта работа сфокусирована на базовом рабочем процессе работы с секретами. В последующих лабораторных работах будут рассмотрены более детальные способы передачи данных через переменные окружения и монтирование конфигурационных файлов.

Подготовка пространства имен для работы с секретами

На этом этапе вы подготовите чистое пространство имен (namespace) для практики работы с секретами.

Начните работу в директории /home/labex/project. В этой директории вы создадите манифест пода.

mkdir -p /home/labex/project
cd /home/labex/project

Убедитесь, что API-сервер Kubernetes доступен. Если виртуальная машина только что запустилась и узел еще не готов, подождите несколько секунд и повторите команду.

kubectl get nodes --request-timeout=5s

Ожидаемый вывод:

NAME         STATUS   ROLES           AGE   VERSION
labex-v135   Ready    control-plane   ...   v1.35...

Дождитесь готовности пода сетевого плагина кластера перед созданием объектов приложения.

kubectl wait --namespace kube-system --for=condition=Ready pod -l k8s-app=calico-node --timeout=120s

Ожидаемый вывод:

pod/calico-node-... condition met

Создайте пространство имен с именем ckad-prep-secrets:

kubectl create namespace ckad-prep-secrets

Установите это пространство имен в качестве текущего контекста:

kubectl config set-context --current --namespace=ckad-prep-secrets

Проверьте текущее пространство имен:

kubectl config view --minify --output 'jsonpath={..namespace}'; echo

Ожидаемый вывод:

ckad-prep-secrets

Создание и проверка секрета

На этом этапе вы создадите секрет, в котором будут храниться настройки подключения к базе данных для небольшого приложения.

Команда kubectl create secret generic создает непрозрачный (opaque) секрет. generic означает, что Kubernetes не присваивает ключам какое-либо специальное встроенное значение. Каждый флаг --from-literal добавляет одну пару «ключ-значение» в секрет.

kubectl create secret generic db-credentials \
  --from-literal=DB_USER=orders-app \
  --from-literal=DB_PASSWORD=dev-password-123 \
  --from-literal=DB_NAME=orders

Ожидаемый вывод:

secret/db-credentials created

Проверьте сводную информацию о секрете:

kubectl get secret db-credentials

Ожидаемый вывод:

NAME             TYPE     DATA   AGE
db-credentials   Opaque   3      ...

Просмотрите секрет в формате YAML. Kubernetes хранит значения в поле data в виде строк, закодированных в base64, поэтому не стоит ожидать, что вы увидите исходный пароль в этом выводе.

kubectl get secret db-credentials -o yaml

Ожидаемый вывод включает:

data:
  DB_NAME: b3JkZXJz
  DB_PASSWORD: ...
  DB_USER: b3JkZXJzLWFwcA==
type: Opaque

Кодировка Base64 — это не шифрование. Любой, кто может прочитать объект Secret, может декодировать его значения. Декодируйте здесь только имя пользователя, чтобы увидеть, как работает представление данных, не выводя при этом пароль.

kubectl get secret db-credentials -o 'jsonpath={.data.DB_USER}' | base64 --decode; echo

Ожидаемый вывод:

orders-app

Настройка пода с использованием секрета

На этом этапе вы запустите под, который считывает секрет в виде переменных окружения.

Поле envFrom.secretRef импортирует все ключи из секрета в окружение контейнера. Это похоже на шаблон с ConfigMap из предыдущей лабораторной работы, но значения берутся из объекта Secret. Команда в этом поде выводит имя пользователя и имя базы данных, а затем просто подтверждает, что пароль был загружен. Сам пароль при этом не выводится.

Создайте файл secret-reader-pod.yaml:

cat > secret-reader-pod.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
  name: secret-reader
  labels:
    app: secret-reader
spec:
  terminationGracePeriodSeconds: 0
  containers:
  - name: reader
    image: busybox:1.36
    command:
    - /bin/sh
    - -c
    - 'echo user=${DB_USER}; echo database=${DB_NAME}; if [ -n "${DB_PASSWORD}" ]; then echo password-loaded; fi; sleep 3600'
    envFrom:
    - secretRef:
        name: db-credentials
EOF

Примените манифест пода:

kubectl apply -f secret-reader-pod.yaml

Ожидаемый вывод:

pod/secret-reader created

Дождитесь готовности пода:

kubectl wait --for=condition=Ready pod/secret-reader --timeout=120s

Ожидаемый вывод:

pod/secret-reader condition met

Прочитайте логи пода. Приложение подтверждает, что значения из секрета были доступны, но значение пароля не отображается.

kubectl logs secret-reader -c reader

Ожидаемый вывод:

user=orders-app
database=orders
password-loaded

Обновление секрета и пересоздание пода

На этом этапе вы обновите секрет и пересоздадите под, чтобы контейнер получил новые значения.

Окружение контейнера фиксируется в момент его запуска. Если секрет используется в качестве переменных окружения, обновление объекта Secret не приведет к перезаписи окружения внутри уже запущенного контейнера. Запустите новый под, когда приложению необходимо считать обновленные значения секрета.

Обновите секрет с помощью нового пользователя приложения и пароля:

kubectl patch secret db-credentials --type merge --patch '{"stringData":{"DB_USER":"orders-worker","DB_PASSWORD":"rotated-password-456","DB_NAME":"orders"}}'

Ожидаемый вывод:

secret/db-credentials patched

Подтвердите обновление имени пользователя, декодировав только DB_USER:

kubectl get secret db-credentials -o 'jsonpath={.data.DB_USER}' | base64 --decode; echo

Ожидаемый вывод:

orders-worker

Удалите старый под:

kubectl delete pod secret-reader

Ожидаемый вывод включает:

pod "secret-reader" deleted

Пересоздайте под из того же манифеста и дождитесь его готовности:

kubectl apply -f secret-reader-pod.yaml
kubectl wait --for=condition=Ready pod/secret-reader --timeout=120s

Ожидаемый вывод:

pod/secret-reader created
pod/secret-reader condition met

Снова прочитайте логи. Новый под теперь видит обновленного пользователя из секрета и по-прежнему не выводит пароль в открытом виде.

kubectl logs secret-reader -c reader

Ожидаемый вывод:

user=orders-worker
database=orders
password-loaded

Резюме

Вы создали секрет Kubernetes, изучили его закодированные данные, декодировали неконфиденциальный ключ, чтобы понять принцип представления данных, подключили секрет к поду приложения и пересоздали под после обновления секрета. Вы также закрепили важную привычку при работе с конфиденциальными данными: проверять, что приложение получило пароль, не выводя само значение пароля в логи.