在构建阶段将环境变量从docker-compose传递到容器

32

我正在尝试使用单个Dockerfile,多个docker-compose文件和多个environment_variables文件创建几个环境的配置。 我需要它为每个环境使用不同的Python依赖项文件。

假设我们在两个环境中创建一个名为web的服务: developmentproduction。 为了实现这一点,我创建了以下文件结构:

docker-compose-dev.yml
docker-compose-prod.yml
envs/
  dev.env
  prod.env
web/
  Dockerfile
  requirements_dev.txt 
  requirements_prod.txt

目标是在容器的构建过程中将requirements_*.txt文件的适当名称实例化到Dockerfile中。根据文档,我尝试了这种不太成熟的方法,但似乎并不起作用:

  1. 将名称定义为环境变量:
    • envs/dev.env: REQUIREMENTS=requirements_dev.txt
    • envs/prod.env: REQUIREMENTS=requirements_prod.txt
  2. Dockerfile中使用此环境变量:

    FROM python:3.5
    ENV PYTHONUNBUFFERED 1
    ENV APP_ROOT /usr/src/app
    ...
    COPY $REQUIREMENTS $APP_ROOT/
    RUN pip install -r $APP_ROOT/$REQUIREMENTS
    
  3. docker-compose 配置文件中导入相应的定义:

  4. version: '2'
    
    services:
        web:
            build: ./web
            env_file:
                - envs/dev.env   # in docker-compose-dev.yml
                - envs/prod.env   # in docker-compose-prod.yml
            ...
    
    当我运行docker-compose up --build docker-compose-dev.yml命令时,构建过程中没有定义$REQUIREMENTS变量。
    docker-compose文档中提到了这个问题:

    注意: 如果您的服务指定了构建选项,则环境文件中定义的变量在构建期间不会自动可见。使用构建的args子选项来定义构建时环境变量。

    但是要在Dockerfile中使用ARG选项,例如ARG REQUIREMENTS,需要在docker-compose中添加相应的args选项,如下所示:
    services:
        web:
            build:
                context: ./web
                args:
                    - REQUIREMENTS
    

    尽管如此,按照文档所述,使用这种配置我的测试也失败了,因为Dockerfile中REQUIREMENTS变量的值是从

    Compose运行的环境中

    获取的,因此它会从我的shell中获取值,而不是从envs/dev.env中获取。

    因此,我的问题是:

    是否有可能在构建时将docker-compose中的env_file的环境变量传递给Dockerfile,而无需在本地shell中设置变量?


我自己遇到了这个问题。试图同时使用env_filebuild: args: FOO: ${SOME_VAR:-foo},似乎SOME_VAR没有从env_file中加载..也许这是一个bug,即在构建参数解析之后发生环境变量文件插值,或者不应用环境变量文件插值到构建参数解析? - ColinM
我在其他问题中读到了一个声明,即Dockerfile旨在是自包含的,不依赖于外部环境。但另一方面,这与argsARG的目的相矛盾。因此,它是一个错误还是一个特性并不清楚。 - BartoNaz
1个回答

62
您的 docker-compose.yml 应该像这样:
version: '2'
services:
  web:
    build:
      context: ./web
      args:
        REQUIREMENTS: "requirements_dev.txt"

您的Dockerfile应该像这样使用ARG定义构建参数:
FROM python:3.5
ENV PYTHONUNBUFFERED 1
ENV APP_ROOT /usr/src/app
ARG REQUIREMENTS
...
COPY $REQUIREMENTS $APP_ROOT/
RUN pip install -r $APP_ROOT/$REQUIREMENTS

我已经验证过并在Github上创建了一个压缩的功能演示:

https://github.com/jannikweichert/stackoverflow-41747843


谢谢,这确实有效!虽然需要在 docker-compose.yml 中硬编码变量,而不是从 *.env 文件中读取它们,但这比没有好多了。 - BartoNaz
1
太棒了!好处是你的Dockerfile作为一份包含必要输入变量显式信息的规范,而你的docker-compose则是容器设置的显式规范。开发人员不需要再检查其他文件来了解正在发生的情况。 - Jannik Weichert

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接