如何在Dockerfile中定义一个变量?

332
在我的 Dockerfile 中,我希望定义一些变量以便稍后在 Dockerfile 中使用。我知道可以使用 ENV 指令来实现,但我并不想让这些变量成为环境变量。有没有办法在 Dockerfile 的范围内声明变量?

ARG 没有定义一个可以在 Dockerfile 中使用的变量。你需要将其与 ENV 命令配合使用才能得到你想要的结果;ARG foo; ENV FOO=$foo; COPY file $foo(对于糟糕的格式化表示抱歉,我猜手机上不可能进行代码块和多行操作)。 - ntwrkguru
6个回答

236
您可以使用ARG - 请参见https://docs.docker.com/engine/reference/builder/#arg

ARG指令定义了一个变量,用户可以在构建时使用docker build命令通过--build-arg <varname>=<value>标志传递给构建器。如果用户指定了Dockerfile中未定义的构建参数,则构建会输出错误。

在构建时与COPY一起使用可能很有用(例如,复制特定文件夹等特定标记的内容)。例如:

ARG MODEL_TO_COPY
COPY application ./application
COPY $MODEL_TO_COPY ./application/$MODEL_TO_COPY

构建容器时:
docker build --build-arg MODEL_TO_COPY=model_name -t <container>:<model_name specific tag> .

似乎对于COPY命令不起作用。 - femibyte

191

回答你的问题:

在我的Dockerfile中,我想定义一些变量以便稍后在Dockerfile中使用。

你可以使用以下方法定义变量:

ARG myvalue=3

等号周围不允许有空格。

之后使用如下:

RUN echo $myvalue > /test

95
据我所知,只有ENV允许这样做,正如在“环境变量替换”中提到的那样。

使用ENV语句声明的环境变量也可以用作某些指令中要解释为变量的变量。

它们必须是环境变量,才能在每个由docker build创建的新容器中为Dockerfile的每一行重新声明。

换句话说,这些变量不是直接在Dockerfile中解释的,而是在为Dockerfile行创建的容器中解释的,因此需要使用环境变量。


今天,我同时使用了ARG (docker 1.10+和docker build --build-arg var=value)以及ENV
仅使用ARG意味着你的变量只在构建时可见,而非运行时可见。
我的Dockerfile通常包含:
ARG var
ENV var=${var}

在您的情况下,ARG就足够了:我通常使用它来设置http_proxy变量,这是docker构建需要在构建时访问互联网的。

Christopher King评论中 补充道:

小心!
ARG 变量只在其被使用的"阶段"内处于作用域中,需要为每个阶段重新声明。

他指出了 Dockerfile / 作用域

An ARG variable definition comes into effect from the line on which it is defined in the Dockerfile not from the argument’s use on the command-line or elsewhere.

For example, consider this Dockerfile:

FROM busybox
USER ${user:-some_user}
ARG user
USER $user
# ...

A user builds this file by calling:

docker build --build-arg user=what_user .

The USER at line 2 evaluates to some_user as the user variable is defined on the subsequent line 3.
The USER at line 4 evaluates to what_user as user is defined and the what_user value was passed on the command line.
Prior to its definition by an ARG instruction, any use of a variable results in an empty string.

An ARG instruction goes out of scope at the end of the build stage where it was defined.
To use an arg in multiple stages, each stage must include the ARG instruction.


8
注意!变量ARG仅在“使用它的阶段”中才处于作用域内,需要为每个阶段重新声明!请参考:https://docs.docker.com/engine/reference/builder/#scope - Christopher King
3
感谢您的反馈,非常有见地。我已经将您的评论和参考资料包含在答案中,以提高可见性。 - VonC

18
如果同一条 RUN 指令中要重新使用变量,可以简单地设置一个 shell 变量。我真的很喜欢他们用官方 Ruby Dockerfile来处理这个问题的方式。

2
很棒的答案。虽然如果可能的话应该使用ARG,但有时您需要分配和重复使用动态变量。例如:RUN foo=$(date) && echo $foo - wisbucky

11

你可以使用ARG变量默认值,在运行命令期间,你甚至可以使用--build-arg 变量=值来更新此值。要在docker文件中使用这些变量,可以在运行命令中将它们引用为$变量

注意: 这些变量对于像RUN echo $变量这样的Linux命令是可用的,并且它们不会在镜像中持续存在。


1
这是更好的答案,因为默认值对意图至关重要。 - WestCoastProjects
1
语法需要更新为 ARG 变量=默认值,而不是 ARG 变量 默认值 - Nathan Neulinger

3
晚来的宾客,但如果您不想暴露环境变量,我猜这么做可能更容易:
RUN echo 1 > /tmp/__var_1
RUN echo `cat /tmp/__var_1`
RUN rm -f /tmp/__var_1

我最终完成了这个任务,因为我们在AWS CodeArtifact中托管私有的npm包:

RUN aws codeartifact get-authorization-token --output text > /tmp/codeartifact.token
RUN npm config set //company-123456.d.codeartifact.us-east-2.amazonaws.com/npm/internal/:_authToken=`cat /tmp/codeartifact.token`
RUN rm -f /tmp/codeartifact.token

这里ARG无法使用,而且我不想使用ENV,因为我不想将此令牌暴露给其他任何内容。


3行的“RUN”将会有3个层次。如果我们检查早期的层次,我们能看到你的秘密吗? - undefined

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