我将从这篇优秀文章中总结要点。
ARG和ENV的区别
1 ) 简短解释:
ARG 只在构建 Docker 镜像的期间(RUN等命令)可用,而在创建镜像后和从其中启动容器(ENTRYPOINT、CMD)时不可用。
ENV 值可用于容器,也可用于运行 Docker 构建时带有该值的 RUN-style 命令(从引入该值的行开始)。如果您使用 bash 在中间容器中设置环境变量(RUN export VARI=5 && …),则该变量将无法保留到下一个命令中。
2 ) 详细解释:
ARG 也称为构建时变量。只能在 Dockerfile 中使用 ARG 指令宣告时到构建镜像时之间使用。正在运行的容器无法访问 ARG 变量的值。CMD 和 ENTRYPOINT 指令告诉容器其默认运行内容。如果您通知 Dockerfile 利用各种 ARG 变量(没有默认值),但在运行构建命令时未提供任何值,则会出现错误消息。
但是,ARG 值可以通过查看镜像的 docker history 轻松检查。因此,它们不适用于敏感数据。
ENV 变量同样在构建期间可用,在使用 ENV 指令引入后即可使用。然而,与 ARG 不同,容器也可以从最终镜像中获取其值。下面更详细地解释了如何在启动容器时覆盖 ENV 值。
3 ) 图形解释:
以下是 Dockerfile 构建 Docker 镜像并运行容器过程中 ARG 和 ENV 可用性的简化概述。
它们有重叠,但是 ARG 不能从容器内部使用。
![enter image description here](https://istack.dev59.com/urEMb.webp)
设置 ARG 和 ENV 值
设置 ARG 值
所以,您有一个定义了 ARG
和 ENV
值的 Dockerfile
。如何设置它们?您可以在 Dockerfile
中将它们留空或设置默认值。如果没有为预期的 ARG 变量提供值且没有默认值,则会出现错误消息。
以下是一个 Dockerfile
示例,包括默认值和不包括默认值:
ARG some_variable_name
RUN echo "Oh dang look at that $some_variable_name"
在命令行中构建Docker镜像时,可以使用“--build-arg”设置“ARG”值。
$ docker build --build-arg some_variable_name=a_value
运行上述Dockerfile
命令,将导致打印以下行(其中之一):哦,看那个a_value
那么,如何将其转换为使用docker-compose.yml
文件呢?
使用docker-compose时,可以在args块中指定要传递的ARG
值:
(docker-compose.yml文件)
version: '3'
services:
somename:
build:
context: ./app
dockerfile: Dockerfile
args:
some_variable_name: a_value
当你尝试设置一个在 Dockerfile
中没有提到的变量时,Docker 会报错提示。
设置 ENV 变量
那么,如何设置 ENV
变量呢?你可以在启动容器时进行设置(我们下面会详细说明),但是你也可以通过硬编码直接在 Dockerfile
中提供默认的 ENV
值。此外,你还可以为环境变量设置动态默认值!
在构建镜像时,你只能提供像前面所述的 ARG
值。你不能直接为 ENV
变量提供值。然而,ARG
和 ENV
可以一起使用。你可以使用 ARG 来设置 ENV
变量的默认值。
下面是一个基本的 Dockerfile
,使用硬编码的默认值:
ENV hey
ENV foo /bar
ADD . $foo
以下是一个使用动态构建环境值的Dockerfile
片段:
ARG A_VARIABLE
ENV an_env_var=$A_VARIABLE
一旦镜像被构建完成,你可以通过三种不同的方式来启动容器并提供ENV
变量的值,可以通过命令行或使用docker-compose.yml
文件进行配置。所有这些都会覆盖Dockerfile
中的默认ENV
值。
与ARG
不同的是,你可以向容器传递各种环境变量。甚至是Dockerfile
中没有显式定义的变量。但是是否会对应用程序产生影响则取决于你的应用程序。
选项1:逐个提供值
从命令行使用 -e 标志:
$ docker run -e "env_var_name=another_value" alpine env
从 docker-compose.yml
文件中:
version: '3'
services:
plex:
image: linuxserver/plex
environment:
- env_var_name=another_value
选项 2:从主机传递环境变量值
这与上述方法相同。
唯一的区别是,您不提供值,而只是命名变量。这将使 Docker 访问主机环境中的当前值并将其传递给容器。
$ docker run -e env_var_name alpine env
对于
docker-compose.yml
文件,省略等号和等号之后的部分即可获得相同的效果。
version: '3'
services:
plex:
image: linuxserver/plex
environment:
- env_var_name
选项3:从文件中获取值(env_file)
而不是将变量写出或硬编码(根据12因素宣言并不好的习惯),我们可以指定一个文件来读取值。这样的文件内容看起来像这样:
env_var_name=another_value
上面的文件名为env_file_name(名称任意),位于当前目录中。
您可以引用文件名,解析其中包含的环境变量来设置:
$ docker run --env-file=env_file_name alpine env
使用
docker-compose.yml
文件时,我们只需引用一个 env_file,Docker 将解析其中的变量并设置它们。
version: '3'
services:
plex:
image: linuxserver/plex
env_file: env_file_name
设置ARG和ENV的常见命令行方式
以下是一张小抄表,结合ARG
和ENV
的概述与常用的命令行设置方式。
![enter image description here](https://istack.dev59.com/1X0Fm.webp)
ENV
添加了环境变量,但是使用docker build -t temp --build-arg BUILD_TIME=def
命令会打印出 "One or more build-args [BUILD_TIME] were not consumed, failing build." 的错误信息。添加单独的ARG BUILD_TIME_ARG=default
和ENV BUILD_TIME=$BUILD_TIME_ARG
可以解决这个问题。你能把它加入到你的回答中吗?感谢您的帮助。 - Michał PietraszkoENV
相同的名称创建ARG
。ARG BUILD_TIME=default
ENV BUILD_TIME=$BUILD_TIME
- Michał Pietraszko