docker-compose 环境变量加载 .env,但不加载 compose 文件中的 env_file

Fra*_*y_V 4 environment-variables docker-compose

我真的不明白 docker-compose 在环境变量文件方面的行为。

我已经为运行 2 个 Flask 应用程序的简单回显服务器设置定义了一些变量。

.env

FLASK_RUN_PORT=5000
WEB_1_PORT=80
WEB_2_PORT=8001
Run Code Online (Sandbox Code Playgroud)

然后在docker-compose.yml

version: '3.8'

x-common-variables: &shared_envvars
  FLASK_ENV: development
  FLASK_APP: main.py
  FLASK_RUN_HOST: 0.0.0.0
  COMPOSE_PROJECT_NAME: DOCKER_ECHOES

x-volumes: &com_volumes
  - .:/project          # maps the current directory, e.g. project root that is gitted, to /proj in the container so we can live-reload

services:
  web_1:
    env_file: .env
    build:
      dockerfile: dockerfile_flask
      context: .
    ports:
      - "${WEB_1_PORT}:${FLASK_RUN_PORT}"       # flask runs on 5000 (default). docker-compose --env-file .env up loads whatever env vars specified & allows them to be used this way here.
    volumes: *com_volumes
    environment:
      <<: *shared_envvars   # DRY: defined common stuff in a shared section above, & use YAML merge language syntaxe to include that k-v mapping here. pretty neat.
      FLASK_NAME: web_1
  web_2:
    env_file: .env
    build:
      dockerfile: dockerfile_flask
      context: .
    ports:
      - "${WEB_2_PORT}:${FLASK_RUN_PORT}"       # flask by default runs on 5000 so keep it on container, and :8001 on host
    volumes: *com_volumes
    environment:
      <<: *shared_envvars
      FLASK_NAME: web_2
Run Code Online (Sandbox Code Playgroud)

如果我docker-compose up按照上述方式运行,一切都会按预期进行。

但是,如果我只是更改文件名.env,例如flask.env,,然后相应地将两者更改env_file: .envenv_file: flask.env,那么我会得到:

(venv) [fv@fv-hpz420workstation flask_echo_docker]$ docker-compose up
WARNING: The WEB_1_PORT variable is not set. Defaulting to a blank string.
WARNING: The FLASK_RUN_PORT variable is not set. Defaulting to a blank string.
WARNING: The WEB_2_PORT variable is not set. Defaulting to a blank string.
ERROR: The Compose file './docker-compose.yml' is invalid because:
Run Code Online (Sandbox Code Playgroud)

显然,在这种情况下,文件中定义的环境变量没有加载。我知道根据文档,environement:我正在使用的部分会覆盖env_file:. 但这些不是相同的变量。无论如何,如果这是问题所在,那么第一种方法也不应该起作用,对吗?

以上有什么问题吗?

Fra*_*y_V 17

实际上,它env_file是在构建图像后加载的。我们可以验证这一点。通过我上面发布的代码,我可以看到该代码env_file.env在构建时尚未加载,因为我收到了错误消息(告诉我WEB_PORT_1未设置等)。

但这可能只是因为该文件从未加载。为了排除这种情况,我们构建了图像(例如通过提供缺少的参数docker-compose build -e (...),然后我们可以验证它是否确实已加载(在我的例子中通过在 Flask 应用程序中记录其值,或者简单地打印到屏幕等)。

这意味着 的内容env_file可供正在运行的容器使用,但在此之前(例如构建映像时)不可用。

如果要在构建时在文件中使用这些变量,则docker-compose.yml必须命名该文件.env(除非有办法提供默认名称以外的名称,但如果是这样,我还没有找到任何名称)。这就是为什么更改 env_file: flask.envenv_file: .envSEEMED 使其工作 - 但它工作的真正原因是因为我的端口是在.envdocker-compose 无论如何解析的默认名称中指定的。它并不关心我docker-compose.yml是否在文件中指定它。

总结一下 - TL;DR

  • 如果您需要在构建时将环境变量提供给 docker-compose,则必须将它们存储在.env. 除了确保该文件与docker-compose.yml. 您无法更改默认名称.env
  • 要在容器运行时提供 envar,您可以将它们放入foo.env然后指定env_file:foo.env
  • 对于运行时变量,另一种选择是指定它们environment: [vars],如果只是将它们硬编码在 中docker-compose.yml是可以接受的。根据文档(未经测试),这些将覆盖也由 定义的任何变量env_file