乐趣区

关于docker:Docker第3部分十二个Dockerfile指令

原文作者:Jeff Hale
原文地址:https://towardsdatascience.co…
翻译:付新圆

本篇文章是对于 Dockerfiles 的,这是 Docker 系列文章的第三局部。如果您还没有读过 第 1 局部,请先浏览它,您能够从全新的角度理解 Docker 容器概念。第 2 局部是 Docker 生态系统的简要介绍。在当前的文章中,我将钻研精简 Docker 映像、Docker CLI 命令以及应用 Docker 的数据。当初,让咱们跳进这十几个 Dockerfile 阐明中去吧!

图:跳进来

Docker 映像

Docker 容器是栩栩如生的 Docker 映像,它是一个独立的、最小的操作系统,带有利用程序代码。

Docker 映像在构建时创立的,而 Docker 容器是在运行时创立。

Dockerfile 是 Docker 的外围,Dockerfile 通知 Docker 如何构建用于制作容器的映像。

每个 Docker 映像都蕴含一个名为 Dockerfile 的文件,没有扩展名。调用 Dockerfile docker build 创立映像时,假设该 Dockerfile 位于当前工作目录中,能够应用文件标记(-f)指定其余地位。

容器是由一系列层构建而成的,除位于最初一层之上的最终容器层外,每一层都是只读的。Dockerfile 通知 Docker 增加哪些层以及增加程序。

每一层实际上只是一个文件,其中蕴含自上一层以来的更改。在 Unix 中,简直所有内容都是文件。

根底图像提供了初始层,根本图像也称为父图像。

当图像从近程存储库拉到本地计算机时,只下载本地计算机上尚未存在的层。Docker 就是通过重用现有层来节俭空间和工夫。

图:根本(跳跃)图像

Dockerfile 指令是一行结尾的大写单词,后跟其参数。Dockerfile 中的每一行都能够蕴含一条指令。构建图像时,阐明从上到下进行解决。阐明如下:

FROM ubuntu:18.04 
COPY . /app 

只有指令 FROM,RUN,COPY 和 ADD 能力在最终图像中创立图层,其余的指令可配置事物,增加元数据或通知 Docker 在运行时执行某些操作,例如公开端口或运行命令。
在本文中,我假如您正在应用基于 Unix 的 Docker 映像。您也能够应用基于 Windows 的映像,但这是一个较慢,较不欢快,较不常见的过程。因而,如果能够,请应用 Unix。

让咱们疾速浏览一下咱们将摸索的十二个 Dockerfile 指令吧。

Dockerfile 指令

FROM —指定根本(父)图像。

LABEL —提供元数据,包含维护者信息。

ENV —设置持久性环境变量。

RUN —运行命令并创立图像层,用于将软件包装置到容器中。

COPY - 将文件和目录复制到容器。

ADD - 将文件和目录复制到容器,能够反对本地.tar 文件。

CMD —为执行中的容器提供命令和参数,能够笼罩参数,只能有一个 CMD。

WORKDIR —为以下阐明设置工作目录。

ARG —定义在构建时传递给 Docker 的变量。

ENTRYPOINT —为执行中的容器提供命令和参数。争执仍然存在。

EXPOSE —裸露端口。

VOLUME —创立目录装置点以拜访和存储持久数据。

让咱们开始吧!

阐明和示例

Dockerfile 能够像上面这样简略:

FROM ubuntu:18.04 

FROM

Dockerfile 必须以 FROM 指令或 ARG 指令结尾,后跟 FROM 指令。

FROM 关键字通知 Docker 应用与提供的存储库和标签匹配的根底映像,根本图像也称为父图像。

在此示例中,ubuntu 是映像存储库。Ubuntu 是 官网 Docker 存储库的名称,该存储库提供了风行的 Linux 操作系统的 Ubuntu 版本的根本版本。

图:Linux 吉祥物 Tux

请留神,此 Dockerfile 蕴含根底映像的标记:18.04,这个标签通知 Docker 在 ubuntu 仓库中镜像的哪个版本。如果不蕴含标签,则默认状况下,Docker 将采纳最新标签。为了使您的用意清晰明了,最好指定一个根本图像标签。

当上述 Dockerfile 首次用于在本地构建映像时,Docker 下载 ubuntu 映像中指定的层。能够将这些层视为彼此重叠。每一层都是一个文件,具备与前一层不同的一组文件。

创立容器时,能够在只读层的顶部增加可写层。

图:从 Docker 文档

为了提高效率,Docker 应用了一种写时拷贝策略。如果一个层存在于图像的前一层,而另一层须要对其进行读拜访,Docker 将应用现有文件。不须要下载任何内容。

当一个图像正在运行时,如果一个层须要被容器批改,那么该文件将被复制到顶部的可写层中。

更具实质性的 Dockerfile

尽管咱们的复线图很简洁,但它也很慢,提供的信息很少,并且在容器运行时什么也不做。让咱们看一个较长的 Dockerfile,它构建一个小得多的图像,并在容器运行时执行脚本。

FROM python:3.7.2-alpine3.8 
LABEL maintainer="jeffmshale@gmail.com" 
ENV ADMIN="jeff" 
RUN apk update && apk upgrade && apk add bash 
COPY . ./app 
ADD https://raw.githubusercontent.com/discdiver/pachy-vid/master/sample_vids/vid1.mp4 \ 
/my_app_directory 
RUN ["mkdir", "/a_directory"] 
CMD ["python", "./my_script.py"] 

这是怎么回事能?让咱们逐渐理解并揭开神秘面纱。
根本映像是带有标签 3.7.2-alpine3.8 的正式 Python 映像。从 源代码中能够看到,该映像蕴含 Linux、Python 和其余一些内容。平地图像之所以受欢迎,是因为它们体积小,速度快且平安。然而,Alpine 映像并没有很多操作系统长处。如果须要,您必须本人装置这样的软件包。

LABEL

下一条指令是 LABEL。LABEL 将元数据增加到图像中。在本例中,它提供图像维护者的分割信息。Labels 不会减慢构建速度或占用空间,它们提供了无关 Docker 映像的有用信息,因而肯定要应用它们。无关 LABEL 元数据的更多信息,请参见 此处。

ENV

ENV 设置在容器运行时可用的长久环境变量。在下面的例子中,您能够在创立 Docker 容器时应用 ADMIN 变量。

ENV 非常适合设置常量,如果您在 Dockerfile 中的多个地位应用常量,并且想在当前更改其值,则能够在一个地位进行更改。

图:环境

对于 Dockerfiles,通常能够通过多种形式实现同一件事。针对您的案例,最好的办法是均衡 Docker 约定、透明性和速度。例如,RUN、CMD 和 ENTRYPOINT 具备不同的用处,并且均可用于执行命令。

RUN

RUN 在构建时创立一个层。每次运行后,Docker 都会提交映像的状态。

RUN 通常用于将软件包装置到映像中 在下面的示例中,RUN apk update && apk upgrade 通知 Docker 从根底映像更新软件包 && apk add bash 通知 Docker 将 bash 装置到映像中。

apk 代表 Alpine Linux 软件包管理器。如果您应用的是 Alpine 以外的其余版本的 Linux 根底映像,则应应用 RUN apt-get 而不是 apk 装置软件包。apt 代表高级包工具。在前面的示例中,我将探讨安装包的其余办法。

图:跑

RUN 及其同级命令 CMD 和 ENTRYPOINT 能够在 exec 表单或 shell 表单中应用。Exec form 应用的 JSON 数组语法如下:

例如:RUN ["my_executable", "my_first_param1", "my_second_param2"]

在下面的示例中,咱们应用格局为的 shell 模式 RUN apk update && apk upgrade && apk add bash

稍后在 Dockerfile 中,咱们应用首选的 exec 模式 RUN ["mkdir", "/a_directory"] 创立目录。别忘了对 exec form 应用 JSON 语法的字符串应用双引号!

COPY

COPY . ./app 指令通知 Docker 在本地构建上下文中获取文件和文件夹,并将它们增加到 Docker 映像的当前工作目录中。如果不存在,复制将创立目标目录。

图:复制

ADD

ADD 与 COPY 执行雷同的操作,但有两个以上的用例。ADD 可用于将文件从近程 URL 挪动到容器,ADD 能够提取本地 TAR 文件。

我在下面的示例中应用 ADD 将文件从近程 URL 复制到容器的 my_app_directory 中 。Docker 文档不倡议以这种形式应用近程 URL,因为您无奈删除这些文件。额定的文件会减少最终图像的大小。

Docker 文档还倡议尽可能应用 COPY 而不是 ADD 来进步清晰度。Docker 没有将 ADD 和 COPY 合并到一个命令中,以缩小 Dockerfile 指令的数量来放弃直线,这太蹩脚了。

留神,ADD 指令蕴含 \ 换行符,应用它能够通过将一条长指令拆分成几行来进步可读性。

CMD

CMD 向 Docker 提供了一个在容器启动时运行的命令。它不会在构建时将命令的后果提交给映像。在下面的示例中,CMD 将使 Docker 容器在运行时运行 my_ script.py 文件。

图:那是 CMD!

无关 CMD 的其余几件事:

  • 每个 Dockerfile 仅一个 CMD 指令。否则,除最初一个以外的所有内容都将被疏忽。
  • CMD 能够蕴含一个可执行文件。如果存在没有可执行文件的 CMD,则必须存在 ENTRYPOINT 指令。在这种状况下,CMD 和 ENTRYPOINT 指令都应为 JSON 格局。
  • 命令行参数将 docker run 笼罩 Dockerfile 中提供给 CMD 的参数。

筹备好了吗?

让咱们在另一个 Dockerfile 示例中介绍更多阐明。

FROM python:3.7.2-alpine3.8 
LABEL maintainer="jeffmshale@gmail.com" 
# Install dependencies 
RUN apk add --update git 
# Set current working directory 
WORKDIR /usr/src/my_app_directory 
# Copy code from your local context to the image working directory 
COPY . . 
# Set default value for a variable 
ARG my_var=my_default_value 
# Set code to run at container run time 
ENTRYPOINT ["python", "./app/my_script.py", "my_var"] 
# Expose our port to the world 
EXPOSE 8000 
# Create a volume for data storage 
VOLUME /my_volume 

请留神,您能够在 Dockerfiles 中应用正文。正文以 # 结尾。
软件包装置是 Dockerfiles 的次要工作。如前所述,有几种办法能够应用 RUN 装置软件包。

您能够应用 apk 在 Alpine Docker 映像中装置软件包,apk 就像惯例 Linux 构建中的 apt-get。例如,带有根本 Ubuntu 映像的 Dockerfile 中的软件包能够像这样更新和装置:RUN apt-get update && apt-get install my_package

除了 apk 和 apt-get 之外 ,还能够通过 pip,wheel 和 conda 装置 Python 软件包。其余语言能够应用各种安装程序。

根底层须要向装置层提供相干的软件包管理器。如果您在装置软件包时遇到问题,请在装置软件包管理器之前尝试应用它们。

您能够将 RUN 与 pip 一起应用,并在 Dockerfile 中间接列出要装置的软件包。如果这样做,则将您的软件包装置到一条指令中,并用换行符()将其离开。与多个 RUN 指令相比,此办法提供了清晰度和更少的层数。

或者,您能够在文件中列出软件包要求,而后在该文件上运行软件包管理器。人们通常将文件命名为 requirements.txt。我将在下一篇文章中分享一个举荐的模式,以利用 build.ca 缓存与 requirements.txt 一起应用。

WORKDIR

WORKDIR 会更改容器中的工作目录,以供前面的 COPY、ADD、RUN、CMD 和 ENTRYPOINT 指令应用。几点注意事项:

  • 最好应用 WORKDIR 设置绝对路径,而不是应用 Dockerfile 中的 cd 命令在文件系统中导航。
  • 如果该目录不存在,则 WORKDIR 会主动创立该目录。
  • 您能够应用多个 WORKDIR 指令。如果提供了相对路径,则每个 WORKDIR 指令都会更改当前工作目录。

图:某种工作目录

ARG

ARG 定义了一个在构建时从命令行传递到映像的变量。能够在 Dockerfile 中为 ARG 提供默认值,如示例所示:ARG my_var=my_default_value

与 ENV 变量不同,ARG 变量不适用于运行中的容器。然而,在生成映像时,能够应用 ARG 值在命令行中为 ENV 变量设置默认值。而后,ENV 变量在容器运行期间始终存在。

ENTRYPOINT

ENTRYPOINT 指令还容许您在容器启动时提供默认命令和参数。它看起来与 CMD 类似,然而如果应用命令行参数运行容器,则 ENTRYPOINT 参数不会被笼罩。

而是将传递给的命令行参数 docker run my_image_name 附加到 ENTRYPOINT 指令的参数中。例如,docker run my_image bash 将参数 bash 增加到 ENTRYPOINT 指令的现有参数的开端。

图:进入某处

Dockerfile 应该至多具备一个 CMD 或 ENTRYPOINT 指令。

Docker 文档中有一些对于在 CMD 和 ENTRYPOINT 之间抉择初始容器命令的倡议:

  • 当您 须要每次运行 相 同 的 命令时,请 抉择 ENTRYPOINT。
  • 当 容器 将 用作可执行程序时,首选入口点。
  • 当您 须要提供 额定的默认参数,能够从命令行 重写 时,应用 CMD。

在下面的示例中,ENTRYPOINT ["python", "my_script.py", "my_var"] 让容器在容器开始运行时运行带有参数 my_var 的 python 脚本 my_script.py。 而后,my_script 能够 通过 argparse 应用 my_var。请留神,my_var 具备 ARG 先前在 Dockerfile 中提供的默认值。因而,如果未从命令行传递参数,则将应用默认参数。

Docker 建议您通常应用 ENTRYPOINT:的 exec 模式 ENTRYPOINT ["executable", "param1", "param2"]。这种模式是应用 JSON 数组语法的模式。

EXPOSE

EXPOSE 指令显示要公布哪个端口以提供对正在运行的容器的拜访。EXPOSE 实际上不会公布端口。相同,它充当构建映像的人员与运行容器的人员之间的文档。

图:裸露

docker run-p 标记一起应用,以在运行时公布和映射一个或多个端口。大写 -P 标记将公布所有公开的端口。

VOLUME

VOLUME 指定您的容器将在哪里存储和 / 或拜访持久数据。

图:卷

总结

Dockerfile 兴许是 Docker 把握的要害组件。我心愿本文能帮忙到你们。

退出移动版