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 值无法在运行的容器内部使用。

之后我们将详细介绍其中的每一个。

ARG 和 ENV 可用性概述。

注意:在图像中,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 的不同方法的示例作为概述。

ARG 和 ENV 可用性概述。

在我们继续之前:是时候提一下另一个常见问题了。如果您尝试从 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 的其他文章。

posted @ 2024-06-27 15:55  CharyGao  阅读(1151)  评论(0编辑  收藏  举报