Как передать переменные среды в контейнеры Docker?

831

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

# Dockerfile
ENV DATABASE_URL amazon:rds/connection?string
AJcodez
источник

Ответы:

1247

Вы можете передавать переменные окружения в ваши контейнеры с -eфлагом.

Пример из скрипта запуска:

sudo docker run -d -t -i -e REDIS_NAMESPACE='staging' \ 
-e POSTGRES_ENV_POSTGRES_PASSWORD='foo' \
-e POSTGRES_ENV_POSTGRES_USER='bar' \
-e POSTGRES_ENV_DB_NAME='mysite_staging' \
-e POSTGRES_PORT_5432_TCP_ADDR='docker-db-1.hidden.us-east-1.rds.amazonaws.com' \
-e SITE_URL='staging.mysite.com' \
-p 80:80 \
--link redis:redis \  
--name container_name dockerhub_id/image_name

Или, если вы не хотите иметь значение в командной строке, где оно будет отображаться и psт. Д., -eМожете получить значение из текущей среды, если вы просто передадите его без =:

sudo PASSWORD='foo' docker run  [...] -e PASSWORD [...]

Если у вас много переменных окружения и особенно если они предназначены для секретности, вы можете использовать env-файл :

$ docker run --env-file ./env.list ubuntu bash

Флаг --env-file принимает имя файла в качестве аргумента и ожидает, что каждая строка будет в формате VAR = VAL, имитируя аргумент, передаваемый --env. Строки комментариев должны быть только с префиксом #

описки
источник
Есть ли более простой способ сделать это? Это действительно раздражает необходимость заново создавать контейнер с разными переменными. Может быть, сохранить его в файле?
Джейсон Аксельсон
29
Я храню команды запуска docker в сценариях оболочки (./start_staging.sh и т. Д.), А затем выполняю их удаленно, используя Ansible.
опечатки
1
У меня проблемы с получением второй версии для работы; Я устанавливаю ПАРОЛЬ = foo в среде, затем передаю --env ПАРОЛЬ, и только слово «ПАРОЛЬ» появляется в config.json контейнера; любая другая переменная окружения имеет ключ и значение. Я использую Docker 1.12.1.
Кевин Берк,
@KevinBurke: Я думаю, что вы хотите -e ПАРОЛЬ = $ ПАРОЛЬ, если вы читаете из текущей среды оболочки
опечатки
8
@KevinBurke: Сделайте export PASSWORD=fooвместо этого, и переменная будет передана docker runкак переменная окружения, заставляя docker run -e PASSWORDработать.
февраля
93

Вы можете передать используя -eпараметры с docker run ..командой, как упомянуто здесь и как упомянуто @errata.
Однако возможный недостаток этого подхода заключается в том, что ваши учетные данные будут отображаться в списке процессов, где вы его запускаете.
Для того, чтобы сделать его более безопасным, вы можете написать свои учетные данные в файле конфигурации и делать docker runс , --env-fileкак указано здесь . Затем вы можете контролировать доступ к этому файлу конфигурации, чтобы другие, имеющие доступ к этому компьютеру, не увидели ваши учетные данные.

Сабин
источник
2
Я добавил еще один способ решения этой проблемы в ответе @ errata.
Брайан
21
Будьте осторожны --env-file, когда вы используете --envваши значения env, они будут заключены в кавычки / экранированы со стандартной семантикой любой используемой вами оболочки, но при использовании --env-fileзначений, которые вы получите внутри вашего контейнера, все будет иначе. Команда docker run просто читает файл, выполняет базовый анализ и передает значения в контейнер, это не эквивалентно поведению вашей оболочки. Просто небольшая ошибка, которую нужно знать, если вы конвертируете кучу --envзаписей в --env-file.
Shorn
5
Чтобы уточнить ответ Shorn, при использовании env-файла мне пришлось поместить очень длинное значение переменной среды в одну строку, поскольку, похоже, нет никакого способа вставить в него разрыв строки или разделить его на несколько строк, таких как: $ MY_VAR = вещи $ MY_VAR = $ MY_VAR больше вещей
Джейсон Уайт
54

Если вы используете 'docker-compose' в качестве метода ускорения ваших контейнеров, на самом деле есть полезный способ передать переменную среды, определенную на вашем сервере, в контейнер Docker.

docker-compose.ymlДопустим, в вашем файле вы раскручиваете базовый контейнер hapi-js, а код выглядит так:

hapi_server:
  container_name: hapi_server
  image: node_image
  expose:
    - "3000"

Предположим, что на локальном сервере, на котором находится ваш проект Docker, есть переменная среды с именем 'NODE_DB_CONNECT', которую вы хотите передать в свой контейнер hapi-js, и вы хотите, чтобы его новое имя было 'HAPI_DB_CONNECT'. Затем в docker-compose.ymlфайле вы передадите локальную переменную среды в контейнер и переименуете ее так:

hapi_server:
  container_name: hapi_server
  image: node_image
  environment:
    - HAPI_DB_CONNECT=${NODE_DB_CONNECT}
  expose:
    - "3000"

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

Marquistador
источник
6
Это не сработает. Эти переменные не передаются в контейнер.
Фрондор
@ Фрондор правда? Согласно этим документам, похоже, что так и должно быть.
Дарда
1
Проблема этого подхода заключается в том, что вы фиксируете переменные среды в файле docker-compose.yml в репозитории git, чего не следует делать. Как вы обходите это? в идеале у вас должен быть отдельный env-файл, который gitignored и может импортироваться / загружаться в Dockerfile или docker-compose.yml
Халед Осман
35

Используя docker-compose, вы можете наследовать переменные env в docker-compose.yml и впоследствии любые Dockerfile (ы), вызываемые docker-composeдля создания образов. Это полезно, когда Dockerfile RUNкоманда должна выполнять команды, специфичные для среды.

(ваша оболочка RAILS_ENV=developmentуже существует в среде)

docker-compose.yml :

version: '3.1'
services:
  my-service: 
    build:
      #$RAILS_ENV is referencing the shell environment RAILS_ENV variable
      #and passing it to the Dockerfile ARG RAILS_ENV
      #the syntax below ensures that the RAILS_ENV arg will default to 
      #production if empty.
      #note that is dockerfile: is not specified it assumes file name: Dockerfile
      context: .
      args:
        - RAILS_ENV=${RAILS_ENV:-production}
    environment: 
      - RAILS_ENV=${RAILS_ENV:-production}

Dockerfile :

FROM ruby:2.3.4

#give ARG RAILS_ENV a default value = production
ARG RAILS_ENV=production

#assign the $RAILS_ENV arg to the RAILS_ENV ENV so that it can be accessed
#by the subsequent RUN call within the container
ENV RAILS_ENV $RAILS_ENV

#the subsequent RUN call accesses the RAILS_ENV ENV variable within the container
RUN if [ "$RAILS_ENV" = "production" ] ; then echo "production env"; else echo "non-production env: $RAILS_ENV"; fi

Таким образом , я не нужно указывать переменные окружения в файлах или docker-compose build/ upкоманд:

docker-compose build
docker-compose up
joshweir
источник
Должны ли они быть одинаковыми? Кажется, это немного сбивает с толку ... И как бы я переопределил аргументы, если вместо этого хочу запустить разработку?
CyberMew
@CyberMew Да, они должны быть одинаковыми между вашей средой, docker-compose и Dockerfile. Если вы хотите вместо этого запустить разработку, перед запуском сборки docker-compose запустите RAILS_ENV = development в своем терминале, чтобы установить переменную среды, таким образом docker-compose и, в свою очередь, Dockerfile унаследует это значение от вашей среды.
Джошвайр
31

Используйте -eзначение или --env для установки переменных среды (по умолчанию []).

Пример из скрипта запуска:

 docker run  -e myhost='localhost' -it busybox sh

Если вы хотите использовать несколько сред из командной строки, то перед каждой переменной среды используйте -eфлаг.

Пример:

 sudo docker run -d -t -i -e NAMESPACE='staging' -e PASSWORD='foo' busybox sh

Примечание: убедитесь, что имя контейнера указано после переменной окружения, а не до этого.

Если вам нужно установить много переменных, используйте --env-fileфлаг

Например,

 $ docker run --env-file ./my_env ubuntu bash

Для любой другой помощи, посмотрите в справку Docker:

 $ docker run --help

Официальная документация: https://docs.docker.com/compose/environment-variables/

Вишну Мишра
источник
2
Зачем нам это надо ubuntu bash? Это относится к изображениям, созданным с Ubuntu в качестве базового изображения, или к каждому изображению?
Рейанш Харга
Я хотел бы прочитать немного о введении имени контейнера после -eаргументов давным-давно! Я даже не могу понять, почему они сделали это необходимым ...
Ironchicken
13

Есть хороший способ, как передать переменные окружения хост-машины в докер-контейнер:

env > env_file && docker run --env-file env_file image_name

Используйте эту технику очень осторожно, потому env > env_fileчто в нее будут помещены ВСЕ переменные ENV хост-машины env_fileи они будут доступны в работающем контейнере.

Алекс Т
источник
5

Для Amazon AWS ECS / ECR вы должны управлять переменными среды ( особенно секретами ) с помощью частного сегмента S3. См. Сообщение в блоге « Как управлять секретами для приложений на основе сервисов контейнеров Amazon EC2 с помощью Amazon S3 и Docker» .

Джозеф Юнке
источник
Или хранилище параметров SSM
joshweir
5

Другой способ заключается в использовании полномочий /usr/bin/env:

docker run ubuntu env DEBUG=1 path/to/script.sh
sanmai
источник
2

Если у вас есть переменные окружения env.shлокально и вы хотите установить их при запуске контейнера, вы можете попробовать

COPY env.sh /env.sh
COPY <filename>.jar /<filename>.jar
ENTRYPOINT ["/bin/bash" , "-c", "source /env.sh && printenv && java -jar /<filename>.jar"]

Эта команда запускает контейнер с оболочкой bash (я хочу оболочку bash, поскольку sourceэто команда bash), получает исходный env.shфайл (который устанавливает переменные окружения) и выполняет файл jar.

На env.shвнешнем виде , как это,

#!/bin/bash
export FOO="BAR"
export DB_NAME="DATABASE_NAME"

Я добавил printenvкоманду только для проверки того, что фактическая команда источника работает. Вы, вероятно, должны удалить его, когда подтвердите, что команда источника работает нормально, или переменные окружения появятся в ваших журналах докера.

Акилеш Радж
источник
2
При таком подходе вам придется перестраивать свой образ докера каждый раз, когда вы хотите передать другой / измененный набор env. Передача envs во время «docker --run --env-file ./somefile.txt» является превосходным / динамическим подходом.
Дмитрий Шевкопляс
2
@DmitryShevkoplyas Я согласен. Мой вариант использования, где нет возможности указать --env-filearg для docker runкоманды. Например, если вы развертываете приложение с использованием механизма приложений Google, а приложению, работающему внутри контейнера, требуются переменные среды, установленные внутри контейнера Docker, у вас нет прямого подхода для установки переменных среды, поскольку вы не можете контролировать docker runкоманду , В таком случае у вас может быть сценарий, который расшифровывает переменные env с помощью, скажем, KMS и добавляет их к тому, env.shкоторый можно получить для установки переменных env.
Акилеш Радж
Вы можете использовать команду POSIX .(точка), доступную в обычном, shвместо source. (так sourceже, как .)
go2null
1

Используя jq для конвертации env в JSON:

env_as_json=`jq -c -n env`
docker run -e HOST_ENV="$env_as_json" <image>

это требует JQ версии 1.6 или новее

это pust хост env как json, по сути, так в Dockerfile:

ENV HOST_ENV  (all env from the host as json)
Александр Миллс
источник
Как эта линия работает для вас docker run -e HOST_ENV="$env_as_json" <image>? : ? В моем случае Docker, по-видимому, не разрешает переменные или подоболочки ( ${}или $()) при передаче в качестве аргументов docker. Например: A=123 docker run --rm -it -e HE="$A" ubuntuзатем внутри этого контейнера: root@947c89c79397:/# echo $HE root@947c89c79397:/# .... HEПеременная не делает это.
Perplexabot
0

мы также можем разместить переменную окружения компьютера, используя флаг -e и $:

Перед запуском нужно экспортировать (значит установить) локальную переменную env и файл или просто перед использованием

docker run -it -e MG_HOST=$MG_HOST -e MG_USER=$MG_USER -e MG_PASS=$MG_PASS -e MG_AUTH=$MG_AUTH -e MG_DB=$MG_DB -t image_tag_name_and_version 

Используя этот метод, установите переменную env автоматически с вашим именем в моем случае (MG_HOST, MG_USER)

Дополнительно:

Если вы используете python, вы можете получить доступ к этим переменным envment в Docker с помощью

import os
host,username,password,auth,database=os.environ.get('MG_HOST'),os.environ.get('MG_USER'),os.environ.get('MG_PASS'),os.environ.get('MG_AUTH'),os.environ.get('MG_DB')
Мобин Альхассан
источник
0

docker run --rm -it --env-file <(bash -c 'env | grep <your env data>') Это способ получить данные, хранящиеся в a, .envи передать их в Docker, при этом ничего не хранится небезопасно (так что вы не можете просто смотреть docker historyи брать ключи).

Скажем, у вас есть куча вещей от AWS, .envвот так:

AWS_ACCESS_KEY: xxxxxxx
AWS_SECRET: xxxxxx
AWS_REGION: xxxxxx

запуск docker с `` `docker run --rm -it --env-file <(bash -c 'env | grep AWS_') соберет все это и безопасно передаст, чтобы получить доступ из контейнера.

MadDanWithABox
источник