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

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

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

下面是一个简单的例子:

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

当你运行 docker compose up 时,Compose 文件中定义的 web 服务 interpolates.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 已设置且非空,否则为空
    • ${VAR+replacement} -> replacement 如果 VAR 已设置,否则为空

欲了解更多信息,请参阅Compose规范中的 插值

使用插值设置变量的方法

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文件中定义了一个变量,你可以直接在compose.yml中使用environment属性来引用它。例如,如果你的.env文件包含环境变量DEBUG=1,并且你的compose.yml文件看起来像这样:

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

    Docker Compose 用 .env 文件中的值替换 ${DEBUG}

    重要

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

  • 你可以将你的.env文件放在项目目录根目录以外的位置,然后使用 --env-file选项在CLI中,这样Compose就可以导航到它。

  • 您的.env文件可以被另一个.env文件覆盖,如果它被替换为--env-file

重要

.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.yml文件中引用的.env文件,此方法非常有用。例如,您可能为生产环境(.env.prod)和测试环境(.env.test)准备了不同的.env文件。 在以下示例中,有两个环境文件,.env.env.dev。它们为TAG设置了不同的值。
    $ cat .env
    TAG=v1.5
    $ cat ./config/.env.dev
    TAG=v1.6
    $ cat compose.yml
    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 文件与 .env 文件

一个.env文件也可以用来声明 预定义的环境变量,这些变量用于控制Compose的行为和要加载的文件。

在没有明确使用--env-file标志执行时,Compose会在您的工作目录中搜索.env文件( PWD)并加载值 用于自我配置和插值。如果此文件中的值定义了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 未设置,则 image 选项的值为 postgres:

注意

postgres: 不是一个有效的镜像引用。Docker 期望的引用要么是没有标签的,比如 postgres,它会默认使用最新的镜像,要么是带有标签的,比如 postgres:15