我正在尝试使用单个
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
文件的正确名称。根据文档,我尝试了这种幼稚的方法,但似乎不起作用:
REQUIREMENTS=requirements_dev.txt
REQUIREMENTS=requirements_prod.txt
在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
在
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
,而无需在我的 shell 中本地设置变量?Dockerfile
您的 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 上创建了一个缩小的功能演示:
运行带有
build:
块的容器发生在两个单独的阶段:首先 Compose 构建镜像,然后运行基于该镜像的容器。 build:
块之外的任何内容都不会影响构建步骤,更具体地说,通过 env_file:
设置的环境变量只会影响正在运行的容器,并且在构建期间不可见。
同样,Compose 有两种不同的“环境”概念。 当处理 Compose 文件本身时,在开始任何操作之前,Compose 会考虑对
docker-compose
命令可见的环境变量、任何 docker-compose --env-file
选项以及隐式 .env
文件。 当容器运行时,每个容器的 environment:
和 env_file:
专门为该容器设置环境。
要使变量对构建过程可见,您需要几个步骤:
变量本身必须声明为 Dockerfile
ARG
,以允许它从外部传入。 例如,
FROM python:3.5
WORKDIR /usr/src/app
ARG REQUIREMENTS
COPY $REQUIREMENTS ./
RUN pip install -r $REQUIREMENTS
ARG
值在COPY
命令和RUN
指令等地方可见,但对最终容器CMD
不可见。 请注意,它们嵌入在图像中,并且工具可能能够提取它们,这意味着您应该避免以这种方式传递凭据。
在 Compose 文件中,声明
build: { args: }
设置或传递变量。 问题中的语法是正确的,可以从 Compose 环境中传递它;重复一遍
services:
web:
build:
context: ./web
args:
- REQUIREMENTS
运行 Compose 时,使值在 Compose 环境中可见。 您可以使用主机上的普通环境变量来完成此操作
REQUIREMENTS=requirements_dev.txt docker-compose build
但是如果您想使用现有的环境文件,可以使用 Compose CLI 选项
docker-compose --env-file envs/dev.env build
如果此文件仅包含构建时设置,则不一定需要将其包含在 Compose 中
env_file:
,并且您可以完全删除该行或块。 由于文件将被加载到 Compose 的外部环境中,因此您还可以使用 environment:
有选择地传递值或根据需要将它们映射到不同的名称。