我们能否在构建Docker镜像时通过Dockerfile传递环境变量?

136

我正在处理一个任务,涉及使用Dockerfile构建具有centOs为其基础的docker镜像。 Dockerfile中的其中一步需要设置http_proxyhttps_proxy环境变量以在代理后面工作。

由于这个Dockerfile将被多个使用不同代理的团队使用,我希望避免为每个团队编辑Dockerfile。相反,我正在寻找一种解决方案,允许我在构建时传递ENV变量,例如:

sudo docker build -e http_proxy=somevalue .

我不确定是否已经有提供此功能的选项。我有所遗漏吗?


1
在运行时传递这些参数有什么问题吗?就像 docker run -e http_proxy http://1.2.3.4:3128 -e https_proxy 1.2.3.4:3129 这样?docker run 的文档请参考 http://docs.docker.com/reference/commandline/run/。 - user2915097
3
问题在于Docker文件中的一个步骤涉及到yum安装,如果我不设置http/https环境变量,它将失败,如果没有正确的安装,我就无法构建镜像。因此,docker run 在这里对我没有帮助。 - Aniketh
这个问题已经在这里 https://github.com/docker/docker/issues/4962 和这里 https://github.com/docker/docker/pull/9176 中讨论过并被关闭,所以目前看来你没有解决方案。 - user2915097
感谢用户2915097的评论。我已经查看了上述的Github链接,我提出这个问题只是希望在Stackoverflow上有人遇到过类似的情况。 - Aniketh
请随时在 https://github.com/docker/docker/pull/9176 中发表您对此类需求的要求。 - nwinkler
显示剩余2条评论
4个回答

195

容器可以使用 构建参数(在 Docker 1.9+ 中可用),类似于环境变量。

以下是方法:

FROM php:7.0-fpm
ARG APP_ENV=local
ENV APP_ENV=${APP_ENV}
RUN cd /usr/local/etc/php && ln -sf php.ini-${APP_ENV} php.ini

然后构建生产容器:

docker build --build-arg APP_ENV=prod .

针对您的特定问题:

FROM debian
ENV http_proxy=${http_proxy}

请运行以下命令:docker build --build-arg http_proxy=10.11.24.31 .需要注意的是,如果使用docker-compose构建容器,您可以在docker-compose.yml文件中指定这些构建参数, 但不能在命令行中指定。但是,您可以在docker-compose.yml文件中使用变量替换,该替换使用环境变量

21
因为我忽视了它:你需要使用ARG告诉Docker可以将构建参数传递给构建器。如果没有指定ARG <name>,它将无法正常工作。 - Markus Bruckner
10
这个 ENV APP_ENV ${APP_ENV} 是不必要的。只需要有 ARG APP_ENV 而不需要 =local,它将获取构建参数并将其用作任何由 ENV 设置的变量即可。 - ElmoVanKielmo
10
@ElmoVanKielmo 建造过程中是正确的,但是 ARG 不会在运行 docker 镜像时作为环境变量持续存在。使用 ENV APP_ENV ${APP_ENV} 确保环境变量在容器运行时仍然可用。 - DuckPuppy
@DuckPuppy 真的,但我坚持回答了原帖问题。 - ElmoVanKielmo
@ElmoVanKielmo OP的问题是关于如何从命令行传递ENV,那么仅有ARG有何帮助?你需要ARG以便可以通过--build-arg传递一个参数,然后你需要ENV将其复制到环境变量中,以便与镜像一起持久化。 - haridsv
显示剩余3条评论

52

所以我不得不通过尝试和错误来寻找答案,因为许多人解释说您可以将ARG -> ENV传递,但它并不总是有效的,因为ARG在FROM标记之前或之后定义非常重要。

下面的示例应该清楚地解释了这一点。 我最初遇到的主要问题是,我的所有ARGS都在FROM之前定义,这导致所有的ENV始终未定义。

# ARGS PRIOR TO FROM TAG ARE AVAIL ONLY TO FROM for dynamic a FROM tag
ARG NODE_VERSION
FROM node:${NODE_VERSION}-alpine

# ARGS POST FROM can bond/link args to env to make the containers environment dynamic
ARG NPM_AUTH_TOKEN
ARG EMAIL
ARG NPM_REPO

ENV NPM_AUTH_TOKEN=${NPM_AUTH_TOKEN}
ENV EMAIL=${EMAIL}
ENV NPM_REPO=${NPM_REPO}

# for good measure, what do we really have
RUN echo NPM_AUTH_TOKEN: $NPM_AUTH_TOKEN && \
  echo EMAIL: $EMAIL && \
  echo NPM_REPO: $NPM_REPO && \
  echo $HI_5
# remember to change HI_5 every build to break `docker build`'s cache if you want to debug the stdout

..... # rest of whatever you want RUN, CMD, ENTRYPOINT etc..

7
哇,噔,这也发生在我身上了!没人谈论这个问题,在文档中也没有提到、警告等!非常感谢! - chrizzler
我可以提一下,如果你的部署环境是自动CI,这是至关重要的。例如,当我尝试让GitLab CI跨项目域进行扩展时,我发现了这个问题。例如,一个项目可能会使用不同的节点版本等。 - Nick
1
让我省了不少心,谢谢!我永远也想不到 ARG 的位置是很重要的。 - Nikita Zavyalov
3
我认为这个解释实际上在这里有详细说明:https://docs.docker.com/engine/reference/builder/#understand-how-arg-and-from-interact。在FROM之前声明的ARG不属于任何构建阶段,因此不能在FROM之后的任何指令中使用。 - andras
1
非常感谢,这是一个很烦人的问题要追踪,干杯 - Peroxy

5
我遇到了同样的情况。
根据Sin30的回答,一个不错的解决方案是使用shell。
CMD ["sh", "-c", "cd /usr/local/etc/php && ln -sf php.ini-$APP_ENV php.ini"]

3

要设置多个构建参数,比如你的情况下的 http_proxyhttps_proxy,需要进行以下更改:

1). Dockerfile

FROM centos:latest

# Define ARG after FROM to indicate values coming from build arguments are part of the build stage.
ARG http_proxy 
ARG https_proxy

# Create the environment variables and assign the values from the build arguments.
ENV http_proxy=$http_proxy \
    https_proxy=$https_proxy \

# Print the values.
RUN echo "http_proxy: $http_proxy"
RUN echo "https_proxy: $https_proxy"

2)。运行命令

sudo docker build \
--build-arg http_proxy=http://172.0.0.1 \
--build-arg https_proxy=https://10.20.30.2 \
.

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