Як передати змінні середовища в контейнери Docker?


828

Я новачок у Docker, і незрозуміло, як отримати доступ до зовнішньої бази даних з контейнера. Чи найкращий спосіб жорсткого коду в рядку з'єднання?

# Dockerfile
ENV DATABASE_URL amazon:rds/connection?string

Відповіді:


1241

Ви можете передати змінні середовища у ваші контейнери із -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-файлу приймає ім'я файлу як аргумент і очікує, що кожен рядок буде у форматі VAR = VAL, імітуючи аргумент, переданий на --env. Рядки коментарів мають бути встановлені лише з #


Чи є простіший спосіб зробити це? Це дійсно дратує необхідність щоразу створювати контейнер з різними змінними. Може зберігати його у файлі?
Джейсон Аксельсон

29
Я зберігаю команди запуску докер у скриптах оболонки ((./start_staging.sh тощо). Потім виконую їх віддалено, використовуючи Ansible.
errata

1
У мене виникають проблеми з тим, щоб друга версія працювала; Я встановлюю PASSWORD = foo в оточенні, потім передаю --env PASSWORD, і в config.json контейнера відображається лише слово "PASSWORD"; кожна інша змінна середовище має ключ і значення. Я використовую Docker 1.12.1.
Кевін Берк

@KevinBurke: я думаю, ви хочете -e PASSWORD = $ PASSWORD, якщо читаєте з поточного середовища оболонки
errata

8
@KevinBurke: export PASSWORD=fooНатомість зробіть, і змінна буде передана docker runяк змінна середовище, зробивши docker run -e PASSWORDроботу.
qerub

93

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


2
Я додав ще один спосіб вирішити цю проблему до відповіді @ errata.
Брайан

21
Будьте обережні --env-file, коли ви використовуєте --envваші ENV значення будуть котируватися / уникати зі стандартною семантикою будь-якої оболонки, яку ви використовуєте, але при використанні --env-fileзначень, які ви отримаєте всередині вашого контейнера, будуть іншими. Команда run docker просто зчитує файл, робить дуже основний аналіз і передає значення в контейнер, це не еквівалентно тому, як поводиться ваша оболонка. Лише невеликий готч, про який слід знати, перетворюючи купу --envзаписів у --env-file.
Шорн

5
Щоб розробити відповідь Шорна, використовуючи env-файл, мені довелося поставити значення дуже великої змінної середовища все в одному рядку, оскільки, здається, немає способу поставити в ньому розрив рядка або розділити його на кілька рядків, таких як: $ MY_VAR = речі $ MY_VAR = $ MY_VAR більше матеріалів
Джейсон Уайт

53

Якщо ви використовуєте "docker-compose" в якості методу для спінації ваших контейнерів, насправді є корисним способом передавання змінної середовища, визначеної на вашому сервері, до контейнера Docker.

docker-compose.ymlСкажімо, у вашому файлі ви створюєте базовий контейнер hapi-js, і код виглядає так:

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

Скажімо, що локальний сервер, на якому працює ваш проект докера, має змінну середовища з назвою "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"

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


6
Це не спрацює. Ці змінні не передаються в контейнер.
Фрондор

@Frondor справді? Згідно з цими документами, здається, так і слід.
Дарда

1
Проблема такого підходу полягає в тому, що ви залучаєте змінні середовища у файлі docker-compose.yml до сховища git, чого не слід. Як ти обійдеш це? в ідеалі у вас є окремий env-файл, який буде зафіксований і може імпортувати / завантажувати в Dockerfile або docker-compose.yml
Khaled Osman

35

Використовуючи docker-compose, ви можете успадкувати env-змінні у docker-compose.yml, а згодом і будь-який Dockerfile (s), викликаний 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}

Докерфайл :

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

Чи повинні вони бути однойменними? Здається, що це заплутано. І як би я змінив аргументи, якщо замість цього я хочу запустити розробку?
CyberMew

@CyberMew Так, вони повинні бути однаковими між вашим оточенням, докер-композицією та Dockerfile. Якщо ви хочете замість цього запустити розробку, перед тим, як запустити збірку docker-compose, запустіть RAILS_ENV = development у своєму терміналі, щоб встановити змінну середовища, таким чином docker-compose і, в свою чергу, Dockerfile успадкує це значення з вашого оточення.
joshweir

30

Використовуйте -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 run --help

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


2
Навіщо нам це потрібно ubuntu bash? Чи застосовується це для зображень, створених за допомогою ubuntu як базового зображення, або до кожного зображення?
Reyansh Kharga

Я хотів би прочитати трохи про те, як поставити ім'я контейнера після -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

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 shell, оскільки 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 runкомандою . У такому випадку у вас може бути сценарій, який розшифровує змінні env, використовуючи, скажімо, KMS, і додає їх до того, env.shякий можна отримати для встановлення змінних env.
akilesh raj

ви можете використовувати команду 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 або новіша

це пустить хост env як json, по суті, як у Dockerfile:

ENV HOST_ENV  (all env from the host as json)

Як ця лінія працює для вас docker run -e HOST_ENV="$env_as_json" <image>? : ? У моєму випадку 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_') захопить це все і передасть його надійно, щоб бути доступним зсередини контейнера.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.