本文主要是对Docker Compose的环境变量以及如何在Compose中设置环境变量进行一个总结。

一、环境信息

本文所使用的环境如下:

  • 操作系统:CentOS Linux release 8.1.1911
  • Docker:19.03.11
  • Docker Compose:1.26.0

二、Docker Compose CLI环境变量

Docker Compose CLI环境变量主要用来配置Docker Compose命令行的行为。以DOCKER_开头的变量与用于配置Docker命令行客户端的那些变量效果相同。注意也可以使用环境文件来提供其中的一些变量 。至于具体有哪些Docker Compose CLI环境变量,见以下列表:

  • COMPOSE_PROJECT_NAME:设置项目名称。如果未设置,默认为当前工作目录的名称(如果未设置工作目录,工作目录默认为Compose配置文件所在目录)。在项目启动时该值与服务名称会一起添加到容器中。例如项目名称为myapp,并且包含两个服务dbweb,则Compose会分别启动名为myapp_db_1myapp_web_1的容器 。
  • COMPOSE_FILE:指定要使用的Compose配置文件的路径。如果未指定,Compose会先在当前目录中查找docker-compose.yml文件,找不到就依次在上层目录中查找,直到找到为止,如果找不到会报错。此变量支持由路径分隔符分隔的多个Compose文件(在Linux和macOS上路径分隔符为:,在Windows上为;)。例如, COMPOSE_FILE=docker-compose.yml:docker-compose.prod.yml。路径分隔符也可以使用COMPOSE_PATH_SEPARATOR进行自定义。
  • COMPOSE_API_VERSION:设置此变量的目的是为了解决Compose需要临时运行而客户端和服务器版本不匹配的情况。在生产环境中不推荐使用这个临时方案,最好通过升级来保证客户端和服务端版本的兼容性。
  • DOCKER_HOST:设置Docker守护进程(Daemon)的监听URL 。与Docker客户端一样,默认为unix:///var/run/docker.sock
  • DOCKER_TLS_VERIFY:如果该环境变量不为空,则与Docker守护进程的所有交互都通过TLS协议进行加密。
  • DOCKER_CERT_PATH:配置用于TLS验证的ca.pemcert.pem以及key.pem文件的路径。默认为~/.docker
  • COMPOSE_HTTP_TIMEOUT:配置Compose向Docker守护进程发送请求的超时时间。单位为秒,默认值60s。
  • COMPOSE_TLS_VERSION:配置与Docker守护进程进行TLS通信的TSL版本。默认版本为TLSv1。支持TLSv1TLSv1_1TLSv1_2三个版本。
  • COMPOSE_CONVERT_WINDOWS_PATHS:在卷的定义中是否启用从Windows形式到Unix形式的路径转换。默认值为0true1启用,false0禁用。
  • COMPOSE_PATH_SEPARATOR:指COMPOSE_FILE环境变量中的路径间隔符。
  • COMPOSE_FORCE_WINDOWS_HOST:是否启用使用short syntax解析卷的声明并始终假设主机路径是Windows路径,即使Compose在基于UNIX的系统上运行。true1启用,false0禁用。
  • COMPOSE_IGNORE_ORPHANS:是否启用不检测项目中的孤儿容器。true1启用,false0禁用。
  • COMPOSE_PARALLEL_LIMIT:设置Compose可以执行进程的最大并发数。默认值为64,并且设置不能低于2
  • COMPOSE_INTERACTIVE_NO_CLI:是否启用不使用Docker命令行执行runexec命令。true1启用,false0禁用。在CLI被上述操作需要的Windows上,此选项不可用。

三、在文件中声明环境变量

Compose支持在名为.env的环境文件中声明默认环境变量,该文件放置在执行docker-compose命令的文件夹(当前工作目录)中即可生效。所以可以将不同的.env放置在不同的目录下,在哪个目录执行docker-compose命令,哪个目录下的.env文件就会生效。

1.语法规则

  • env文件中的每一行都采用VAR=VAL格式。
  • #开头的行将作为注释处理并被忽略。
  • 忽略空白行。
  • 引号不会被特殊处理,意味着它们是VAL的一部分。

2.作用

定义在.env中的环境变量主要用于Compose配置文件中的变量替换,特别是当多个Compose配置文件都用到同一个环境变量时,可以将该环境变量定义在.env中,当环境变量的值改变了也不必修改所有Compose配置文件,只需修改.env文件中的环境变量值即可,很方便维护。也可以用于定义以下Docker Compose CLI环境变量:

  • COMPOSE_API_VERSION
  • COMPOSE_CONVERT_WINDOWS_PATHS
  • COMPOSE_FILE
  • COMPOSE_HTTP_TIMEOUT
  • COMPOSE_TLS_VERSION
  • COMPOSE_PROJECT_NAME
  • DOCKER_CERT_PATH
  • DOCKER_HOST
  • DOCKER_TLS_VERIFY

另外关于.env还有以下两点需注意:

  • 运行时环境中存在的值始终会覆盖.env文件内部定义的值。同样,通过命令行参数传递的值也具有优先权。
  • .env文件中定义的环境变量在容器内部不会自动显示。

四、Docker Compose设置环境变量

Docker Compose中设置环境变量十分灵活,总结为以下几种方式。

1.替换Compose配置文件中的环境变量

可以使用shell中的环境变量替换Compose配置文件中的值,${VARIABLE}$VARIABLE这两种语法都支持。如有以下Compose配置:

version: '3'
services:
  web:
    image: "myapp:${MYAPP_TAG}"
    ports:
      - "5000:5000"
  redis:
    image: "redis:alpine"

通过export设置环境变量MYAPP_TAG的值为v1.0.1,然后验证Compose配置文件发现环境变量已被替换:

dockerfile ENV设置环境变量 docker -e 环境变量_compose设置环境变量


如果未设置环境变量,则Compose会将配置文件中的环境变量替换为空字符串。这里环境变量MYAPP_TAG未设置,image选项的值为myapp:,见下图:

dockerfile ENV设置环境变量 docker -e 环境变量_docker-compose_02


可以使用典型的shell语法提供内联默认值,支持以下两种语法:

  • ${VARIABLE:-default}:如果VARIABLE未设置或为空,则会应用default的值。
  • ${VARIABLE-default}:仅当VARIABLE未设置时才会应用default的值。

比如Compose配置文件中有以下配置:

services:
  web:
    image: "myapp:${MYAPP_TAG:-v1.0.0}"

未设置环境变量和设置为空时,都会应用默认值:

dockerfile ENV设置环境变量 docker -e 环境变量_compose设置环境变量_03


改为以下写法:

services:
  web:
    image: "myapp:${MYAPP_TAG-v1.0.0}"

此时该变量设置为空,但没有应用默认值:

dockerfile ENV设置环境变量 docker -e 环境变量_docker-compose_04


关闭终端再重新打开终端,此时该环境变量已清除,再次验证Compose配置文件发现应用了默认值:

dockerfile ENV设置环境变量 docker -e 环境变量_compose设置环境变量_05


可以使用以下两种语法来强制要求变量必须赋值:

  • ${VARIABLE:?err}:如果VARIABLE未设置或为空,退出并输出一条包含err的错误信息。
  • ${VARIABLE?err}:如果VARIABLE未设置,退出并输出一条包含err的错误信息。

比如Compose配置文件中有以下配置:

services:
  web:
    image: "myapp:${MYAPP_TAG:?version error}"

未设置环境变量和设置为空时,会输出错误信息:

dockerfile ENV设置环境变量 docker -e 环境变量_docker-compose_06


改为以下写法:

services:
  web:
    image: "myapp:${MYAPP_TAG?version error}"

此时该变量设置为空,没有输出错误信息:

dockerfile ENV设置环境变量 docker -e 环境变量_docker_07


关闭终端再重新打开终端,此时该环境变量已清除,再次验证Compose配置文件发现输出了错误信息:

dockerfile ENV设置环境变量 docker -e 环境变量_env文件声明环境变量_08


当配置中需要$符号时,可以使用$$符号。也可以防止Compose插值,因此$$ 可以引用不想由Compose处理的环境变量。例如以下配置:

version: '3'
services:
  web:
    image: "myapp:v1.0.0"
    ports:
      - "5000:5000"
    command: "$$VAR_NOT_INTERPOLATED_BY_COMPOSE"    
  redis:
    image: "redis:alpine"

设置了环境变量VAR_NOT_INTERPOLATED_BY_COMPOSE,Compose配置文件中的VAR_NOT_INTERPOLATED_BY_COMPOSE也不会被替换:

dockerfile ENV设置环境变量 docker -e 环境变量_compose环境变量_09

2.设置容器中的环境变量

可以通过environment关键字设置服务容器中的环境变量,就像 docker run -e VARIABLE=VALUE ...一样 。比如Compose配置文件中有以下配置,等价于docker run -e DEBUG=1

services:
  web:
    environment:
      - DEBUG=1

验证Compose配置文件:

dockerfile ENV设置环境变量 docker -e 环境变量_compose环境变量_10

3.将环境变量传递到容器

使用environment关键字时不赋值就可以将shell中的环境变量传递给服务容器,就像使用docker run -e VARIABLE ...一样。比如Compose配置文件中有以下配置,等价于docker run -e DEBUG

services:
  web:
    environment:
      - DEBUG

shell中没有设置该环境变量时,Compose配置文件中默认为将它解释为null

dockerfile ENV设置环境变量 docker -e 环境变量_env文件声明环境变量_11


通过export将该环境设置为2,验证Compose配置文件,已经传递到容器:

dockerfile ENV设置环境变量 docker -e 环境变量_docker_12


容器中的DEBUG变量的值是从运行Compose的shell中的同名变量中获取的。

4.通过env_file为容器设置多个环境变量

可以通过env_file配置选项将外部文件中配置的多个环境变量传递到服务容器,就像使用docker run --env-file=FILE ...一样。比如Compose配置文件中有以下配置,等价于docker run --env-file=web-variables.env

services:
  web:
    env_file:
      - web-variables.env

在Compose配置文件目录新建一个名为web-variables.env的文件,随意配置几个测试用环境变量:

APPNAME=MyApp
AUTHOR=RtxTitanV
VERSION=v1.0.0
CREATETIME
DESCRIPTION=web service

通过export设置CREATETIME,验证Compose配置文件,可知Compose把web-variables.env配置内容解释为了environment配置,多个环境变量已成功设置:

dockerfile ENV设置环境变量 docker -e 环境变量_compose环境变量_13

5.使用docker-compose run命令设置环境变量

可以使用docker-compose run -e设置一次性容器上的环境变量,就像docker run -e命令一样。使用以下Compose配置文件进行测试:

version: '3'
services:
  tomcat:
    image: "tomcat:9.0-jdk8-corretto"
    ports:
      - "8080:8080"
  redis:
    image: "redis:alpine"

执行以下命令后台启动两个服务:

docker-compose up -d

dockerfile ENV设置环境变量 docker -e 环境变量_compose环境变量_14


执行以下命令在tomcat服务一次性容器上设置环境变量并查看环境变量:

docker-compose run -e DEBUG=1 tomcat env

结果见下图,已成功设置:

dockerfile ENV设置环境变量 docker -e 环境变量_compose环境变量_15


也可以通过从shell中传递环境变量的值,而不是直接赋值,执行以下命令:

export DEBUG=2
docker-compose run -e DEBUG tomcat env

结果见下图,已成功设置:

dockerfile ENV设置环境变量 docker -e 环境变量_docker_16

6.通过.env文件设置环境变量

可以在名为.env的环境文件中为Compose配置文件中引用的任何环境变量设置默认值,或者用于配置Compose。如有以下Compose配置:

version: '3'
services:
  web:
    image: "myapp:${MYAPP_TAG}"
    ports:
      - "5000:5000"
    environment:
      - APPNAME
  redis:
    image: "redis:alpine"

在Compose配置文件所在目录新建一个.env文件,内容如下:

MYAPP_TAG=v1.0.0
APPNAME=MyApp

验证Compose配置文件,环境变量都被解释为.env文件中配置的默认值:

dockerfile ENV设置环境变量 docker -e 环境变量_docker-compose_17


当在多个文件中设置相同的环境变量时,Compose选择要使用的值的优先级如下:

  1. Compose配置文件
  2. Shell环境变量
  3. 环境文件
  4. Dockerfile
  5. 未定义的变量

下面通过export设置环境变量,发现Compose选择使用了Shell环境变量的值:

dockerfile ENV设置环境变量 docker -e 环境变量_env文件声明环境变量_18


然后修改Compose配置文件的以下部分:

services:
  web:
    environment:
      - APPNAME=TestApp

验证Compose配置文件,可知Compose最终选择了Compose配置文件中设置的值:

dockerfile ENV设置环境变量 docker -e 环境变量_docker_19

NodeJS容器中需注意的细节:
如果有脚本的package.json条目像NODE_ENV=test node server.js一样启动,那么这将覆盖docker-compose.yml文件中的任何设置。

7.设置Compose CLI环境变量

可以通过Docker Compose CLI环境变量来配置Docker Compose命令行的行为,它们以COMPOSE_DOCKER_开头。这里以COMPOSE_FILECOMPOSE_PROJECT_NAME这两个最常用的Compose CLI环境变量为例进行设置。使用以下配置进行测试:

version: '3'
services:
  tomcat:
    image: "tomcat:9.0-jdk8-corretto"
    ports:
      - "8080:8080"
  redis:
    image: "redis:alpine"

其中docker-compose.yml/root/compose-env-test目录下,在/root/compose-env-test目录下新建一个test目录并进入,然后再新建一个/root/compose-env-test2目录。在/root/compose-env-test/test目录下执行以下命令后台启动项目并指定工作目录为/root/compose-env-test2目录:

docker-compose --project-directory /root/compose-env-test2 up -d

此时没有通过设置COMPOSE_FILE-f选项指定使用的Compose配置文件,工作目录以及它的所有上层目录中都没有docker-compose.yml文件,而当前目录的上层目录中有docker-compose.yml文件,启动成功:

dockerfile ENV设置环境变量 docker -e 环境变量_compose设置环境变量_20


/root/compose-env-test2目录下执行以下命令后台启动项目并指定工作目录为/root/compose-env-test目录:

docker-compose --project-directory /root/compose-env-test up -d

工作目录中有docker-compose.yml文件,而当前目录以及它的所有上层目录中都没有docker-compose.yml文件,启动失败:

dockerfile ENV设置环境变量 docker -e 环境变量_compose环境变量_21


所以在Compose配置文件未指定时,Compose会先在当前目录中查找docker-compose.yml文件。找不到就依次在上层目录中查找,直到找到为止,如果找不到会报错。继续在/root/compose-env-test2目录下执行以下命令:

export COMPOSE_FILE=/root/compose-env-test/docker-compose.yml
docker-compose --project-directory /root/compose-env-test up -d

在通过COMPOSE_FILE环境变量指定了Compose配置文件之后后台启动成功:

dockerfile ENV设置环境变量 docker -e 环境变量_compose设置环境变量_22


/root/compose-env-test3目录下新建一个docker-compose.yml文件,内容如下,服务名和之前不一样:

version: '3'
services:
  tomcat2:
    image: "tomcat:9.0-jdk8-corretto"
    ports:
      - "8080:8080"
  redis2:
    image: "redis:alpine"

继续在/root/compose-env-test2目录下执行以下命令:

export COMPOSE_FILE=/root/compose-env-test/docker-compose.yml
docker-compose -f /root/compose-env-test3/docker-compose.yml --project-directory /root/compose-env-test up -d

COMPOSE_FILE环境变量和-f选项同时使用时,会使用-f选项指定的Compose配置文件:

dockerfile ENV设置环境变量 docker -e 环境变量_docker-compose_23


继续在/root/compose-env-test2目录下执行以下命令:

docker-compose -f /root/compose-env-test3/docker-compose.yml up -d

此时没有通过设置COMPOSE_PROJECT_NAME-p指定项目名称,也没有指定工作目录,默认工作目录为Compose配置文件所在目录,而此时项目名称正好为这个目录名称:

dockerfile ENV设置环境变量 docker -e 环境变量_env文件声明环境变量_24


执行以下命令后台启动,指定工作目录为/root/compose-env-test

docker-compose -f /root/compose-env-test3/docker-compose.yml --project-directory /root/compose-env-test up -d

此时项目名称正好为工作目录名称:

dockerfile ENV设置环境变量 docker -e 环境变量_env文件声明环境变量_25


所以可以肯定,在没有通过设置COMPOSE_PROJECT_NAME-p指定项目名称时,默认为当前工作目录名称。下面通过COMPOSE_PROJECT_NAME指定项目名称,执行以下命令:

export COMPOSE_PROJECT_NAME=myproject
docker-compose -f /root/compose-env-test3/docker-compose.yml --project-directory /root/compose-env-test up -d

此时项目名称为COMPOSE_PROJECT_NAME中设置的名称:

dockerfile ENV设置环境变量 docker -e 环境变量_compose设置环境变量_26


执行以下命令:

export COMPOSE_PROJECT_NAME=myproject
docker-compose -f /root/compose-env-test3/docker-compose.yml -p myproject2 --project-directory /root/compose-env-test up -d

在同时使用COMPOSE_PROJECT_NAME环境变量和-p选项设置项目名称时,会将-p选项的设置作为项目名称:

dockerfile ENV设置环境变量 docker -e 环境变量_compose设置环境变量_27

8.通过link创建环境变量

在v1版的Compose配置文件中使用links选项时,会为每个链接创建环境变量。它们记录在Link环境变量参考中。但是,这些变量现已被弃用。取而代之的是使用link别名作为主机名。