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

问题描述 投票:0回答:2

我正在尝试使用单个

Dockerfile
、多个
docker-compose
文件和多个
envoronment_variables
文件为多个环境创建配置。我需要它为每个环境使用具有 python 依赖项的不同文件。

比方说,我们在两个环境中创建

web
服务:
development
production
。为了实现这一目标,我创建了以下文件结构:

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

目标是在容器的

requirements_*.txt
进程中实例化
Dockerfile
中的
build
文件的正确名称。根据文档,我尝试了这种幼稚的方法,但似乎不起作用:

  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
    配置中导入相应的定义:

    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
文档中对此有一个注释:

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

但是要使用

ARG
中的
Dockerfile
选项,就像
ARG REQUIREMENTS
一样,需要
args
中相应的
docker-compose
选项,如下所示:

services:
    web:
        build:
            context: ./web
            args:
                - REQUIREMENTS

尽管如此,使用此配置我的测试也失败了,因为根据 documentation,Dockerfile 中

REQUIREMENTS
变量的值取自

Compose 运行的环境

因此,它从我的 shell 获取值,而不是从

envs/dev.env

所以我的问题是:

是否可以在构建时将环境变量

env_file
中的
docker-compose
传递到
Dockerfile
,而无需在我的 shell 中本地设置变量?

docker docker-compose
2个回答
63
投票

您的 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


0
投票

运行带有

build:
块的容器发生在两个单独的阶段:首先 Compose 构建镜像,然后运行基于该镜像的容器。
build:
块之外的任何内容都不会影响构建步骤,更具体地说,通过
env_file:
设置的环境变量只会影响正在运行的容器,并且在构建期间不可见。

同样,Compose 有两种不同的“环境”概念。 当处理 Compose 文件本身时,在开始任何操作之前,Compose 会考虑对

docker-compose
命令可见的环境变量、任何
docker-compose --env-file
选项以及隐式
.env
文件。 当容器运行时,每个容器的
environment:
env_file:
专门为该容器设置环境。

要使变量对构建过程可见,您需要几个步骤:

  1. 变量本身必须声明为 Dockerfile

    ARG
    ,以允许它从外部传入。 例如,

    FROM python:3.5
    WORKDIR /usr/src/app
    ARG REQUIREMENTS
    COPY $REQUIREMENTS ./
    RUN pip install -r $REQUIREMENTS
    

    ARG
    值在
    COPY
    命令和
    RUN
    指令等地方可见,但对最终容器
    CMD
    不可见。 请注意,它们嵌入在图像中,并且工具可能能够提取它们,这意味着您应该避免以这种方式传递凭据。

  2. 在 Compose 文件中,声明

    build: { args: }
    设置或传递变量。 问题中的语法是正确的,可以从 Compose 环境中传递它;重复一遍

    services:
      web:
        build:
          context: ./web
          args:
            - REQUIREMENTS
    
  3. 运行 Compose 时,使值在 Compose 环境中可见。 您可以使用主机上的普通环境变量来完成此操作

    REQUIREMENTS=requirements_dev.txt docker-compose build
    

    但是如果您想使用现有的环境文件,可以使用 Compose CLI 选项

    docker-compose --env-file envs/dev.env build
    

如果此文件仅包含构建时设置,则不一定需要将其包含在 Compose 中

env_file:
,并且您可以完全删除该行或块。 由于文件将被加载到 Compose 的外部环境中,因此您还可以使用
environment:
有选择地传递值或根据需要将它们映射到不同的名称。

© www.soinside.com 2019 - 2024. All rights reserved.