Docker ARG、ENV 和 .env - 完整指南
Docker ARG、ENV 和 .env - 完整指南
Error: Docker image build failed.
构建 Docker 镜像并配置你的 Docker 化应用程序并不一定是一次尝试、失败、重复的 Google 表演。本文将帮助您自信地使用 Docker ARG、ENV、env_file 和 .env 文件。
唯一的先决条件是:确保您熟悉 Docker 的基础知识。
继续阅读,您将了解如何利用 Docker 构建时变量、环境变量和 docker-compose 模板的强大功能轻松配置 Docker 映像和 docker 化应用程序。
概述
好吧,让我们开始了解细节。该指南分为以下主题:
请随意直接跳到您现在需要的那个。所有这些将帮助您更好地理解 Dockerfile 中的 ENV 和 ARG。
刚刚开始使用 Docker?查看这篇关于您应该了解的 6 个 Docker 基础知识的文章。
常见的误解
这是一篇很长、很深入的读物。让我们从您现在可以使用的东西开始,而无需阅读整个内容!
以下是快速要点列表:
- 有些工具会查找名为 .env 的文件并尝试从中读取。
docker-compose
是其中之一,但还有其他一些。但并非所有这些工具都使用这些条目来设置环境变量。 docker-compose
使用 .env 文件中的值来设置 docker-compose.yml 文件的预处理步骤的值。像 $HI 这样的美元符号变量会在 docker-compose.yml (或您指向 docker-compose 的任何文件)中替换。这不会直接设置环境变量。- ARG 仅在构建 Docker 映像(RUN 等)期间可用,而不是在创建映像并从中启动容器(ENTRYPOINT、CMD)之后可用。您可以使用 ARG 值来设置 ENV 值来解决这个问题。
- ENV 值可用于容器,也可用于在映像构建期间运行的 Dockerfile 命令,从引入它们的行开始。
- 如果您使用 bash (RUN export VARI=5 && ...) 在 Dockerfile 指令中设置环境变量,它将不会持续存在。下一个命令将无法访问该值。 (如果确实需要,您可以使用此方法来设置动态环境变量。)
- env_file 是一个文件术语,其中包含有关可由 Docker CLI 使用的环境变量的行。这是将许多环境变量传递给单个命令的便捷方法。名称听起来像 .env 文件,但它们并不相同。
- 设置 ARG 和 ENV 值会在 Docker 映像中留下痕迹。不要将它们用于不应该保留的秘密(好吧,你可以使用多阶段构建)。
点环境文件 (.env)
首先, .env
文件只是一个文件。但是,如果它位于当前目录中,某些工具默认会出于各种原因对其进行调查。 docker-compose
是这些工具之一。
如果您的项目中有一个名为 .env 的文件,则它仅用于通过 docker-compose
将值放入活动的 docker-compose.yml
文件(或您指向的文件)中。
该机制本身并没有在 Docker 中设置任何 ENV 或 ARG 值。它完全是 docker-compose.yml 的东西。
.env
文件中的值按以下表示法写入:
VARIABLE_NAME=some value
OTHER_VARIABLE_NAME=some other value, like 5
请注意,在 bash 脚本中,您需要编写类似
export VARIABLE_NAME=something
的内容?这里的语法略有不同。
这些键值对用于替换 docker-compose.yml
文件中的美元符号变量。这是一个预处理步骤,生成的临时文件由 docker-compose
使用。这是避免硬编码值的好方法!
您还可以使用它在 docker-compose
中设置环境变量的值。这不会自动发生。
下面是一个示例 docker-compose.yml 文件,它依赖于 .env
文件提供的值来设置未来容器的环境变量:
version: '3'
services:
example:
image: ubuntu
environment:
- env_var_name=${VARIABLE_NAME} # here it is!
提示:使用 .env 文件时,您可以使用单个命令调试 docker-compose.yml 文件。输入
docker-compose config
。这样,您将看到 docker-compose.yml 文件内容在替换步骤后的外观,而无需运行其他任何内容。
关于 docker-compose
和 .env
文件的另一件事!这是你应该了解的一个陷阱。主机上的环境变量将覆盖 .env 文件中指定的值。是的,你没有看错。请在此处阅读更多信息,或查看有关 compose 的 env var 优先级的文档。
现在 .env
已经不存在了,让我们看看 Dockerfile 中发生了什么。
ARG 和 ENV
使用 Docker 时,我们区分两种不同类型的变量 - ARG 和 ENV。它们的不同之处在于图像容器生命周期中值何时可用。
以下是 ARG 和 ENV 可用性的简化概述。从从 Dockerfile 构建 Docker 镜像开始,直到容器运行。 ARG 值无法在运行的容器内部使用。
之后我们将详细介绍其中的每一个。
注意:在图像中,Dockerfile 周围有一个矩形。这有点令人困惑。它应该仅围绕 “构建映像” 步骤。但这样读起来会比较困难……
ARG(构建时间)
通过 ARG 定义的变量也称为构建时变量。它们仅在通过 Dockerfile 中的 ARG 指令在 Dockerfile 中 “宣布” 的那一刻起才可用。
正在运行的容器无法访问 ARG 变量的值。因此,默认情况下,您通过 CMD 和 ENTRYPOINT 指令运行的任何内容都不会看到这些值。
ARG 的好处是,Docker 将期望获取这些变量的值。至少,如果您不指定默认值。如果运行 build
命令时未提供这些值,则会出现错误消息。以下是 Docker fill 在构建过程中抱怨的示例:
# no default value is specified!
ARG some_value
尽管 ARG 值不可用于容器,但在构建映像后可以通过 Docker CLI 轻松检查它们。例如,通过在图像上运行 docker history
。如果不受信任的用户可以访问您的图像,则 ARG 和 ENV 对于敏感数据来说不是一个好的选择。
ENV(构建时间和运行时间)
ENV 变量在构建期间和未来运行的容器中都可用。在 Dockerfile 中,只要您使用 ENV 指令引入它们,它们就可以使用。
与 ARG 不同,ENV 值可由从最终映像启动的容器访问。启动容器时可以覆盖 ENV 值,更多内容见下文。
设置 ARG 值
到现在为止,您已经了解了 ARG 和 ENV 之间的区别。让我们从 ARG 开始看看如何设置它们。
您可以选择仅指定 ARG 值应该存在,或者也为其提供默认值。下面是一个 Dockerfile 示例,既没有默认值,也有一个:
# no default value:
ARG some_variable_name
# WITH a hard-coded default value:
#ARG some_variable_name=some_default_value
# we will leave this commented out for the upcoming example
# let's use the value
RUN echo "Oh dang look at that $some_variable_name"
# NOTE: you can can also put curly brackets around
# the variable name: ${some_variable_name}
# I find this more readable
从命令行构建 Docker 映像时,可以使用 –build-arg 设置 ARG 值:
$ docker build --build-arg some_variable_name=a_value
使用上面的 Dockerfile 运行该命令将导致打印以下行(以及其他内容):
Oh dang look at that a_value
如果您通过 docker-compose
构建图像怎么办?使用 docker-compose 时,您可以指定 “args” 传递给 Dockerfile ARG 条目:
(docker-compose.yml 文件)
version: '3'
services:
example:
build:
context: .
dockerfile: Dockerfile
args:
some_variable_name: a_value
当您尝试设置 Dockerfile 中未提及的 ARG 变量时,Docker 会抱怨。如果你没有设置所需的变量,Docker 也会抱怨。
设置 ENV 值
那么,如何设置 ENV 值呢?您可以通过该过程的多个步骤来完成此操作!每一项都会覆盖前一项。
- 您可以在构建期间设置 ENV 值(通过默认值或从 ARG 值)。
- 运行容器时,您可以通过多种方式为环境变量提供值。我们稍后会详细讨论这个细节。
首先,这是一个基本的 Dockerfile,使用带有硬编码默认值的 ENV:
# no default value would crash
#ENV hey
# ENV needs a default value
ENV foo /bar
# you can also write
ENV foo=/bar
# ENV values can be used during the build
COPY . $foo
# or COPY . ${foo}
# this resolves to: COPY . /bar
如果您想在构建过程中动态设置 ENV 变量怎么办?构建图像时,您唯一可以提供的就是 ARG 值。您不能直接为 ENV 变量提供值。然而,ARG 和 ENV 可以一起工作。您可以使用 ARG 在 Dockerfile 中设置 ENV 变量的默认值。
以下是 Dockerfile 的片段,使用动态构建环境值:
# expect a build-time variable
ARG A_VARIABLE
# use the value to set the ENV var default
ENV an_env_var=$A_VARIABLE
# Success! If not overridden, the value of an_env_var
# will be available to your containers!
构建镜像后,您可以在启动容器时指定环境变量。 All 将覆盖通过 Dockerfile 中的 ENV 设置的任何值。
您可以通过三种不同的方式为环境变量提供值,既可以使用 docker CLI,也可以使用 docker-compose 和 docker-compose.yml 文件。我们针对这三种方式详细介绍了这两种工具。
注意:您可以传递未通过 ENV 定义的环境变量!构建时 ARG 变量的定义更加严格。
1. 一一提供价值
通过命令行操作 docker run
时,请使用 -e 标志:
$ docker run -e "env_var_name=another_value" alpine env
从 docker-compose.yml 文件来看,这可以得出同样的结果:
version: '3'
services:
example:
image: ubuntu
environment:
- env_var_name=another_value
2. 从主机传递环境变量值
与上面类似,但值得指出。您提供变量名称,但省略值。这将使 Docker 查找主机环境中的当前值并将其传递给容器。
这是将冗长变量排除在 CLI 之外的好方法。
$ docker run -e env_var_name alpine env
对于 docker-compose.yml 文件,只需指定环境变量的名称具有相同的效果:
version: '3'
services:
example:
image: ubuntu
environment:
- env_var_name
3. 从文件(有时称为 env_file)中获取值
我们可以指定一个文件来记录它们,而不是列出很多变量。
该文件的内容如下所示:
env_var_name=another_value
env_var_name2=yet_another_value
让我们来看一个例子。假设我们创建一个名为 “BOB”(名称任意)的文件,并将上述行放入其中。
我们需要像这样引用文件名:
$ docker run --env-file=BOB alpine env
对于 docker-compose.yml 文件,我们使用 env_file 指令:
version: '3'
services:
example:
image: ubuntu
env_file: BOB
你可能会问为什么是 “BOB”?好吧,大多数文档和教程都将该文件称为 “env_file” 或类似的名称,这听起来很重要。但这只是一个任意的名称。我选择称其为 “BOB” 是为了表明一个观点。
还记得上面的图片吗?我添加了通过 Docker CLI 或在 Dockerfile 中在不同阶段设置 ENV 和 ARG 的不同方法的示例作为概述。
在我们继续之前:是时候提一下另一个常见问题了。如果您尝试从 Dockerfile 的 RUN 语句内部设置环境变量的值(例如 RUN export VARI=5 && ...
),您将无法在以下任何 RUN 语句中访问该值。这与设置 ENV 值不同!
原因是通过 RUN 语句的 “设置” 发生在临时容器内。命令完成运行时的映像,但容器的环境不会以这种方式持续存在。
如果确实需要,您可以使用此方法来设置动态环境变量。
旁注:检查图像
如果您对某个映像感到好奇,并且想知道它在容器启动之前是否提供了默认的 ENV 变量值,您可以 “检查” 它,并查看默认设置了哪些 ENV 条目:
# first, get the images on your system
$ docker images
# select an image id you are curious about and...
$ docker inspect image-id
# look out for an "Env" array in the output
覆盖 ENV 值
想象一下,您有一个从 Dockerfile 构建的映像。该 Dockerfile 定义了一些 ENV 值。
运行容器时如何更改这些值?或者,如果您愿意,如何确保 ENV 值保持不变?
当通过 CLI 提供单个环境变量或具有正确条目的 env_files 时,Dockerfile 中的 ENV 值将被覆盖。
此外,容器内运行的进程可以自行更改其环境。下面是一个命令,它使用在运行 Python 脚本之前设置 SOME_VAR 的 shell 行覆盖 CMD:
$docker run myimage SOME_VAR=hi python app.py
这种运行容器的方式将完全覆盖您可能在映像中定义的任何 SOME_VAR。至少从 app.py 脚本的角度来看是这样。即使您在最终命令之前使用 -e 标志设置了一个值。
优先级从强到弱:
- 填充容器化应用程序集,
- 来自单个环境条目的值,
- 来自 env_file 的值,
- Dockerfile ENV 条目。
综上所述
这是对构建 Docker 映像和启动容器时设置 ARG 和 ENV 变量的所有方法的真正彻底的了解。
我希望它能帮助您很好地了解构建时参数、环境变量、env_files 以及 docker-compose 的工作方式。
在您的形象塑造之旅中一切顺利!如果您想了解更多信息,请查看我关于构建 Docker 映像和充分利用 Docker 的其他文章。