使用插值在 Compose 文件中设置、使用和管理变量

Compose 文件可以使用变量来提供更大的灵活性。如果您想快速切换镜像标签以测试多个版本,或想将卷源调整到您的本地环境,您无需每次都编辑 Compose 文件,只需设置变量即可在运行时将值插入到 Compose 文件中。

插值还可以在运行时用于将值插入到您的 Compose 文件中,然后这些值可用于将变量传递到您的容器环境中。

以下是一个简单示例

$ cat .env
TAG=v1.5
$ cat compose.yaml
services:
  web:
    image: "webapp:${TAG}"

当您运行 docker compose up 时,Compose 文件中定义的 web 服务会插值使用 .env 文件中设置的镜像 webapp:v1.5。您可以使用 config 命令来验证这一点,该命令会将解析后的应用配置打印到终端。

$ docker compose config
services:
  web:
    image: 'webapp:v1.5'

插值语法

插值适用于未加引号和双引号的值。支持带花括号 (${VAR}) 和不带花括号 ($VAR) 的表达式。

对于带花括号的表达式,支持以下格式

  • 直接替换
    • ${VAR} -> VAR 的值
  • 默认值
    • ${VAR:-default} -> 如果设置且非空则为 VAR 的值,否则为 default
    • ${VAR-default} -> 如果设置则为 VAR 的值,否则为 default
  • 必需值
    • ${VAR:?error} -> 如果设置且非空则为 VAR 的值,否则带错误退出
    • ${VAR?error} -> 如果设置则为 VAR 的值,否则带错误退出
  • 替代值
    • ${VAR:+replacement} -> 如果设置且非空则为 replacement,否则为空
    • ${VAR+replacement} -> 如果设置则为 replacement,否则为空

更多信息,请参阅 Compose Specification 中的插值

使用插值设置变量的方法

Docker Compose 可以从多个源将变量插值到您的 Compose 文件中。

请注意,当同一变量由多个源声明时,会应用优先级规则

  1. 您的 shell 环境中的变量
  2. 如果未设置 --env-file,则使用本地工作目录 (PWD) 中 .env 文件设置的变量
  3. --env-file 指定的文件或项目目录中的 .env 文件中的变量

您可以通过运行 docker compose config --environment 来检查 Compose 用于插值 Compose 模型所使用的变量和值。

.env 文件

Docker Compose 中的 .env 文件是一个文本文件,用于定义在运行 docker compose up 时应可用于插值的变量。此文件通常包含变量的键值对,并允许您在一个地方集中管理配置。如果您需要存储多个变量,.env 文件会非常有用。

.env 文件是设置变量的默认方法。.env 文件应放置在项目目录的根目录中,与您的 compose.yaml 文件相邻。有关环境文件格式的更多信息,请参阅环境文件语法

基本示例

$ cat .env
## define COMPOSE_DEBUG based on DEV_MODE, defaults to false
COMPOSE_DEBUG=${DEV_MODE:-false}

$ cat compose.yaml 
  services:
    webapp:
      image: my-webapp-image
      environment:
        - DEBUG=${COMPOSE_DEBUG}

$ DEV_MODE=true docker compose config
services:
  webapp:
    environment:
      DEBUG: "true"

附加信息

  • 如果您在 .env 文件中定义了一个变量,您可以使用 environment 属性直接在您的 compose.yaml 文件中引用它。例如,如果您的 .env 文件包含环境变量 DEBUG=1 并且您的 compose.yaml 文件如下所示

     services:
       webapp:
         image: my-webapp-image
         environment:
           - DEBUG=${DEBUG}

    Docker Compose 会将 ${DEBUG} 替换为 .env 文件中的值

    重要

    当在 .env 文件中使用变量作为容器环境中的环境变量时,请注意环境变量优先级

  • 您可以将您的 .env 文件放置在项目目录根目录以外的位置,然后使用 CLI 中的 --env-file 选项,以便 Compose 可以找到它。

  • 如果使用--env-file 进行替换,您的 .env 文件可能会被另一个 .env 文件覆盖。

重要

.env 文件进行替换是 Docker Compose CLI 的一个功能。

在运行 docker stack deploy 时,Swarm 不支持此功能。

.env 文件语法

以下语法规则适用于环境文件

  • # 开头的行被视为注释并被忽略。
  • 空行被忽略。
  • 未加引号和双引号 (") 的值会应用插值。
  • 每行表示一个键值对。值可以可选地加引号。
    • VAR=VAL -> VAL
    • VAR="VAL" -> VAL
    • VAR='VAL' -> VAL
  • 未加引号的值的行内注释必须在其前面有一个空格。
    • VAR=VAL # comment -> VAL
    • VAR=VAL# not a comment -> VAL# not a comment
  • 加引号的值的行内注释必须跟在闭合引号之后。
    • VAR="VAL # not a comment" -> VAL # not a comment
    • VAR="VAL" # comment -> VAL
  • 单引号 (') 的值按字面意思使用。
    • VAR='$OTHER' -> $OTHER
    • VAR='${OTHER}' -> ${OTHER}
  • 引号可以使用 \ 转义。
    • VAR='Let\'s go!' -> Let's go!
    • VAR="{\"hello\": \"json\"}" -> {"hello": "json"}
  • 双引号值中支持常见的 shell 转义序列,包括 \n\r\t\\
    • VAR="some\tvalue" -> some value
    • VAR='some\tvalue' -> some\tvalue
    • VAR=some\tvalue -> some\tvalue

使用 --env-file 进行替换

您可以在 .env 文件中为多个环境变量设置默认值,然后在 CLI 中将该文件作为参数传递。

此方法的优点是您可以将文件存储在任何地方并适当命名,例如。此文件路径是相对于执行 Docker Compose 命令的当前工作目录。通过使用 --env-file 选项来传递文件路径。

$ docker compose --env-file ./config/.env.dev up

附加信息

  • 如果您想临时覆盖已在 compose.yaml 文件中引用的 .env 文件,此方法非常有用。例如,您可能为生产环境 (.env.prod) 和测试环境 (.env.test) 使用不同的 .env 文件。在以下示例中,有两个环境文件:.env.env.dev。两者为 TAG 设置了不同的值。
    $ cat .env
    TAG=v1.5
    $ cat ./config/.env.dev
    TAG=v1.6
    $ cat compose.yaml
    services:
      web:
        image: "webapp:${TAG}"
    
    如果在命令行中未使用 --env-file,则默认加载 .env 文件
    $ docker compose config
    services:
      web:
        image: 'webapp:v1.5'
    
    传递 --env-file 参数会覆盖默认文件路径
    $ docker compose --env-file ./config/.env.dev config
    services:
      web:
        image: 'webapp:v1.6'
    
    当传递的文件路径作为 --env-file 参数无效时,Compose 会返回一个错误
    $ docker compose --env-file ./doesnotexist/.env.dev  config
    ERROR: Couldn't find env file: /home/user/./doesnotexist/.env.dev
    
  • 您可以使用多个 --env-file 选项来指定多个环境文件,Docker Compose 会按顺序读取它们。后面的文件可以覆盖前面文件中的变量。
    $ docker compose --env-file .env --env-file .env.override up
    
  • 您可以在启动容器时,从命令行覆盖特定的环境变量。
    $ docker compose --env-file .env.dev up -e DATABASE_URL=mysql://new_user:new_password@new_db:3306/new_database
    

本地 .env 文件 vs <项目目录> .env 文件

.env 文件也可用于声明用于控制 Compose 行为和要加载文件的预定义环境变量

在没有显式 --env-file 标志的情况下执行时,Compose 会在您的工作目录 (PWD) 中搜索 .env 文件,并加载用于自身配置和插值的值。如果此文件中的值定义了 COMPOSE_FILE 预定义变量,从而导致项目目录设置为另一个文件夹,Compose 将加载第二个 .env 文件(如果存在)。这第二个 .env 文件的优先级较低。

这种机制使得使用自定义变量集作为覆盖来调用现有 Compose 项目成为可能,而无需通过命令行传递环境变量。

$ cat .env
COMPOSE_FILE=../compose.yaml
POSTGRES_VERSION=9.3

$ cat ../compose.yaml 
services:
  db:
    image: "postgres:${POSTGRES_VERSION}"
$ cat ../.env
POSTGRES_VERSION=9.2

$ docker compose config
services:
  db:
    image: "postgres:9.3"

从 shell 进行替换

您可以使用主机机器或执行 docker compose 命令的 shell 环境中现有的环境变量。这使您能够在运行时动态地将值注入到 Docker Compose 配置中。例如,假设 shell 中包含 POSTGRES_VERSION=9.3 并且您提供了以下配置

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

使用此配置运行 docker compose up 时,Compose 会在 shell 中查找 POSTGRES_VERSION 环境变量并将其值代入。在此示例中,Compose 在运行配置之前将镜像解析为 postgres:9.3

如果未设置环境变量,Compose 会用空字符串替换。在上一个示例中,如果未设置 POSTGRES_VERSION,则镜像选项的值将是 postgres:

注意

postgres: 不是有效的镜像引用。Docker 期望使用没有标签的引用(例如 postgres,它默认为 latest 镜像)或带有标签的引用(例如 postgres:15)。

页面选项