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

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

# Dockerfile
ENV DATABASE_URL amazon:rds/connection?string

22 ответа

Решение

Вы можете передавать переменные окружения в ваши контейнеры с помощью -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. Строки комментариев должны быть только с префиксом #

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

Использование -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/

Если вы используете "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"

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

С помощью docker-composeприведенный ниже пример показывает, как вы можете наследовать переменные оболочки env как в docker-compose.yml, так и в любом Dockerfile(s), вызываемых docker-compose строить изображения. Я нашел это полезным, если, скажем, в DockerfileRUN Команда Мне нужно выполнить команды, специфичные для окружающей среды.

(ваша оболочка имеет 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-composebuild/up команды:

docker-compose build
docker-compose up

Мы также можем разместить переменную среды машины, используя флаг -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 внутри докера с помощью

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')

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

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

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

Проблема, с которой я столкнулся, заключалась в том, что я помещал --env-файл в конец команды

docker run -it --rm -p 8080:80 imagename --env-file ./env.list

Исправить

docker run --env-file ./env.list -it --rm -p 8080:80 imagename

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

Скажем, у вас в вашем .env вот так:

AWS_ACCESS_KEY: xxxxxxx
AWS_SECRET: xxxxxx
AWS_REGION: xxxxxx

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

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

Я рекомендую использовать файл env для упрощения организации и обслуживания.

ПРИМЕР (docker-composeинтерфейс командной строки)

      docker-compose -f docker-compose.yml --env-file ./.env up

ПРИМЕР (командная строка)

      docker run -it --name "some-ctn-name" --env-file ./.env "some-img-name:Dockerfile"

ВАЖНО :dockerCLI имеет некоторые ограничения в отношении (см. ниже) переменных окружения.

ПРОБЛЕМА: запуск Docker и переменные среды с кавычками и двойными кавычками

Как ни странно, подкоманда не принимает файлы env , отформатированные как действительные сценарии BASH («Shell»), поэтому она рассматривает окружающие кавычки и двойные кавычки как часть значения переменных среды, поэтому контейнер получит значение (в файле env , для пример)...

      SOME_ENV_VAR_A="some value a"

... как"some value a"и неsome value a. Кроме этого, у нас будут проблемы с использованием одного и того же файла env в других контекстах (включая сам BASH).

Это довольно странное поведение, поскольку файлы .env являются обычными скриптами BASH ("Shell").

Однако BASH («Shell») предлагает нам мощные функции, поэтому давайте воспользуемся ими в качестве обходного решения.

Мое решение включает в себя Dockerfile, файл env , файл сценария BASH и подкоманду () особым образом.

Стратегия состоит во внедрении ваших переменных среды с использованием другой переменной среды, установленной вrunподкоманду и используя сам контейнер для установки этих переменных.

Обходное решение

Создать Dockerfile

ПРИМЕР

      FROM python:3.10-slim-buster
WORKDIR /some-name
COPY . /some-name/
RUN apt-get -y update \
    && apt-get -y upgrade \
    [...]
ENTRYPOINT bash entrypoint.bash

Создайте файл env (файл сценария BASH) ( .env )

ПРИМЕР

      #!/bin/bash

# Some description a
SOME_ENV_VAR_A="some value a"

# Some description b
SOME_ENV_VAR_B="some value b"

# Some description c
SOME_ENV_VAR_C="some value c"
[...]

Создайте файл сценария BASH для ENTRYPOINT ( entrypoint.bash )

ПРИМЕР

      #!/bin/bash

set -a;source <(echo -n "$ENV_VARS");set +a
python main.py

Внедрение переменных среды с помощью подкоманды run

ПРИМЕР

      docker run -it --name "some-ctn-name" --env ENV_VARS="$(cat ./.env)" "some-img-name:Dockerfile"

ПЛЮС

У docker-compose этой проблемы нет, так как он использует YAML. YAML не рассматривает окружающие кавычки и двойные кавычки как часть значения переменных среды, чего нельзя сделать сdocker runподкоманда.

Спасибо!

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

docker run ubuntu env DEBUG=1 path/to/script.sh

Если у вас есть переменные среды в 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 Команда только для проверки того, что фактическая команда источника работает. Вы, вероятно, должны удалить его, когда подтвердите, что команда источника работает нормально, или переменные окружения появятся в ваших журналах докера.

Для передачи нескольких переменных среды через docker-compose файл среды также можно использовать в файле docker-compose.

      web:
 env_file:
  - web-variables.env

https://docs.docker.com/compose/environment-variables/#the-env_file-configuration-option

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

Вы можете использовать -e или --env в качестве аргумента, за которым следует формат ключ-значение.

Например:

      docker build -f file_name -e MYSQL_ROOT_PASSWORD=root

Используя 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)

Самое простое решение: просто запустите эти команды

      sudo docker container run -p 3306:3306 -e MYSQL_RANDOM_ROOT_PASSWORD=yes --name mysql -d mysql
sudo docker container logs mysql

Что там происходит?

  • Первая команда запускает контейнер MySQL со случайным паролем.
  • Вторая команда показывает журналы контейнера, где вы сможете узнать, какой случайный пароль предоставлен.

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

      docker network create todo-app
docker run -d \
     --network todo-app --network-alias mysql \
     -v todo-mysql-data:/var/lib/mysql \
     -e MYSQL_ROOT_PASSWORD=secret \
     -e MYSQL_DATABASE=todos \
     mysql:8.0
docker exec -it <mysql-container-id> mysql -u root -p
SHOW DATABASES;

Вот как я смог это решить

docker run --rm -ti -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_SESSION_TOKEN -e AWS_SECURITY_TOKEN amazon/aws-cli s3 ls

еще один пример:

export VAR1=value1
export VAR2=value2

$ docker run --env VAR1 --env VAR2 ubuntu env | grep VAR
VAR1=value1
VAR2=value2

Garnet - это сборка глобального менеджера переменных env именно для этого: https://github.com/garnet-labs/garnet-oss . У них есть специальное руководство по развертыванию Docker по адресу: https://docs.usegarnet.com/integration-guides/docker.

Существуют некоторые несоответствия документации для установки переменных среды с помощью docker run.

Интернет-справочник говорит одно:

--env , -e Установить переменные среды

Man - страница немного отличается:

-e, --env=[] Установить переменные окружения

В docker run --helpснова дает что-то другое:

-e, --env список Установить переменные окружения


Что-то, что не обязательно ясно в любой доступной документации:

Завершающий пробел после или может быть заменен на =, или в случае -eможно вообще исключить:

      $ docker run -it -ekey=value:1234 ubuntu env
key=value:1234

Уловка, которую я нашел методом проб и ошибок (и подсказки выше)...

Если вы получаете сообщение об ошибке:

неизвестный флаг: --env

Тогда вам может быть полезно использовать знак равенства с --env, Например:

      --env=key=value:1234

Разные способы запуска контейнера могут иметь разные сценарии парсинга.


Эти приемы могут быть полезны при использовании Docker в различных конфигурациях компоновки, таких как Visual Studio Code devcontainer.json, где пробелы не допускаются в runArgsмножество.

Чтобы импортировать среду в контейнеры, вы можете использоватьenv_file:в вашем файле docker-compose.yaml или вы можете скопировать.envфайл в контейнер, а затем читать с помощью расширенных библиотек.

Python-проект

Вы можете использоватьpython-dotenvупаковка:

      pip install python-dotenv

Затем в коде:

      import os
from dotenv import load_dotenv

    load_dotenv()
    SECRET_KEY = os.getenv("MY_SECRET")

Перейти проект

github.com/joho/godotenvупаковка:

      go get github.com/joho/godotenv

В вашем коде:

      package main

import (
    "github.com/joho/godotenv"
    "log"
    "os"
)

func main() {
  err := godotenv.Load()
  if err != nil {
    log.Fatal("Error loading .env file")
  }

  secretKey := os.Getenv("MY_SECRET")
}

Пример: предположим, у вас есть вариант использования для запуска контейнера базы данных MySQL, поэтому вам нужно передать следующие переменные

      docker run -dit --name db1 -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=mydb -e MYSQL_USER=jack -e MYSQL_PASSWORD=redhat mysql:5.7
Другие вопросы по тегам