本文主要是对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
,并且包含两个服务db
和web
,则Compose会分别启动名为myapp_db_1
和myapp_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.pem
、cert.pem
以及key.pem
文件的路径。默认为~/.docker
。 -
COMPOSE_HTTP_TIMEOUT
:配置Compose向Docker守护进程发送请求的超时时间。单位为秒,默认值60s。 -
COMPOSE_TLS_VERSION
:配置与Docker守护进程进行TLS通信的TSL版本。默认版本为TLSv1
。支持TLSv1
、TLSv1_1
和TLSv1_2
三个版本。 -
COMPOSE_CONVERT_WINDOWS_PATHS
:在卷的定义中是否启用从Windows形式到Unix形式的路径转换。默认值为0
。true
或1
启用,false
或0
禁用。 -
COMPOSE_PATH_SEPARATOR
:指COMPOSE_FILE
环境变量中的路径间隔符。 -
COMPOSE_FORCE_WINDOWS_HOST
:是否启用使用short syntax解析卷的声明并始终假设主机路径是Windows路径,即使Compose在基于UNIX的系统上运行。true
或1
启用,false
或0
禁用。 -
COMPOSE_IGNORE_ORPHANS
:是否启用不检测项目中的孤儿容器。true
或1
启用,false
或0
禁用。 -
COMPOSE_PARALLEL_LIMIT
:设置Compose可以执行进程的最大并发数。默认值为64
,并且设置不能低于2
。 -
COMPOSE_INTERACTIVE_NO_CLI
:是否启用不使用Docker命令行执行run
和exec
命令。true
或1
启用,false
或0
禁用。在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配置文件发现环境变量已被替换:
如果未设置环境变量,则Compose会将配置文件中的环境变量替换为空字符串。这里环境变量MYAPP_TAG
未设置,image
选项的值为myapp:
,见下图:
可以使用典型的shell语法提供内联默认值,支持以下两种语法:
-
${VARIABLE:-default}
:如果VARIABLE
未设置或为空,则会应用default
的值。 -
${VARIABLE-default}
:仅当VARIABLE
未设置时才会应用default
的值。
比如Compose配置文件中有以下配置:
services:
web:
image: "myapp:${MYAPP_TAG:-v1.0.0}"
未设置环境变量和设置为空时,都会应用默认值:
改为以下写法:
services:
web:
image: "myapp:${MYAPP_TAG-v1.0.0}"
此时该变量设置为空,但没有应用默认值:
关闭终端再重新打开终端,此时该环境变量已清除,再次验证Compose配置文件发现应用了默认值:
可以使用以下两种语法来强制要求变量必须赋值:
-
${VARIABLE:?err}
:如果VARIABLE
未设置或为空,退出并输出一条包含err
的错误信息。 -
${VARIABLE?err}
:如果VARIABLE
未设置,退出并输出一条包含err
的错误信息。
比如Compose配置文件中有以下配置:
services:
web:
image: "myapp:${MYAPP_TAG:?version error}"
未设置环境变量和设置为空时,会输出错误信息:
改为以下写法:
services:
web:
image: "myapp:${MYAPP_TAG?version error}"
此时该变量设置为空,没有输出错误信息:
关闭终端再重新打开终端,此时该环境变量已清除,再次验证Compose配置文件发现输出了错误信息:
当配置中需要$
符号时,可以使用$$
符号。也可以防止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
也不会被替换:
2.设置容器中的环境变量
可以通过environment
关键字设置服务容器中的环境变量,就像 docker run -e VARIABLE=VALUE ...
一样 。比如Compose配置文件中有以下配置,等价于docker run -e DEBUG=1
:
services:
web:
environment:
- DEBUG=1
验证Compose配置文件:
3.将环境变量传递到容器
使用environment
关键字时不赋值就可以将shell中的环境变量传递给服务容器,就像使用docker run -e VARIABLE ...
一样。比如Compose配置文件中有以下配置,等价于docker run -e DEBUG
:
services:
web:
environment:
- DEBUG
shell中没有设置该环境变量时,Compose配置文件中默认为将它解释为null
:
通过export
将该环境设置为2
,验证Compose配置文件,已经传递到容器:
容器中的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
配置,多个环境变量已成功设置:
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
执行以下命令在tomcat
服务一次性容器上设置环境变量并查看环境变量:
docker-compose run -e DEBUG=1 tomcat env
结果见下图,已成功设置:
也可以通过从shell中传递环境变量的值,而不是直接赋值,执行以下命令:
export DEBUG=2
docker-compose run -e DEBUG tomcat env
结果见下图,已成功设置:
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
文件中配置的默认值:
当在多个文件中设置相同的环境变量时,Compose选择要使用的值的优先级如下:
- Compose配置文件
- Shell环境变量
- 环境文件
- Dockerfile
- 未定义的变量
下面通过export
设置环境变量,发现Compose选择使用了Shell环境变量的值:
然后修改Compose配置文件的以下部分:
services:
web:
environment:
- APPNAME=TestApp
验证Compose配置文件,可知Compose最终选择了Compose配置文件中设置的值:
NodeJS容器中需注意的细节:
如果有脚本的package.json
条目像NODE_ENV=test node server.js
一样启动,那么这将覆盖docker-compose.yml
文件中的任何设置。
7.设置Compose CLI环境变量
可以通过Docker Compose CLI环境变量来配置Docker Compose命令行的行为,它们以COMPOSE_
或DOCKER_
开头。这里以COMPOSE_FILE
和COMPOSE_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
文件,启动成功:
在/root/compose-env-test2
目录下执行以下命令后台启动项目并指定工作目录为/root/compose-env-test
目录:
docker-compose --project-directory /root/compose-env-test up -d
工作目录中有docker-compose.yml
文件,而当前目录以及它的所有上层目录中都没有docker-compose.yml
文件,启动失败:
所以在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配置文件之后后台启动成功:
在/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配置文件:
继续在/root/compose-env-test2
目录下执行以下命令:
docker-compose -f /root/compose-env-test3/docker-compose.yml up -d
此时没有通过设置COMPOSE_PROJECT_NAME
或-p
指定项目名称,也没有指定工作目录,默认工作目录为Compose配置文件所在目录,而此时项目名称正好为这个目录名称:
执行以下命令后台启动,指定工作目录为/root/compose-env-test
:
docker-compose -f /root/compose-env-test3/docker-compose.yml --project-directory /root/compose-env-test up -d
此时项目名称正好为工作目录名称:
所以可以肯定,在没有通过设置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
中设置的名称:
执行以下命令:
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
选项的设置作为项目名称:
8.通过link创建环境变量
在v1版的Compose配置文件中使用links
选项时,会为每个链接创建环境变量。它们记录在Link环境变量参考中。但是,这些变量现已被弃用。取而代之的是使用link别名作为主机名。