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

AJc*_*dez 733 environment-variables docker dockerfile

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

# Dockerfile
ENV DATABASE_URL amazon:rds/connection?string
Run Code Online (Sandbox Code Playgroud)

err*_*ata 1115

您可以使用-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
Run Code Online (Sandbox Code Playgroud)

或者,如果您不希望在命令行上显示值ps,等等,-e可以从当前环境中获取值,如果您只是在没有=:

sudo PASSWORD='foo' docker run  [...] -e PASSWORD [...]
Run Code Online (Sandbox Code Playgroud)

如果您有许多环境变量,特别是如果它们是秘密的,您可以使用env文件:

$ docker run --env-file ./env.list ubuntu bash
Run Code Online (Sandbox Code Playgroud)

--env-file标志将文件名作为参数,并期望每一行都是VAR = VAL格式,模仿传递给--env的参数.注释行只需要以#为前缀

  • 我将docker run命令存储在shell脚本(./start_staging.sh等..)中,然后使用Ansible远程执行它们. (29认同)
  • 我学到的痛苦的事情是,您应该在 docker 映像名称之前传递所有“-e”值,否则不会引发错误,并且所有变量都不会具有值! (9认同)
  • @KevinBurke:改为`导出PASSWORD = foo`,变量将作为环境变量传递给`docker run`,使`docker run -e PASSWORD`工作. (7认同)
  • 需要明确的是,命令行中的“-e”和 Dockerfile 中的“ENV”做同样的事情吗? (2认同)

Sab*_*bin 88

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

docker run--env-file

  • 小心`--env-file`,当你使用`--env`时,你的env值会被你使用的任何shell的标准语义引用/转义,但是当使用`--env-file`时你的值你将进入你的容器将是不同的.docker run命令只读取文件,执行非常基本的解析并将值传递给容器,它不等同于shell的行为方式.如果你要将一堆`--env`条目转换为`--env-file`,那么只需要注意一点. (20认同)
  • 要详细说明Shorn的答案,当使用env文件时,我不得不在一行上放置一个非常长的环境变量的值,因为似乎没有任何方法可以在其中放置换行符,或者将其划分为多行如:$ MY_VAR = stuff $ MY_VAR = $ MY_VAR更多东西 (5认同)
  • 我添加了另一种解决@ errata答案的问题的方法. (2认同)

Mar*_*dor 49

如果您使用'docker-compose'作为旋转容器的方法,实际上有一种方法可以将服务器上定义的环境变量传递给Docker容器.

在你的docker-compose.yml文件中,假设你正在启动一个基本的hapi-js容器,代码如下:

hapi_server:
  container_name: hapi_server
  image: node_image
  expose:
    - "3000"
Run Code Online (Sandbox Code Playgroud)

假设您的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"
Run Code Online (Sandbox Code Playgroud)

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

  • 这不行.这些变量不会传递给容器. (5认同)
  • 这种方法的问题是您将 docker-compose.yml 文件中的环境变量提交到 git 存储库,而您不应该这样做。你如何解决这个问题?理想情况下,您将拥有一个 gitignored 的单独 env 文件,并且可以导入/加载到 Dockerfile 或 docker-compose.yml 中 (2认同)

Mob*_*san 38

我们还可以使用-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
Run Code Online (Sandbox Code Playgroud)

通过使用此方法,您可以使用您的给定名称自动设置环境变量。就我而言,是 MG_HOST 和 MG_USER。

此外:

如果您使用 Python,则可以通过以下方式访问 Docker 内的这些环境变量:

import os

host = os.environ.get('MG_HOST')
username = os.environ.get('MG_USER')
password = os.environ.get('MG_PASS')
auth = os.environ.get('MG_AUTH')
database = os.environ.get('MG_DB')
Run Code Online (Sandbox Code Playgroud)

  • 如果有人仍然对这个“docker run”命令有问题,值得注意的是,环境变量“-e”必须位于“-t”之前,如图所示。我把我的放在图像后面,但它不起作用。 (2认同)

Vis*_*hra 25

使用-e或--env值设置环境变量(默认[]).

启动脚本的示例:

 docker run  -e myhost='localhost' -it busybox sh
Run Code Online (Sandbox Code Playgroud)

如果要从命令行使用多个环境,则在每个环境变量之前使用该-e标志.

例:

 sudo docker run -d -t -i -e NAMESPACE='staging' -e PASSWORD='foo' busybox sh
Run Code Online (Sandbox Code Playgroud)

注意:确保将容器名称放在环境变量之后,而不是之前.

如果需要设置许多变量,请使用--env-file标志

例如,

 $ docker run --env-file ./my_env ubuntu bash
Run Code Online (Sandbox Code Playgroud)

如需其他帮助,请查看Docker帮助:

 $ docker run --help
Run Code Online (Sandbox Code Playgroud)

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

  • 为什么我们需要`ubuntu bash`?它适用于使用 ubuntu 作为基础映像创建的映像还是适用于每个映像? (3认同)

jos*_*eir 25

使用docker-compose,下面的示例显示了如何在docker-compose.yml中继承shell env变量,以及依次调用docker-compose构建映像的任何Dockerfile .我发现这很有用,如果在Dockerfile RUN命令中我需要执行特定于环境的命令.

(你的shell 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}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

这样我就不需要在files或docker-compose build/ upcommands中指定环境变量:

docker-compose build
docker-compose up
Run Code Online (Sandbox Code Playgroud)


Ale*_*x T 10

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

env > env_file && docker run --env-file env_file image_name
Run Code Online (Sandbox Code Playgroud)

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


小智 8

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

假设您有大量 AWS 内容,如下所示.env

AWS_ACCESS_KEY: xxxxxxx
AWS_SECRET: xxxxxx
AWS_REGION: xxxxxx
Run Code Online (Sandbox Code Playgroud)

运行 docker withdocker run --rm -it --env-file <(bash -c 'env | grep AWS_')将抓取所有内容并安全地传递它以便可以从容器内访问。


Edu*_*cio 8

有多种方法可以将环境变量传递到容器,包括使用docker-compose(如果可能的话最好的选择)。

我建议使用env 文件以便于组织和维护。

示例(docker-composeCLI)

docker-compose -f docker-compose.yml --env-file ./.env up
Run Code Online (Sandbox Code Playgroud)

示例(dockerCLI)

docker-compose -f docker-compose.yml --env-file ./.env up
Run Code Online (Sandbox Code Playgroud)

重要提示: CLI对于环境变量(见下文)docker一些限制。

问题:Docker 运行和环境变量带有引号和双引号

奇怪的是,该docker run子命令不接受格式为有效 BASH(“Shell”)脚本的env 文件,因此它将周围的引号和双引号视为环境变量值的一部分,因此容器将获取 (在 env 文件中对于例子)...

docker run -it --name "some-ctn-name" --env-file ./.env "some-img-name:Dockerfile"
Run Code Online (Sandbox Code Playgroud)

...作为"some value a"和不some value a。除此之外,我们在其他上下文(包括 BASH 本身)中使用相同的env 文件时会遇到问题。

这是非常奇怪的行为,因为 .env 文件是常规的BASH(“Shell”)脚本

然而,BASH(“Shell”)为我们提供了强大的功能,因此让我们在解决方案中利用它来发挥我们的优势。

我的解决方案涉及一个Dockerfile、一个env 文件、一个BASH 脚本文件和特殊方式的run子命令 ( )。docker run

该策略包括使用子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
Run Code Online (Sandbox Code Playgroud)

创建 env 文件(BASH 脚本文件)( .env )

例子

SOME_ENV_VAR_A="some value a"
Run Code Online (Sandbox Code Playgroud)

为ENTRYPOINT创建 BASH 脚本文件( entrypoint.bash )

例子

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
Run Code Online (Sandbox Code Playgroud)

使用run子命令注入环境变量

例子

#!/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"
[...]
Run Code Online (Sandbox Code Playgroud)

docker -compose不存在这个问题,因为它使用 YAML。YAML 不将引号和双引号视为环境变量值的一部分,而子命令则没有这样做docker run

谢了!


aki*_*raj 6

如果你本地有环境变量env.sh并且想在容器启动时设置它,你可以尝试

COPY env.sh /env.sh
COPY <filename>.jar /<filename>.jar
ENTRYPOINT ["/bin/bash" , "-c", "source /env.sh && printenv && java -jar /<filename>.jar"]
Run Code Online (Sandbox Code Playgroud)

该命令将使用 bash shell 启动容器(我想要一个 bash shell,因为它source是 bash 命令),获取env.sh文件(设置环境变量)并执行 jar 文件。

看起来env.sh像这样,

COPY env.sh /env.sh
COPY <filename>.jar /<filename>.jar
ENTRYPOINT ["/bin/bash" , "-c", "source /env.sh && printenv && java -jar /<filename>.jar"]
Run Code Online (Sandbox Code Playgroud)

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

  • 使用这种方法,每次您想要传递不同/修改的环境集时,您都必须重建 docker 映像。在“docker --run --env-file ./somefile.txt”期间传递 envs 是优越/动态的方法。 (3认同)
  • @DmitryShevkoplyas 我同意。我的用例是没有为“docker run”命令指定“--env-file”参数的选项。例如,如果您正在使用 Google 应用程序引擎部署应用程序,并且在容器内运行的应用程序需要在 docker 容器内设置环境变量,则您没有直接方法来设置环境变量,因为您无法控制` docker run`命令。在这种情况下,您可以有一个脚本,使用 KMS 解密环境变量,并将它们添加到“env.sh”中,该脚本可用于设置环境变量。 (2认同)

san*_*mai 6

另一种方法是使用 的权力/usr/bin/env

docker run ubuntu env DEBUG=1 path/to/script.sh
Run Code Online (Sandbox Code Playgroud)


T B*_*own 6

我遇到的问题是我将 --env-file 放在命令的末尾

docker run -it --rm -p 8080:80 imagename --env-file ./env.list
Run Code Online (Sandbox Code Playgroud)

使固定

docker run --env-file ./env.list -it --rm -p 8080:80 imagename
Run Code Online (Sandbox Code Playgroud)


Dar*_*ght 6

为了通过 docker-compose 传递多个环境变量,环境文件也可以在 docker-compose 文件中使用。

web:
 env_file:
  - web-variables.env
Run Code Online (Sandbox Code Playgroud)

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


Jos*_*nke 5

对于 Amazon AWS ECS/ECR,您应该通过私有 S3 存储桶管理您的环境变量(尤其是 secrets)。请参阅博客文章如何使用 Amazon S3 和 Docker 管理基于 Amazon EC2 容器服务的应用程序的密钥

  • 或SSM参数存储 (3认同)