如何将环境变量传递给Docker容器?


826

我是Docker的新手,目前尚不清楚如何从容器访问外部数据库。硬编码连接字符串的最佳方法是吗?

# Dockerfile
ENV DATABASE_URL amazon:rds/connection?string

Answers:


1239

您可以使用该-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 run命令存储在shell脚本中(./start_staging.sh等。),然后使用Ansible远程执行它们。
勘误表

1
我无法使第二个版本正常工作;我在环境中设置PASSWORD = foo,然后传递--env PASSWORD,只有单词“ PASSWORD”出现在容器的config.json中。每个其他环境变量都有一个键和一个值。我正在使用Docker 1.12.1。
凯文·伯克

@KevinBurke:我想您要-e PASSWORD = $ PASSWORD,如果您正在从当前的shell环境中进行读取
errata

8
@KevinBurke:export PASSWORD=foo取而代之,该变量将docker run作为环境变量传递给,使docker run -e PASSWORD工作正常。
qerub '16

93

您可以通过此处和@errata提到的命令来使用-e参数。 但是,此方法可能的缺点是您的凭据将显示在运行它的进程列表中。 为了使它更安全,你可能会写你的凭据在配置文件中,并做有提到这里。然后,您可以控制对该配置文件的访问,以便其他有权访问该计算机的人将看不到您的凭据。docker run ..

docker run--env-file


2
我在@errata的答案中添加了另一种解决此问题的方法。
布莱恩(Bryan)

21
请注意--env-file,当您使用--envenv 时,将使用所使用的任何shell的标准语义对env值进行引号/转义,但使用--env-file这些值时,将在容器内获得的值将有所不同。docker run命令仅读取文件,执行非常基本的解析并将值传递到容器,这与您的shell行为不同。如果您要将一堆--env条目转换为,则只需要注意一点--env-file
Shorn

5
为了详细说明Shorn的答案,在使用env文件时,我不得不将非常长的环境变量的值全部放在一行上,因为似乎没有任何办法在其中放入换行符或将其分成几部分多行,例如:$ MY_VAR =东西$ MY_VAR = $ MY_VAR更多东西
Jason White

52

如果您使用“ 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"

希望这有助于您避免对容器中任何文件中的数据库连接字符串进行硬编码!


6
这行不通。这些变量不会传递到容器。
Frondor

@Frondor真的吗?根据这些文档,看来应该如此。
达达

1
这种方法的问题是,您将docker-compose.yml文件中的环境变量提交给了git存储库,而您不应该这样做。您如何解决这个问题?理想情况下,您将拥有一个被gitignored的单独的环境文件,并且可以将其导入/加载到Dockerfile或docker-compose.yml中
Khaled Osman

35

使用docker-compose,您可以继承docker-compose.yml中的env变量,然后继承由调用docker-compose以构建映像的任何Dockerfile 。当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

他们必须同名吗?似乎有点令人困惑。如果要运行开发程序,我将如何覆盖args?
Cyber​​Mew

@Cyber​​Mew是的,它们在您的环境,docker-compose和Dockerfile之间必须具有相同的名称。如果要运行开发程序,则在运行docker-compose build之前,请在终端中运行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帮助:

 $ docker run --help

官方文档:https : //docs.docker.com/compose/environment-variables/


2
我们为什么需要ubuntu bash?它适用于使用ubuntu创建的图像作为基本图像还是每个图像?
Reyansh Kharga,

我希望我能读一些关于在-e争论前加入容器名称的知识!我什至无法开始理解为什么他们
要这样做了

13

有一个不错的技巧,如何将主机环境变量通过管道传递给Docker容器:

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

请非常小心地使用此技术,因为这env > env_file会将所有主机ENV变量转储到env_file并使它们在运行的容器中可访问。



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 shell(我想要bash shell,因为source它是bash命令)启动容器,获取env.sh文件(设置环境变量)并执行jar文件。

env.sh这个样子的,

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

我添加该printenv命令只是为了测试实际的源命令是否有效。当您确认source命令可以正常工作或环境变量将出现在docker日志中时,您可能应该删除它。


2
使用这种方法,每次要传递不同的/修改的环境集时,都必须重新构建docker映像。在“ docker --run --env-file ./somefile.txt”期间传递env是一种优越/动态的方法。
德米特里Shevkoplyas

2
@DmitryShevkoplyas我同意。我的用例是没有--env-filedocker run命令指定arg的选项。例如,如果您正在使用Google App Engine部署应用程序,并且在容器中运行的应用程序需要在docker容器中设置环境变量,则您无法直接设置环境变量,因为您无法控制该docker run命令。在这种情况下,您可能拥有一个脚本,该脚本使用例如KMS解密环境变量,并将其添加到env.sh可用于设置环境变量的容器中。
akilesh raj

您可以使用.常规的POSIX (点)命令sh代替source。(source与相同.
go2null19年

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 args传递时,Docker似乎并没有解析变量或子shell(${}$())。例如:A=123 docker run --rm -it -e HE="$A" ubuntu然后在那个容器内:root@947c89c79397:/# echo $HE root@947c89c79397:/# .... HE变量没有使它。
Perplexabot

0

我们还可以使用-e标志和$托管计算机环境变量:

在运行之前,需要导出(意味着设置)本地环境变量和文件,或者在使用之前

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,则可以通过以下方式在docker内部访问这些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')

0

docker run --rm -it --env-file <(bash -c 'env | grep <your env data>') 这是一种grep存储在中的数据.env并将其传递给Docker的方法,而不会不安全地存储任何内容(因此,您不能只是查看docker history和获取密钥。

假设您有许多类似的AWS内容.env

AWS_ACCESS_KEY: xxxxxxx
AWS_SECRET: xxxxxx
AWS_REGION: xxxxxx

使用``docker run --rm -it --env-file <(bash -c'env | grep AWS_')

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.