如何在docker compose中使用环境变量

Dmi*_*y z 177 docker docker-compose

我希望能够在docker-compose.yml中使用env变量,并在docker-compose时传入值.这是一个例子.今天我正在使用基本的docker run命令执行此操作,该命令包含在我自己的脚本中.有没有办法用compose实现它,没有任何这样的bash包装器?

proxy:
  hostname: $hostname
  volumes:
    - /mnt/data/logs/$hostname:/logs
    - /mnt/data/$hostname:/data
Run Code Online (Sandbox Code Playgroud)

mod*_*tos 219

DOCKER解决方案:

看起来像docker-compose 1.5+已启用变量替换:https://github.com/docker/compose/releases

最新的Docker Compose允许您从撰写文件中访问环境变量.因此,您可以获取环境变量,然后运行Compose,如下所示:

set -a
source .my-env
docker-compose up -d
Run Code Online (Sandbox Code Playgroud)

然后你可以使用$ {VARIABLE}在docker-compose.yml中引用变量,如下所示:

db:
  image: "postgres:${POSTGRES_VERSION}"
Run Code Online (Sandbox Code Playgroud)

以下是文档中的更多信息,请点击此处:https://docs.docker.com/compose/compose-file/#variable-substitution

使用此配置运行docker-compose时,Compose会在shell中查找POSTGRES_VERSION环境变量并将其值替换为.对于此示例,Compose会在运行配置之前将映像解析为postgres:9.3.

如果未设置环境变量,则使用空字符串Compose替换.在上面的示例中,如果未设置POSTGRES_VERSION,则image选项的值为postgres:.

支持$ VARIABLE和$ {VARIABLE}语法.不支持扩展的shell样式功能,例如$ {VARIABLE-default}和$ {VARIABLE/foo/bar}.

如果需要在配置值中放置文字美元符号,请使用双美元符号($$).

我相信此拉取请求中添加了此功能: https //github.com/docker/compose/pull/1765

BASH解决方案:

我注意到人们对Docker的环境变量支持存在问题.而不是在Docker中处理环境变量,让我们回到基础,比如bash!这是一个使用bash脚本和.env文件的更灵活的方法.

一个示例.env文件:

EXAMPLE_URL=http://example.com
# Note that the variable below is commented out and will not be used:
# EXAMPLE_URL=http://example2.com 
SECRET_KEY=ABDFWEDFSADFWWEFSFSDFM

# You can even define the compose file in an env variable like so:
COMPOSE_CONFIG=my-compose-file.yml
# You can define other compose files, and just comment them out
# when not needed:
# COMPOSE_CONFIG=another-compose-file.yml
Run Code Online (Sandbox Code Playgroud)

然后在同一目录中运行此bash脚本,该目录应正确部署所有内容:

#!/bin/bash

docker rm -f `docker ps -aq -f name=myproject_*`
set -a
source .env
cat ${COMPOSE_CONFIG} | envsubst | docker-compose -f - -p "myproject" up -d
Run Code Online (Sandbox Code Playgroud)

只需使用通常的bash语法引用你的compose文件中的env变量(即从文件中${SECRET_KEY}插入).SECRET_KEY.env

请注意,COMPOSE_CONFIG在我的定义.env文件,并在我的bash脚本中使用,但你可以很容易地只需更换{$COMPOSE_CONFIG}my-compose-file.yml在bash脚本.

另请注意,我通过使用"myproject"前缀命名所有容器来标记此部署.您可以使用任何您想要的名称,但它有助于识别您的容器,以便您以后轻松引用它们.假设您的容器是无状态的,就像它们应该的那样,此脚本将根据您的.env文件参数和您的撰写YAML文件快速删除和重新部署容器.

更新 由于这个答案看起来很流行,我写了一篇博文,更深入地描述了我的Docker部署工作流程:http://lukeswart.net/2016/03/lets-deploy-part-1/当你添加时这可能会有所帮助部署配置的复杂性更高,例如nginx配置,LetsEncrypt证书和链接容器.

  • PSA:这个**只适用于`docker-compose up`**而不适用于`docker-compose run`. (8认同)
  • 有一个解决方案https://docs.docker.com/compose/compose-file/#envfile,我在`env_file`下的`.env`中添加环境变量.然后你可以使用`$ {VARIABLE}`引用`docker-compose.yml`中的变量 (4认同)
  • 你可以简单地`grep foo file.text`而不是`cat file.text | grep foo` 在我的情况下,我不得不`导出$(grep"^ [^#]".config | xargs)&& cat docker-compose.yml | envsubst`. (2认同)
  • 这个答案已经过时了。您不再需要 SOURCE 环境脚本。docker-compose 会为你做这件事。https://docs.docker.com/compose/environment-variables/#substitute-environment-variables-in-compose-files (2认同)

Sau*_*mar 81

  1. 创建一个template.yml,这是您docker-compose.yml的环境变量.
  2. 假设您的环境变量位于文件'env.sh'中
  3. 将下面的代码放在sh文件中并运行它.

source env.sh; rm -rf docker-compose.yml; envsubst <"template.yml">"docker-compose.yml";

docker-compose.yml将使用正确的环境变量值生成新文件.

示例template.yml文件:

oracledb:
        image: ${ORACLE_DB_IMAGE}
        privileged: true
        cpuset: "0"
        ports:
                - "${ORACLE_DB_PORT}:${ORACLE_DB_PORT}"
        command: /bin/sh -c "chmod 777 /tmp/start; /tmp/start"
        container_name: ${ORACLE_DB_CONTAINER_NAME}
Run Code Online (Sandbox Code Playgroud)

示例env.sh文件:

#!/bin/bash 
export ORACLE_DB_IMAGE=<image-name> 
export ORACLE_DB_PORT=<port to be exposed> 
export ORACLE_DB_CONTAINER_NAME=ORACLE_DB_SERVER
Run Code Online (Sandbox Code Playgroud)

  • 为什么你会递归删除一个文件?(rm -rf docker-compose.yml) (10认同)
  • 目前仍然没有更好的解决方案? (6认同)
  • -1此解决方案仅使事情复杂化,应根据docker-compose新功能https://docs.docker.com/compose/environment-variables/#substitute-environment-variables-in-compose-files进行更新 (4认同)
  • 我建议在括号内使用上面的命令,这样即使变量也不会被全局设置。前任。`(source env.sh; rm -rf docker-compose.yml; envsubst &lt; "template.yml"&gt; "docker-compose.yml";)` (2认同)
  • 这个答案已经过时了。 (2认同)

Doo*_*y P 77

看来docker-compose现在支持文件中的默认环境变量.

您需要做的就是在名为的文件中声明您的变量.env,它们将在docker-compose.yml中可用.

例如,对于.env包含内容的文件:

MY_SECRET_KEY=SOME_SECRET
IMAGE_NAME=docker_image
Run Code Online (Sandbox Code Playgroud)

您可以在内部访问变量docker-compose.yml或将它们转发到容器中:

my-service:
  image: ${IMAGE_NAME}
  environment:
    MY_SECRET_KEY: ${MY_SECRET_KEY}
Run Code Online (Sandbox Code Playgroud)

  • *.env* 用于解析到 *docker-compose.yml* 解释器中的变量,而不是用于容器。对于要在容器中设置的变量,您需要使用 `env_file: .env.vars` 或包含变量的任何文件名在 *docker-compose.yml* 中指定 *.env* 文件。使用 `env_file: .env` 是一种令人困惑的反模式,它可以工作,但基本上同时使用解释器和容器的变量。 (11认同)
  • 这是最好的解决方案! (4认同)
  • @HBat,您可以使用“env_file”,例如:“env_file: config.env” (4认同)
  • 这也为我工作。我不知道为什么,但是文件名实际上应该是.env,例如config.env对我不起作用。 (3认同)
  • 最好的解决方案。我们可以添加/ etc / environment属性,并通过.env将其用作环境。这样会更安全。 (2认同)
  • @bkis这是一种反模式,因为尽管看起来更容易和/或足够,但正确使用需要不明显或没有充分记录的知识,并且可能导致混乱(很少有人知道实际上有单独的文件用于 yaml 解析以及构建部分,直到遇到问题)。还有安全问题;允许不再需要的变量保留到最终的构建映像/容器通常是不好的做法。 (2认同)

Ped*_*ram 75

不要混淆.env文件和env_file选项!

\n

他们的目的完全不同!

\n

.env文件仅将这些环境变量提供给Docker Compose文件,而该文件也可以传递给容器。

\n

但该env_file选项仅将这些变量传递给容器,而不是Docker Compose 文件 \xe2\x80\x8d

\n

关于秘密的重要说明

\n

该示例使用环境变量将秘密凭据传递到 Docker Compose 文件。有一种更好的加密且安全的方法来执行此操作,官方文档中有详细解释:How to use Secrets in Docker Compose

\n

例子

\n
    \n
  1. 好的,假设我们有这个简单的撰写文件:

    \n
    services:\n  foo:\n    image: ubuntu\n    hostname: suchHostname # <-------------- hard coded \'suchHostname\'\n    volumes:\n      - /mnt/data/logs/muchLogs:/logs # <--- hard coded \'muchLogs\'\n      - /mnt/data/soBig:/data # <----------- hard coded \'soBig\'\n
    Run Code Online (Sandbox Code Playgroud)\n
  2. \n
  3. 我们不想再对这些进行硬编码!因此,我们可以将它们放入当前终端的环境变量中并检查是否docker-compose理解它们:

    \n
    $ export the_hostname="suchHostName"\n$ export dir_logs="muchLogs"\n$ export dir_data="soBig"\n
    Run Code Online (Sandbox Code Playgroud)\n
  4. \n
  5. 并将docker-compose.yml文件更改为:

    \n
    services:\n  foo:\n    image: ubuntu\n    hostname: $the_hostname # <-------------- use $the_hostname\n    volumes:\n      - /mnt/data/logs/$dir_logs:/logs # <--- use $dir_logs\n      - /mnt/data/$dir_data:/data # <-------- usr $dir_data\n
    Run Code Online (Sandbox Code Playgroud)\n
  6. \n
  7. 现在让我们检查一下它是否适用于执行docker-compose config和检查输出:

    \n
    name: tmp\nservices:\n  foo:\n    hostname: suchHostName # <------------- $the_hostname\n    image: ubuntu\n    networks:\n      default: null\n    volumes:\n    - type: bind\n      source: /mnt/data/logs/muchLogs # <-- $dir_logs\n      target: /logs\n      bind:\n        create_host_path: true\n    - type: bind\n      source: /mnt/data/soBig # <---------- $dir_data\n      target: /data\n      bind:\n        create_host_path: true\nnetworks:\n  default:\n    name: tmp_default\n
    Run Code Online (Sandbox Code Playgroud)\n
  8. \n
  9. 好的,可以了!但让我们改用该.env文件。由于Docker Compose可以识别该.env文件,因此我们只需创建一个文件并进行设置:

    \n
    # .env file (in the same directory as \'docker-compose.yml\')\nthe_hostname="suchHostName"\ndir_logs="muchLogs"\ndir_data="soBig"\n
    Run Code Online (Sandbox Code Playgroud)\n

    好的,您可以使用终端对其进行测试(这样我们设置的旧环境变量就export不会干扰并确保一切都在干净的终端中正常工作)只需再次执行步骤 4 即可看到它是否有效!

    \n
  10. \n
\n

到目前为止一切顺利但是,当您偶然发现该env_file选项时,它会变得令人困惑假设您想要将密码传递给Docker Compose文件(而不是容器)。

\n

如果采用错误的方法,您可能会将密码放入.secrets文件中:

\n
# .secrets\nsomepassword="0P3N$3$@M!"\n
Run Code Online (Sandbox Code Playgroud)\n

然后更新 Docker Compose 文件,如下所示:

\n
services:\n  foo:\n    image: ubuntu\n    hostname: $the_hostname\n    volumes:\n      - /mnt/data/logs/$dir_logs:/logs\n      - /mnt/data/$dir_data:/data\n\n    #  BAD:\n    env_file:\n      - .env\n      - .secrets\n    entrypoint: echo "Hush! This is a secret \'$somepassword\'"\n
Run Code Online (Sandbox Code Playgroud)\n

现在再次像步骤 4 一样检查将导致:

\n
WARN[0000] The "somepassword" variable is not set. Defaulting to a blank string.\nname: tmp                       #       ^\nservices:                       #       |\n  foo:                          #       |\n    entrypoint:                 #       |\n    - echo                      #       |\n    - Hush! This is a secret \'\' # <---- \xe2\x80\x8d Oh no!\n    environment:\n      dir_data: soBig\n      dir_logs: muchLogs\n      somepassword: 0P3N$$3$$@M! # <---  Huh?!\n      the_hostname: suchHostName\n    hostname: suchHostName\n    image: ubuntu\n    networks:\n      default: null\n    volumes:\n    - type: bind\n      source: /mnt/data/logs/muchLogs\n      target: /logs\n      bind:\n        create_host_path: true\n    - type: bind\n      source: /mnt/data/soBig\n      target: /data\n      bind:\n        create_host_path: true\nnetworks:\n  default:\n    name: tmp_default\n
Run Code Online (Sandbox Code Playgroud)\n

正如您所看到的,该$somepassord变量仅传递给容器,而不传递给 Docker Compose 文件。

\n
包起来
\n

您可以通过两种方式将环境变量传递给 Docker Compose 文件:

\n
    \n
  1. 通过在运行 docker compose 之前将变量导出到终端。
  2. \n
  3. 通过将变量放入.env文件中。
  4. \n
\n

env_file选项仅将这些额外的变量传递给容器 而不是撰写文件

\n

有用的链接

\n\n

  • 标题非常具有解释性,应该是每个使用 Docker 的开发人员的基础知识。直到现在这还不适合我 (7认同)

Ner*_*mas 18

为所需的卷使用环境变量时:

  1. 在包含 文件的同一文件夹中创建.envdocker-compose.yaml文件

  2. .env文件中声明变量:

    HOSTNAME=your_hostname
    
    Run Code Online (Sandbox Code Playgroud)
  3. 更改$hostname${HOSTNAME}docker-compose.yaml 文件

    proxy:
      hostname: ${HOSTNAME}
      volumes:
        - /mnt/data/logs/${HOSTNAME}:/logs
        - /mnt/data/${HOSTNAME}:/data
    
    Run Code Online (Sandbox Code Playgroud)

当然,您可以在每个构建上动态地执行此操作,如:

echo "HOSTNAME=your_hostname" > .env && sudo docker-compose up
Run Code Online (Sandbox Code Playgroud)

  • 请注意,根据文档:`.env文件功能仅在使用docker-compose up命令时起作用,并且不适用于docker stack deploy. (9认同)
  • @Joe,可以说这个评论救了我的命。无法弄清楚为什么 .env 文件被忽略。 (2认同)

Gaj*_*mbi 13

以下内容适用于docker-compose 3.x在容器内设置环境变量

方法-1 直接方法

web:
  environment:
    - DEBUG=1
      POSTGRES_PASSWORD: 'postgres'
      POSTGRES_USER: 'postgres'
Run Code Online (Sandbox Code Playgroud)

方法-2 “ .env”文件

在与docker-compose.yml相同的位置创建一个.env文件

$ cat .env
TAG=v1.5
POSTGRES_PASSWORD: 'postgres'
Run Code Online (Sandbox Code Playgroud)

您的撰写文件将像

$ cat docker-compose.yml
version: '3'
services:
  web:
    image: "webapp:${TAG}"
    postgres_password: "${POSTGRES_PASSWORD}"
Run Code Online (Sandbox Code Playgroud)

资源

  • 我想看看方法 1 的完整示例。我无法完成这项工作,因此最终使用了 .env 文件(工作正常)。 (2认同)
  • 变量赋值方法`-DEBUG=1`和`DEBUG:1`有什么区别? (2认同)

Jib*_*mes 12

最好的方法是在docker-compose.yml文件外指定环境变量.您可以使用env_file设置,并在同一行中定义您的环境文件.然后再做一个docker-compose up应该用新的环境变量重新创建容器.

这是我的docker-compose.yml的样子:

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

注意:docker-compose期望env文件中的每一行都采用VAR=VAL格式.避免export.env文件中使用.此外,该.env文件应放在执行docker-compose命令的文件夹中.

  • 确实是最好的方法 (7认同)
  • 不。它不会自动使环境变量在 docker 容器内可用。您仍然需要在环境部分明确提及这些。 (5认同)

Gal*_*ses 8

要添加环境变量,您可以将env_file(我们称之为var.env)定义为:

\n
ENV_A=A\nENV_B=B\n
Run Code Online (Sandbox Code Playgroud)\n

并将其添加到 docker compose 清单服务中。此外,您可以直接使用 定义环境变量environment

\n

例如,在docker-compose.yaml

\n
version: \'3.8\'\nservices:\n  myservice:\n    build:\n      context: .\n      dockerfile: ./docker/Dockerfile.myservice\n    image: myself/myservice\n    env_file:\n     - ./var.env\n    environment:\n     - VAR_C=C\n     - VAR_D=D\n    volumes:\n     - $HOME/myfolder:/myfolder\n    ports:\n     - "5000:5000"\n
Run Code Online (Sandbox Code Playgroud)\n

请在此处查看更多/更新信息:手册 \xe2\x86\x92 Docker \xe2\x86\x92Compose \xe2\x86\x92环境变量 \xe2\x86\x92 概述\n

\n


pap*_*lon 7

从 1.25.4 开始,docker-compose 支持--env-file允许您指定包含变量的文件的选项。

你的应该是这样的:

hostname=my-host-name
Run Code Online (Sandbox Code Playgroud)

和命令:

docker-compose --env-file /path/to/my-env-file config
Run Code Online (Sandbox Code Playgroud)


Tho*_*aux 6

你还不能...... 但这是一个替代方案,像docker-composer.yml生成器一样思考:

https://gist.github.com/Vad1mo/9ab63f28239515d4dafd

基本上是一个替换变量的shell脚本.您还可以使用Grunt任务在CI过程结束时构建docker compose文件.


Ant*_*ton 5

我为此创建了一个简单的 bash 脚本,这意味着在使用之前在您的文件上运行它: https: //github.com/antonosmond/subber

基本上只需使用双花括号来创建您的撰写文件来表示环境变量,例如:

app:
    build: "{{APP_PATH}}"
ports:
    - "{{APP_PORT_MAP}}"
Run Code Online (Sandbox Code Playgroud)

双大括号中的任何内容都将替换为同名的环境变量,因此如果我设置了以下环境变量:

APP_PATH=~/my_app/build
APP_PORT_MAP=5000:5000
Run Code Online (Sandbox Code Playgroud)

运行subber docker-compose.yml结果文件将如下所示:

app:
    build: "~/my_app/build"
ports:
    - "5000:5000"
Run Code Online (Sandbox Code Playgroud)


use*_*100 5

env SOME_VAR="I am some var" OTHER_VAR="I am other var" docker stack deploy -c docker-compose.yml
Run Code Online (Sandbox Code Playgroud)

使用 3.6 版:

version: "3.6"
services:
  one:
    image: "nginx:alpine"
    environment:
      foo: "bar"
      SOME_VAR:
      baz: "${OTHER_VAR}"
    labels:
      some-label: "$SOME_VAR"
  two:
    image: "nginx:alpine"
    environment:
      hello: "world"
      world: "${SOME_VAR}"
    labels:
      some-label: "$OTHER_VAR"
Run Code Online (Sandbox Code Playgroud)

我从这个链接https://github.com/docker/cli/issues/939得到它


joe*_*uch 5

仅关注环境变量的默认值和强制值问题,并作为@modulito答案的更新:

docker-compose.yml现在支持使用默认值并在文件中强制执行强制值(来自文档):

支持 $VARIABLE 和 ${VARIABLE} 语法。此外,当使用 2.1 文件格式时,可以使用典型的 shell 语法提供内联默认值:

如果 VARIABLE 在环境中未设置或为空,则 ${VARIABLE:-default} 计算为默认值。仅当环境中未设置 VARIABLE 时,${VARIABLE-default} 才会计算为默认值。

同样,以下语法允许您指定强制变量:

如果环境中 VARIABLE 未设置或为空,${VARIABLE:?err} 将退出并显示包含 err 的错误消息。如果环境中未设置 VARIABLE,${VARIABLE?err} 将退出并显示包含 err 的错误消息。

不支持其他扩展的 shell 样式功能,例如 ${VARIABLE/foo/bar}。


Gor*_*a3D 5

这是为 Docker v20 使用docker composev2 命令编写的。

我遇到了类似的障碍,发现该--env-file参数 适用docker compose config命令。除此之外,使用 docker composeenv_file变量,当我想要在 Dockerfile 之外的其他地方(例如environmentfor docker-compose.yml. 我只想要一个事实来源,即 my .env,并且能够在每个部署阶段交换它们。所以这就是我如何让它工作的,基本上用于生成一个将传递到's 的docker compose config基本文件。docker-compose.ymlARGDockerfile

.local.env这将是你的.env,我有我的用于不同部署的分割。

DEVELOPMENT=1
PLATFORM=arm64
Run Code Online (Sandbox Code Playgroud)

docker-compose.config.yml - 这是我的核心 docker compose 文件。

services:
  server:
    build:
      context: .
      dockerfile: docker/apache2/Dockerfile
      args:
        - PLATFORM=${PLATFORM}
        - DEVELOPMENT=${DEVELOPMENT}
    environment:
      - PLATFORM=${PLATFORM}
      - DEVELOPMENT=${DEVELOPMENT}
Run Code Online (Sandbox Code Playgroud)

现在遗憾的是我确实需要传入变量两次,一次用于Dockerfile,另一次用于environment。然而,它们仍然来自单一来源.local.env,所以至少我不需要重复值。

然后我用它docker compose config来生成半决赛docker-compose.yml。这让我可以传递我的同伴覆盖docker-compose.local.yml来确定最终部署发生的位置。

DEVELOPMENT=1
PLATFORM=arm64
Run Code Online (Sandbox Code Playgroud)

现在我可以Dockerfile访问.env变量了。

FROM php:5.6-apache

# Make sure to declare after FROM
ARG PLATFORM
ARG DEVELOPMENT

# Access args in strings with $PLATFORM, and can wrap i.e ${PLATFORM}
RUN echo "SetEnv PLATFORM $PLATFORM" > /etc/apache2/conf-enabled/environment.conf
RUN echo "SetEnv DEVELOPMENT $DEVELOPMENT" > /etc/apache2/conf-enabled/environment.conf
Run Code Online (Sandbox Code Playgroud)

然后将 .env 变量从其中传递docker-compose.ymlDockerfile我的 Apache HTTP 服务器,该服务器将其传递到我的最终目的地,即 PHP 代码。

我的下一步是从部署阶段传递我的docker compose 覆盖。

docker-compose.local.yml - 这是我的 docker-compose 覆盖。

services:
  server:
    volumes:
      - ./localhost+2.pem:/etc/ssl/certs/localhost+2.pem
      - ./localhost+2-key.pem:/etc/ssl/private/localhost+2-key.pem
Run Code Online (Sandbox Code Playgroud)

最后,运行docker compose命令。

docker compose -f docker-compose.yml -f docker-compose.local.yml up --build
Run Code Online (Sandbox Code Playgroud)

请注意,如果您更改.env文件中的任何内容,您将需要重新运行docker compose config--build添加docker compose up. 由于构建被缓存,因此影响很小。

因此,对于我的最终命令,我通常运行:

services:
  server:
    build:
      context: .
      dockerfile: docker/apache2/Dockerfile
      args:
        - PLATFORM=${PLATFORM}
        - DEVELOPMENT=${DEVELOPMENT}
    environment:
      - PLATFORM=${PLATFORM}
      - DEVELOPMENT=${DEVELOPMENT}
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

191084 次

最近记录:

5 年,11 月 前