如何在Docker Compose中使用环境变量


217

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

proxy:
  hostname: $hostname
  volumes:
    - /mnt/data/logs/$hostname:/logs
    - /mnt/data/$hostname:/data


2
在compose的最新版本中已解决该问题,您的示例将照常运行。检查docs.docker.com/compose/compose-file/#variable-substitution有关变量替换的信息。
natbusa

1
不要忘记docker-app(自2018年6月以来):stackoverflow.com/a/51007138/6309
VonC

Answers:


93
  1. 创建一个template.yml,这是您的docker-compose.ymlwith环境变量。
  2. 假设您的环境变量在文件“ env.sh”中
  3. 将以下代码放入sh文件中并运行它。

来源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}

样本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

@Meet随时在“ BASH解决方案”下查看我的回答,在此我将更全面地概述这种方法。
modulitos

7
目前还没有更好的解决方案?
lvthillo

13
为什么要递归删除文件?(rm -rf docker-compose.yml)
moritzschaefer

@ lorenzvth7您可以在下面查看我的答案,我认为它的答案更彻底:stackoverflow.com/a/33186458/1884158
modulitos 16-10-16

5
-1此解决方案仅使事情复杂,应根据docker
Efrat Levitan

239

DOCKER解决方案:

似乎docker-compose 1.5+已启用变量替换:https//github.com/docker/compose/releases

最新的Docker Compose允许您从compose文件访问环境变量。因此,您可以获取环境变量,然后像下面那样运行Compose:

set -a
source .my-env
docker-compose up -d

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

db:
  image: "postgres:${POSTGRES_VERSION}"

这是来自文档的更多信息,在这里获取:https : //docs.docker.com/compose/compose-file/#variable-substitution

当您使用此配置运行docker-compose时,Compose在外壳程序中查找POSTGRES_VERSION环境变量并替换其值。对于本示例,Compose在运行配置之前将映像解析为postgres:9.3。

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

$ VARIABLE和$ {VARIABLE}语法均受支持。不支持扩展的外壳样式功能,例如$ {VARIABLE-default}和$ {VARIABLE / foo / bar}。

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

而且我认为此请求请求中已添加了此功能:https : //github.com/docker/compose/pull/1765

BASH解决方案:

我注意到人们对Docker的环境变量支持存在问题。让我们回到bash之类的基础知识,而不是在Docker中处理环境变量!这是使用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

然后在同一目录中运行此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

只需使用通常的bash语法在撰写文件中引用您的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证书和链接的容器)的复杂性更高。


2
您可以简单地grep foo file.text代替cat file.text | grep foo。就我而言,我不得不export $(grep "^[^#]" .config | xargs) && cat docker-compose.yml | envsubst
豪尔赫·拉文(JorgeLavín)2016年

“我注意到人们对Docker的环境变量支持存在问题” –您是否有任何详细信息或票证链接?
tleyden '16

抱歉,我没有记录我遇到的特定问题,而且很久以前(〜6个月),我不知道它是否仍然有用。但是,是的,Docker环境变量支持中的某些功能存在错误,并且由多个用户报告。我相信现在好多了。但是,当部署配置变得非常复杂时,我宁愿通过使用bash处理配置逻辑和Docker Compose进行容器编排来对其进行模块化。
modulitos '16

8
PSA:这仅适用于docker-compose up,不适用于docker-compose run
Kriegslustig '16

5
有了这个解决方案docs.docker.com/compose/compose-file/#envfile,我用你来自哪里,一个添加的环境变量.envenv_file。然后您可以在docker-compose.yml使用${VARIABLE}
musale

111

似乎docker-compose现在对file中的默认环境变量具有本机支持。

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

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

MY_SECRET_KEY=SOME_SECRET
IMAGE_NAME=docker_image

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

my-service:
  image: ${IMAGE_NAME}
  environment:
    MY_SECRET_KEY: ${MY_SECRET_KEY}

4
这是最好的解决方案!
拉登科夫·弗拉季斯拉夫

4
这也为我工作。我不知道为什么,但是文件名应该字面值.env,例如,config.env对我来说不起作用。
HBat

1
@HBat的“。” 表示一个隐藏文件-这是本地配置文件的常规过程
Jeremy Hajek

2
最好的解决方案。我们可以添加/ etc / environment属性,并通过.env将其用作环境。这样会更安全。
Chinthaka Dinadasa,

24

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

方法-1 直接方法

web:
  environment:
    - DEBUG=1
      POSTGRES_PASSWORD: 'postgres'
      POSTGRES_USER: 'postgres'

方法-2 “ .env”文件

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

$ cat .env
TAG=v1.5
POSTGRES_PASSWORD: 'postgres'

您的撰写文件将像

$ cat docker-compose.yml
version: '3'
services:
  web:
    image: "webapp:${TAG}"
    postgres_password: "${POSTGRES_PASSWORD}"

资源


2
我想看到方法1的完整示例。我无法完成这项工作,因此最终使用了.env文件(效果很好)。
BobHy

20

将环境变量用于卷时,您需要:

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

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

    HOSTNAME=your_hostname
    
  3. 更改$hostname${HOSTNAME}docker-compose.yaml 文件

    proxy:
      hostname: ${HOSTNAME}
      volumes:
        - /mnt/data/logs/${HOSTNAME}:/logs
        - /mnt/data/${HOSTNAME}:/data
    

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

echo "HOSTNAME=your_hostname" > .env && sudo docker-compose up

9
请注意,根据文档:The .env file feature only works when you use the docker-compose up command and does not work with docker stack deploy.
James Gentes

19

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

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

services:
  web:
    env_file: variables.env

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


2
确实是最好的方式
Dany

没有。它不会自动使环境变量在docker容器内可用。您仍然需要在“环境”部分中明确提及这些内容。
kta


4

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

基本上,只需使用双花括号创建环境变量即可创建撰写文件,例如:

app:
    build: "{{APP_PATH}}"
ports:
    - "{{APP_PORT_MAP}}"

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

APP_PATH=~/my_app/build
APP_PORT_MAP=5000:5000

在运行subber docker-compose.yml结果文件时,看起来像:

app:
    build: "~/my_app/build"
ports:
    - "5000:5000"

2

据我所知,这是一个进行中的工作。他们想这样做,但尚未发布。请参阅1377(@Andy提到的“新” 495)。

我最终实现了@Thomas提出的“作为CI的一部分生成.yml”方法。


1

将env添加到.env文件

VERSION=1.0.0

然后保存到 deploy.sh

INPUTFILE=docker-compose.yml
RESULT_NAME=docker-compose.product.yml
NAME=test

prepare() {
        local inFile=$(pwd)/$INPUTFILE
        local outFile=$(pwd)/$RESULT_NAME
        cp $inFile $outFile
        while read -r line; do
            OLD_IFS="$IFS"
            IFS="="
            pair=($line)
            IFS="$OLD_IFS"
               sed -i -e "s/\${${pair[0]}}/${pair[1]}/g" $outFile
            done <.env
     }
       
deploy() {
        docker stack deploy -c $outFile $NAME
}

        
prepare
deploy
    

1

使用.env文件在docker-compse.yml中定义动态值。是port还是其他任何值。

样本docker-compose:

testcore.web:
       image: xxxxxxxxxxxxxxx.dkr.ecr.ap-northeast-2.amazonaws.com/testcore:latest
       volumes: 
            - c:/logs:c:/logs
       ports:
            - ${TEST_CORE_PORT}:80
       environment:
            - CONSUL_URL=http://${CONSUL_IP}:8500 
            - HOST=${HOST_ADDRESS}:${TEST_CORE_PORT}

在.env文件中,您可以定义以下变量的值:

CONSUL_IP=172.31.28.151
HOST_ADDRESS=172.31.16.221
TEST_CORE_PORT=10002

1
env SOME_VAR="I am some var" OTHER_VAR="I am other var" docker stack deploy -c docker-compose.yml

使用版本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"

我通过此链接https://github.com/docker/cli/issues/939获得了它


1

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

您的应该看起来像这样:

hostname=my-host-name

和命令:

docker-compose --env-file /path/to/my-env-file config
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.