← Kubernetes: конфигурация
6 мин · просто · Урок 1 из 8

Переменные окружения в Pod

Поле env в spec контейнера: литералы, valueFrom, подстановка $(VAR) и почему env не обновляется на лету.

Зачем env-переменные

12-factor app говорит простое: всё, что зависит от окружения, передавай через environment. URL базы, режим запуска, путь к ключу, секрет API. Образ остаётся одним и тем же, поведение меняется через env.

В Kubernetes за это отвечает поле spec.containers[].env у Pod. Дальше любой процесс внутри контейнера видит переменную через $DB_HOST в shell, os.environ["DB_HOST"] в python, os.Getenv("DB_HOST") в go.

Минимальная форма

spec:
  containers:
    - name: app
      image: busybox:1.36
      env:
        - name: DB_HOST
          value: postgres-internal
        - name: LOG_LEVEL
          value: debug

env это массив объектов. У каждого объекта обязательное name, дальше либо value (литерал-строка), либо valueFrom (ссылка на ConfigMap, Secret, downward API).

Имя env с дефисом apiserver не примет: MY-VAR отвалится на apply. Разрешён только шаблон [A-Za-z_][A-Za-z0-9_]*.

value всегда строка. Если нужно число или булеан, значение пишут в кавычках:

- name: REPLICAS
  value: "3"
- name: DEBUG
  value: "true"

Без кавычек YAML распарсит 3 как int, и kubectl ругнётся: v1.EnvVar.Value: ReadString: expects " or n.

valueFrom: четыре источника

valueFrom configMapKeyRef ConfigMap app-config, ключ APP_MODE secretKeyRef Secret app-secret, ключ password fieldRef downward API: metadata.name resourceFieldRef downward API: limits.cpu env в контейнере подставляется один раз на старте
Четыре разных источника, а наружу все выходят одинаковой env-переменной.

value это просто строка. valueFrom достаёт значение из другого объекта кластера. Четыре варианта:

env:
  # из ConfigMap
  - name: APP_MODE
    valueFrom:
      configMapKeyRef:
        name: app-config
        key: APP_MODE

  # из Secret
  - name: DB_PASSWORD
    valueFrom:
      secretKeyRef:
        name: app-secret
        key: password

  # из downward API: имя Pod, namespace, labels
  - name: POD_NAME
    valueFrom:
      fieldRef:
        fieldPath: metadata.name

  # из downward API: requests/limits контейнера
  - name: CPU_LIMIT
    valueFrom:
      resourceFieldRef:
        containerName: app
        resource: limits.cpu

Самая простая форма - литерал через value. ConfigMap и Secret как источники разбираются в следующих уроках трека.

Когда env читается

Один раз на старте контейнера. Если поменять Pod через kubectl edit, изменения сами не подхватятся: kubectl скажет Pod updates may not change fields other than .... У нативного Pod env-блок вообще иммутабельный после создания. Нужно удалить и пересоздать.

У Deployment пересоздание делается автоматически: меняется spec, ReplicaSet поднимает новые Pod со свежим env, старые удаляет.

Для valueFrom из ConfigMap правило то же. Если ConfigMap поменяли, env в работающем контейнере остаётся старым. Нужен rollout. Для динамики используют volume mount (там kubelet синхронит файлы периодически).

Подстановка переменных в env

Можно ссылаться на переменные, уже объявленные выше в том же массиве:

env:
  - name: HOST
    value: postgres-internal
  - name: PORT
    value: "5432"
  - name: DB_URL
    value: "postgres://$(HOST):$(PORT)/app"

Синтаксис $(VAR), не ${VAR}. Работает только для переменных, уже объявленных до текущей. Если перепутать порядок, $(HOST) останется литералом.

env, порядок элементов в массиве:

  1  HOST   = postgres-internal
  2  PORT   = 5432
  3  DB_URL = $(HOST):$(PORT)   раскрыт
  4  BAD    = $(LATER)          литерал
  5  LATER  = x

То же работает в command и args:

command: ["sh", "-c"]
args: ["echo DB=$(DB_URL); sleep 3600"]

Дополнительно shell умеет раскрывать $VAR сам, поэтому sh -c "echo $DB_HOST" тоже работает: тут уже не kubelet подставляет, а shell читает env-переменную из своего окружения.

Связанные команды

# Показать env конкретного контейнера в spec
kubectl get pod app -o jsonpath='{.spec.containers[0].env}' | jq

# Выполнить env внутри Pod и увидеть реальные значения
kubectl exec app -- env | sort

# Увидеть, что контейнер вывел при старте
kubectl logs app

# Разобрать схему полей
kubectl explain pod.spec.containers.env
kubectl explain pod.spec.containers.env.valueFrom --recursive

Что часто ломается

Домашка

Теорию закрепляет задание на своём кластере: 3 шага с проверкой. Кластер поднимается по треку Kubernetes локально, задания лежат в репозитории k8s-practice.

./run.sh start k8s-env-vars     # развернуть стартовое состояние
./run.sh verify k8s-env-vars    # проверить текущий шаг

Коротко

Прошли материал до конца? Отметьте урок пройденным.