难以理解 Docker 编写环境变量

Trouble understanding Docker Compose environment variables

我有一个 playground 项目 Docker 使用这样的文件编写:

version: '3'
services:
    mysql:
        image: 'mysql:8'
        container_name: '${PROJECT_NAME}_mysql'
        hostname: '${PROJECT_NAME}_mysql'
        networks:
            - internal
        ports:
            - '127.0.0.1:${MYSQL_EXPOSE_PORT}:3306'
        volumes:
            - mysql:/var/lib/mysql
        env_file:
            -   ./mysql/.env
        environment:
            MYSQL_EXPOSE_PORT: '${MYSQL_EXPOSE_PORT}'
            MYSQL_ROOT_PASSWORD: '${MYSQL_ROOT_PASSWORD}'
            MYSQL_USER: '${MYSQL_USER}'
            MYSQL_PASSWORD: '${MYSQL_PASSWORD}'
volumes:
    mysql:

networks:
    internal:

我的./mysql/.env是这样的:

MYSQL_DATABASE=foobar
MYSQL_ROOT_PASSWORD=root
MYSQL_USER=web
MYSQL_PASSWORD=web

我的 .env 文件如下所示:

COMPOSE_PROJECT_NAME=foobar
PROJECT_NAME=foobar

MYSQL_EXPOSE_PORT=33061

MYSQL_DATABASE=foobar
MYSQL_ROOT_PASSWORD=root
MYSQL_USER=web_override
MYSQL_PASSWORD=web_override

我在某处读到 env_fileenvironment 创建的变量将在容器本身中可用,而 --env-file 提供在处理 [=20] 期间可用的变量=] 文件.

但是 运行 :

docker-compose -f docker-compose.yml --env-file .env up -d

对我来说,产生了意想不到的行为。

  1. 如果我同时省略 env_fileenvironment 配置,MySQL 将因密码为空而无法启动。来自 --env-file 的变量将被忽略。这是否意味着实际上需要 MYSQL_ROOT_PASSWORD 作为容器环境?

  2. 如果我只输入 env_file,MySQL 会启动,但会使用来自 ./mysql/.env 的凭据。它默默地忽略通过 --env-file 选项

    提供的 .env 文件
  3. 最后,如果我同时输入 env_fileenvironment,由于变量替换,它将遵循 --env-file 的值。但是执行到容器中并回显 $MYSQL_ROOT_PASSWORD 似乎很少丑陋,并且尖叫着等待发生的安全漏洞。

在我看来,我对 Docker Compose 环境变量的工作方式存在根本性的误解。

有人可以对这些问题做出某种澄清吗?

处理环境变量分为两个阶段:

  1. 在 Compose 级别,它采用自己的环境,并且还读取 docker-compose.yml 文件中的 docker compose --env-file file, or if you don't specify that option, .env. It then uses these environment variables to do variable substitution
  2. 每个容器都有自己的环境,由 Compose environment: or env_file: 指令指定。

这意味着在外部环境中设置某些内容或将其放入 --env-file 文件(第 1 步)不会自动使其对容器可见(第 2 步)。

这与您的观察是一致的。在前两种情况下,指定 --env-file 不会在每个容器配置中放置任何内容,它只会影响环境变量扩展,因此从容器的角度来看它没有任何效果。在第三种情况下,您有正确的顺序:--env-file 在 Compose 级别设置变量,变量替换在 environment: 块中设置固定字符串,然后 environment: takes precedence env_file:.