Kubernetes-эквивалент env-файла в Docker

87

Задний план:

В настоящее время мы используем Docker и Docker Compose для наших сервисов. Мы перенесли конфигурацию для различных сред в файлы, которые определяют переменные среды, считываемые приложением. Например prod.envфайл:

ENV_VAR_ONE=Something Prod
ENV_VAR_TWO=Something else Prod

и test.envфайл:

ENV_VAR_ONE=Something Test
ENV_VAR_TWO=Something else Test

Таким образом, мы можем просто использовать файл prod.envили test.envпри запуске контейнера:

docker run --env-file prod.env <image>

Затем наше приложение подбирает свою конфигурацию на основе переменных среды, определенных в prod.env.

Вопросов:

  1. Есть ли способ предоставить переменные среды из файла в Kubernetes (например, при определении пода) вместо их жесткого кодирования следующим образом:
apiVersion: v1
вид: Стручок
метаданные: 
  ярлыки: 
    контекст: docker-k8s-lab
    имя: mysql-pod
  имя: mysql-pod
спецификации: 
  контейнеры: 
    - 
      env: 
        - 
          имя: MYSQL_USER
          значение: mysql
        - 
          имя: MYSQL_PASSWORD
          значение: mysql
        - 
          имя: MYSQL_DATABASE
          значение: образец
        - 
          имя: MYSQL_ROOT_PASSWORD
          значение: supersecret
      изображение: "mysql: latest"
      имя: mysql
      порты: 
        - 
          containerPort: 3306
  1. Если это невозможно, каков предлагаемый подход?
Йохан
источник
Я тоже ищу что-то подобное. Я не хочу создавать ресурс Secretили, ConfigMapпотому что это временно и используется для тестирования. У меня ограниченные права доступа в кластере k8s. Возможно, я смогу создать Secretресурс, но я не смогу удалить его, когда он уже будет создан.
alltej

Ответы:

116

Вы можете заполнить переменные среды контейнера с помощью Secrets или ConfigMaps . Используйте секреты, если данные, с которыми вы работаете, являются конфиденциальными (например, пароли), и ConfigMaps, когда это не так.

В определении вашего Pod укажите, что контейнер должен извлекать значения из секрета:

apiVersion: v1
kind: Pod
metadata: 
  labels: 
    context: docker-k8s-lab
    name: mysql-pod
  name: mysql-pod
spec: 
  containers:
  - image: "mysql:latest"
    name: mysql
    ports: 
    - containerPort: 3306
    envFrom:
      - secretRef:
         name: mysql-secret

Обратите внимание, что этот синтаксис доступен только в Kubernetes 1.6 или новее. В более ранней версии Kubernetes вам нужно будет указать каждое значение вручную, например:

env: 
- name: MYSQL_USER
  valueFrom:
    secretKeyRef:
      name: mysql-secret
      key: MYSQL_USER

(Обратите внимание, что envв качестве значения принимайте массив)

И повторение для каждого значения.

Какой бы подход вы ни использовали, теперь вы можете определить два разных секрета: один для продакшена и один для разработчиков.

dev-secret.yaml:

apiVersion: v1
kind: Secret
metadata:
  name: mysql-secret
type: Opaque
data:
  MYSQL_USER: bXlzcWwK
  MYSQL_PASSWORD: bXlzcWwK
  MYSQL_DATABASE: c2FtcGxlCg==
  MYSQL_ROOT_PASSWORD: c3VwZXJzZWNyZXQK

prod-secret.yaml:

apiVersion: v1
kind: Secret
metadata:
  name: mysql-secret
type: Opaque
data:
  MYSQL_USER: am9obgo=
  MYSQL_PASSWORD: c2VjdXJlCg==
  MYSQL_DATABASE: cHJvZC1kYgo=
  MYSQL_ROOT_PASSWORD: cm9vdHkK

И разверните правильный секрет в правильном кластере Kubernetes:

kubectl config use-context dev
kubectl create -f dev-secret.yaml

kubectl config use-context prod
kubectl create -f prod-secret.yaml

Теперь всякий раз, когда Pod запускается, он заполняет свои переменные среды значениями, указанными в Secret.

Пиксельный слон
источник
5
Это мой текущий подход, однако у меня есть 3 разных модуля, использующих тот же список секретов, что и EnvVars. Можно ли определить их один раз и выставить на 3 модуля?
jävi
1
Не то, что я знаю о.
Pixel Elephant
2
это было бы так здорово ... похоже на выделение шаблона, чтобы поместить env vars в контейнеры. @PixelElephant
AndrewMcLagan
@ jävi Вы имеете в виду контроллеры репликации? Тем не менее, ничто не связывает карту secret / config с одним модулем / RC / Deployment. Он просто определен в манифесте, как указано выше, и может быть установлен для любого количества вещей.
aronchick
@aronchick Я думаю, они ищут эту функцию: github.com/kubernetes/kubernetes/issues/26299, которая, похоже, скоро появится. Я обновлю ответ, как только эта функция появится в выпущенной версии Kubernetes.
Pixel Elephant
36

Новое обновление для Kubernetes (v1.6) позволяет то, о чем вы просили (много лет назад).

Теперь вы можете использовать envFromэто в своем файле yaml:

  containers:
  - name: django
    image: image/name
    envFrom:
      - secretRef:
         name: prod-secrets

Если секреты разработки - это ваш секрет, вы можете создать его:

kubectl create secret generic prod-secrets --from-env-file=prod/env.txt`

Где содержимое файла txt - это пара "ключ-значение":

DB_USER=username_here
DB_PASSWORD=password_here

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

Или Дуань
источник
Вы можете поделиться документацией Kubernetes по этому поводу?
Артем Долобанко
@ArtemDolobanko Отредактировано, имейте в виду, что это все еще ново и множество документов, вы можете найти много обсуждений в трекере проблем Github, если хотите более подробную информацию.
Ор Дуан
@Or Duan, как передать номер версии образу докера с помощью env
dev-stack
что, если нам нужно смонтировать этот текстовый файл в какое-то место, и приложение автоматически создаст env оттуда,
Тара Прасад Гурунг,
2
Это должно быть --from-env-file? Использование --from-fileприводит к одному ключу (названному в честь входного файла) с содержимым файла. Использование --from-env-fileрасширяет ключи внутри файла в секрет. См. Эту документацию Google для получения дополнительной информации.
Дэвид
11

При определении пода для Kubernetes с помощью файла YAML нет прямого способа указать другой файл, содержащий переменные среды для контейнера. В проекте Kubernetes говорится, что они улучшат эту область в будущем (см. Документы Kubernetes ).

А пока я предлагаю использовать инструмент подготовки и сделать модуль YAML шаблоном. Например, при использовании Ansible ваш YAML-файл пода будет выглядеть так:

файл my-pod.yaml.template:

apiVersion: v1
kind: Pod
...
spec:
  containers:
  ...
    env:
    - name: MYSQL_ROOT_PASSWORD
      value: {{ mysql_root_pasword }}
    ...

Затем в вашем сценарии Ansible можно указать переменную в mysql_root_passwordудобном месте и заменить ее при создании ресурса, например:

файл my-playbook.yaml:

- hosts: my_hosts
  vars_files: 
  - my-env-vars-{{ deploy_to }}.yaml
  tasks:
  - name: create pod YAML from template
    template: src=my-pod.yaml.template dst=my-pod.yaml
  - name: create pod in Kubernetes
    command: kubectl create -f my-pod.yaml

файл my-env-vars-prod.yaml:

mysql_root_password: supersecret

файл my-env-vars-test.yaml:

mysql_root_password: notsosecret

Теперь вы создаете ресурс модуля, запустив, например:

ansible-playbook -e deploy=test my-playbook.yaml
Спенсер Браун
источник
4
В идеале вы должны иметь возможность определить секрет (или возможные объекты конфигурации, которые у нас будут) и внедрить их как env vars. К сожалению, эта работа еще не сделана, поэтому я голосую за это.
Тим Хокин
Если вы используете ansible, у нас есть общая роль для развертывания в kubernetes: github.com/ansibl8s/k8s-common . Тогда очень легко подготовить новые приложения, см. Примеры использования его в другом репо: github.com/ansibl8s
ant31
Я надеюсь, что мы будем делать секреты в env vars для 1.2
Пол Мори
1
Обратите внимание, что есть предложение для шаблонов: github.com/kubernetes/kubernetes/blob/master/docs/proposals/…
luebken
что мне делать, если я хочу использовать kubectl-runдля передачи 20 переменных env ??? почему тогда не сделать 12factor проще ??
Холмс
5

Это работает для меня:

файл env-secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: env-secret
type: Opaque
stringData:
  .env: |-
    APP_NAME=Laravel
    APP_ENV=local

и в deployment.yaml илиpod.yaml

spec:
  ...
        volumeMounts:
        - name: foo
          mountPath: "/var/www/html/.env"
          subPath: .env
      volumes:
      - name: foo
        secret:
          secretName: env-secret
````
Madwyatt
источник
как мне использовать env для образа докера, чтобы мне не приходилось обновлять deployment.yaml каждый раз, когда мне нужно увеличивать версию
dev-stack
0

Это старый вопрос, но у него много зрителей, поэтому я добавляю свой ответ. Лучший способ отделить конфигурацию от реализации K8s - использовать Helm. Каждый пакет Helm может иметь values.yamlфайл, и мы можем легко использовать эти значения в диаграмме Helm. Если у нас есть многокомпонентная топология, мы можем создать зонтичный пакет Helm, а пакет родительских значений также может перезаписать дочерние файлы значений.

AVarf
источник
0

Это старый вопрос, но позвольте мне описать свой ответ для будущего новичка.

Вы можете настроить configMapGenerator.

configMapGenerator:
  - name: example
    env: dev.env

и ссылайтесь на этот configMap / example в определении пода

sgsh
источник
0

Я уже 2 часа разбивал себе голову по этому поводу. Я нашел в документации очень простое решение, чтобы минимизировать мою (и, надеюсь, вашу) боль.

  • Держите env.prod, env.devкак у вас есть.

  • Используйте сценарий oneliner, чтобы импортировать их в yaml:

    kubectl create configmap my-dev-config --from-env-file=env.dev

    kubectl create configmap my-prod-config --from-env-file=env.prod

Вы можете увидеть результат (для мгновенного удовлетворения):

# You can also save this to disk
kubectl get configmap my-dev-config -o yaml

Как Rubyist, я лично считаю это решение DRYest, так как у вас есть одна точка для обслуживания (файл ENV bash, который совместим с библиотеками Python / Ruby, ..), а затем вы YAMLize его за одно выполнение.

Обратите внимание, что вам нужно содержать файл ENV в чистоте (у меня есть много комментариев, которые мешали этому сработать, поэтому пришлось добавить cat config.original | egrep -v "^#" | tee config.cleaned ), но это не меняет существенно сложность.

Все это задокументировано здесь

Риккардо
источник