使用docker-compose在构建镜像时传递环境变量

14

我尝试按照 Dockerfiledocker compose 的参考文档传递环境变量给 Docker 镜像,但均未成功。

当使用 docker-compose 进行构建时,我希望在构建过程中将此环境变量传递给 Docker。

在 Docker 主机上,我有:

export BUILD_VERSION=1.0

app.js

console.log('BUILD_VERSION: ' + process.env.BUILD_VERSION);

Dockerfile:

FROM node
ADD app.js /
ARG BUILD_VERSION
ENV BUILD_VERSION=$BUILD_VERSION
RUN echo Build Time: $BUILD_VERSION
RUN node /app.js
CMD echo Run Time: $BUILD_VERSION

docker-compose.yml:

version: '3'
services:
  app:
    build:
      context: .
      args:
        - BUILD_VERSION

如果直接构建图像,则环境变量会被正确传递:
docker build -t test --no-cache --build-arg BUILD_VERSION .

并且也可以在运行时使用:

$ docker run --rm test
Run Time: 1.0
$ docker run --rm test node /app
BUILD_VERSION: 1.0

但是不能使用Docker Compose。
docker-compose up --build

...
Step 5/7 : RUN echo Build Time: $BUILD_VERSION
 ---> Running in 6115161f33bf
Build Time:
 ---> c691c619018a
Removing intermediate container 6115161f33bf
Step 6/7 : RUN node /app.js
 ---> Running in f51831cc5e1e
BUILD_VERSION:

它只能在运行时使用:

$ docker run --rm test
Run Time: 1.0
$ docker run --rm test node /app
BUILD_VERSION: 1.0

我也尝试在docker-compose.yml中使用environment,如下所示,但这只能在运行时而不是构建时使其可用:
version: '3'
services:
  app:
    build:
      context: .
    environment:
      - BUILD_VERSION

请指导,如何以最简单的方式使其工作?


只要 Dockerfile 中有 ENV AA=$BB,并且您之前已经执行了 export BB=CC,就不需要在 yaml 文件中提及 args 或任何命令行 build-arg。 - Scott Stensland
@ScottStensland 我也试过了,但是没成功。:( - orad
我不使用docker-compose来构建镜像,只用它来启动或关闭容器...要构建,我会发出... docker build --tag foo --no-cache的命令。 ...然后是... docker push foo ...对我来说,docker-compose yaml文件的内容是运行时设置,将其控制构建会使其变得混乱和过于复杂,特别是当您有许多具有不同重建标准与启动的容器时。 - Scott Stensland
我同意最好将所有构建任务放在Dockerfile中,只要通过docker-compose调用时有效。但是我还没有找到一个可行的解决方案。 - orad
3个回答

10

你的案例对我而言有效。

你尝试过删除图片并重新构建吗?如果镜像在缓存中,Docker不会重新构建您的镜像,即使环境变量已更改。

您可以使用以下命令进行删除:

 docker-compose down --rmi all

编辑,我在构建时展示了以下内容:

$ cat Dockerfile
FROM alpine
ARG BUILD_VERSION
ENV BUILD_VERSION=$BUILD_VERSION
RUN echo Build Time: $BUILD_VERSION

$ cat docker-compose.yml
version: '3'
services:
  app:
    build:
      context: .
      args:
        - BUILD_VERSION

构建:

$ export BUILD_VERSION=122221
$ docker-compose up --build
Creating network "a_default" with the default driver
Building app
Step 1/4 : FROM alpine
latest: Pulling from library/alpine
8e3ba11ec2a2: Pull complete
Digest: sha256:7043076348bf5040220df6ad703798fd8593a0918d06d3ce30c6c93be117e430
Status: Downloaded newer image for alpine:latest
---> 11cd0b38bc3c
Step 2/4 : ARG BUILD_VERSION
---> Running in b0a1a79967a0
Removing intermediate container b0a1a79967a0
---> 9fa331d63f6d
Step 3/4 : ENV BUILD_VERSION=$BUILD_VERSION
---> Running in a602c27689a5
Removing intermediate container a602c27689a5
---> bf2181423c93
Step 4/4 : RUN echo Build Time: $BUILD_VERSION                <<<<<< (*)
---> Running in 9d828cefcfab
Build Time: 122221
Removing intermediate container 9d828cefcfab
---> 2b3afa3d348c
Successfully built 2b3afa3d348c
Successfully tagged a_app:latest
Creating a_app_1 ... done
Attaching to a_app_1
a_app_1 exited with code 0

正如其他回答所提到的,您可以使用 docker-compose build --no-cache,如果您有多个服务,则可以避免提及“app”,因此docker-compose将构建所有服务。您可以使用不同的 env 变量来处理同一 docker-compose build 中的不同构建版本,例如:
$ cat docker-compose
version: '3'
services:
  app1:
    build:
      context: .
      args:
        - BUILD_VERSION=$APP1_BUILD_VERSION
  app2:
    build:
      context: .
      args:
        - BUILD_VERSION=$APP2_BUILD_VERSION

导出:

$ export APP1_BUILD_VERSION=1.1.1
$ export APP2_BUILD_VERSION=2.2.2

构建:

$ docker-compose build
Building app1
Step 1/4 : FROM alpine
latest: Pulling from library/alpine
8e3ba11ec2a2: Pull complete
Digest: sha256:7043076348bf5040220df6ad703798fd8593a0918d06d3ce30c6c93be117e430
Status: Downloaded newer image for alpine:latest
---> 11cd0b38bc3c
Step 2/4 : ARG BUILD_VERSION
---> Running in 0b66093bc2ef
Removing intermediate container 0b66093bc2ef
---> 906130ee5da8
Step 3/4 : ENV BUILD_VERSION=$BUILD_VERSION
---> Running in 9d89b48c875d
Removing intermediate container 9d89b48c875d
---> ca2480695149
Step 4/4 : RUN echo Build Time: $BUILD_VERSION
---> Running in 52dec27874ec
Build Time: 1.1.1
Removing intermediate container 52dec27874ec
---> 1b3654924297
Successfully built 1b3654924297
Successfully tagged a_app1:latest
Building app2
Step 1/4 : FROM alpine
---> 11cd0b38bc3c
Step 2/4 : ARG BUILD_VERSION
---> Using cache
---> 906130ee5da8
Step 3/4 : ENV BUILD_VERSION=$BUILD_VERSION
---> Running in d29442339459
Removing intermediate container d29442339459
---> 8b26def5ef3a
Step 4/4 : RUN echo Build Time: $BUILD_VERSION
---> Running in 4b3de2d223e5
Build Time: 2.2.2
Removing intermediate container 4b3de2d223e5
---> 89033b10b61e
Successfully built 89033b10b61e
Successfully tagged a_app2:latest

在运行时,环境变量是可用的。我需要在构建时拥有它。 - orad

3

您需要在docker-compose.yml文件中设置参数,如下所示,然后该参数将被覆盖为传递的环境变量 -

version: '3'
services:
  app:
    build:
      context: .
      args:
        - BUILD_VERSION

下一步需要导出您需要传递的环境变量。
$ export BUILD_VERSION=1.0

现在使用以下命令构建镜像:
$ docker-compose build --no-cache --build-arg BUILD_VERSION=$BUILD_VERSION app

正如我之前所提到的,使用docker build命令即使没有虚拟值也可以工作。但是我需要它能够在docker-compose中工作。 - orad
我已经更新了答案,你能试一下看看它是否有效吗! - Mishi.Srivastava
成功了!但我希望能够使用 docker-compose up 一步完成。这样,当我在 docker-compose.yml 中有多个服务时,就必须单独构建镜像。 - orad

1
你可以在构建时从docker-compose文件传递参数到docker build。令人惊讶的是,环境变量在运行和构建中都没有被使用。
// docker-compose.yml

version: '3'
services:
app:
  build:
    context: .
environment:
  - BUILD_VERSION
args:
  - BUILD_VERSION=${BUILD_VERSION}
volumes:
       ...
// Dockerfile
FROM node
ADD app.js /
ARG BUILD_VERSION
ENV BUILD_VERSION=$BUILD_VERSION
RUN echo Build Time: $BUILD_VERSION
RUN node /app.js
CMD echo Run Time: $BUILD_VERSION

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