码迷,mamicode.com
首页 > 其他好文 > 详细

【翻译】Dockerfile参考

时间:2019-11-04 20:04:45      阅读:114      评论:0      收藏:0      [点我收藏+]

标签:tgt   osi   情况   文档   复制   增量   提交   match   存在   

Dockerfile参考

来自docker官方网址:https://docs.docker.com/engine/reference/builder/

docker能够从Dockerfile中读取指令并自动构建一个镜像。Dockerfile是一个文本文档,它包含用户可以在命令行上调用的所有命令来组装一个镜像。使用docker构建,用户可以创建一个连续执行多个命令行指令的自动化构建。

这个页面描述了你可以在Dockerfile中使用的命令。读完此页后,请参阅Dockerfile最佳实践(Dockerfile Best Practices)以获得面向tip的指南。

前言

翻译这篇文章前我们先阐述一个重要的概念,那就是上下文(context):docker构建时会将上下文的所有内容(.dockerignore中指定的内容除外)发送到daemon中进行处理。那么如何指定这个上下文呢?我们看一个命令来更容易的理解:

docker build -t xxxxx .

注意这行命令后面有一个.(小点),这个小点的作用不是指定dockerfile的位置,指定dockerfile的位置是用-f参数来指定的,那你以为这个小点是干嘛的?他就是用来指定构建镜像的上下文的。

理解了以上的例子后,我们再看看COPY这个命令的真是含义:

COPY ./package.json /app/

COPY是将源目标复制到镜像中的一个命令,那么上面这个./package.json是指什么路径呢?这并不是要复制执行 docker build 命令所在的目录下的 package.json,也不是复制 Dockerfile 所在目录下的 package.json,而是复制 上下文(context) 目录下的 package.json

用法描述

docker构建命令(docker build)从Dockerfile和上下文构建一个映像。构建的上下文是位于指定位置路径或URL的文件集。路径是本地文件系统上的一个目录。URL是一个Git存储库位置。

上下文会被递归的处理。因此,路径包含任何子目录,URL包含存储库及其子模块。这个例子显示了一个使用当前目录作为上下文的构建命令:

技术图片
$ docker build .
Sending build context to Docker daemon  6.51 MB
...
View Code

构建由Docker守护进程运行,而不是由CLI运行。构建过程要做的第一件事是将整个上下文(递归地)发送给守护进程。在大多数情况下,最好从一个空目录作为上下文开始,并将Dockerfile保存在该目录中。并且只添加构建Dockerfile所需的文件。

警告:不要使用根目录/作为路径,因为它会导致构建将硬盘驱动器的全部内容传输到Docker守护进程。

要在构建上下文中使用文件,Dockerfile引用一条指令中指定的文件,例如一条COPY指令。要提高构建的性能,可以通过向上下文目录添加.dockerignore文件来排除文件和目录。有关如何创建.dockerignore文件的信息,请参阅此页上的文档。 create a .dockerignore file

通常,Dockerfile的文件名称默认就是Dockerfile(首字母D大写),位于上下文的根目录中。在docker build中使用-f标志指向文件系统中任何位置的Dockerfile。

docker build -f /path/to/a/Dockerfile .

您可以指定一个存储库(repository)和用于保存新映像的标记(tag),这会在镜像构建成功之后应用:

 docker build -t shykes/myapp .

要在构建之后将映像标记到多个存储库中,请在运行构建命令时添加多个-t参数:

docker build -t shykes/myapp:1.0.2 -t shykes/myapp:latest .

在Docker守护进程运行Dockerfile中的指令之前,它对Dockerfile进行初步验证,如果语法不正确,则返回一个错误:

$ docker build -t test/myapp .
Sending build context to Docker daemon 2.048 kB
Error response from daemon: Unknown instruction: RUNCMD

Docker守护进程逐个运行Dockerfile中的指令,如果需要,将每个指令的结果提交到一个新镜像中,最后输出新镜像的ID。Docker守护进程将自动清理您发送的上下文。

注意,每条指令都是独立运行的,并且会创建一个新镜像——因此,运行cd /tmp不会对接下来的指令产生任何影响。

只要有可能,Docker将重用中间镜像(缓存),以显著加快Docker的构建过程。这由控制台输出中的Using cache消息表示。(有关更多信息,请参阅Dockerfile最佳实践指南中的Build cache部分 Build cache section):

$ docker build -t svendowideit/ambassador .
Sending build context to Docker daemon 15.36 kB
Step 1/4 : FROM alpine:3.2
 ---> 31f630c65071
Step 2/4 : MAINTAINER SvenDowideit@home.org.au
 ---> Using cache
---> 2a1c91448f5f
Step 3/4 : RUN apk update &&      apk add socat &&        rm -r /var/cache/
 ---> Using cache
---> 21ed6e7fbb73
Step 4/4 : CMD env | grep _TCP= | (sed s/.*_PORT_\([0-9]*\)_TCP=tcp:\/\/\(.*\):\(.*\)/socat -t 100000000 TCP4-LISTEN:\1,fork,reuseaddr TCP4:\2:\3 \&/ && echo wait) | sh
 ---> Using cache
---> 7ea8aef582cc
Successfully built 7ea8aef582cc

构建缓存仅用于具有本地父链(parent chain)的映像。这意味着这些映像是由以前的构建创建的,或者整个映像链是用docker加载的。如果希望使用特定映像的构建缓存,可以使用--cache-from选项指定它。使用--cache-from指定的镜像不需要父链,可以从其他仓库(registries)获取。

完成构建之后,就可以考虑浏览Pushing a repository to its registry

构建工具BuildKit

 

从18.09版本开始,Docker支持一个新的moby/buildkit项目提供的后端来执行构建(build)。与旧的实现相比,BuildKit后端提供了许多优点。例如,BuildKit可以:

  • 检测并跳过未使用的构建阶段(stage)

  • 并行化构建独立的构建阶段

  • 在构建之间只会增量地传输构建上下文中更改的文件

  • 检测并跳过在构建上下文中传输未使用的文件

  • 使用带有许多新特性的外部Dockerfile实现

  • 避免API其余部分的副作用(中间镜像和容器)

  • 为自动修剪(prune)设置构建缓存的优先级

要使用BuildKit后端,您需要在调用docker构建之前在CLI上设置一个环境变量DOCKER_BUILDKIT=1。

要了解基于BuildKit的构建可用的实验性Dockerfile语法,请参考BuildKit存储库中的文档: refer to the documentation in the BuildKit repository.

格式

下面是Dockerfile的格式:

# 注释
指令 参数

指令不区分大小写。但是,习惯上它们是大写的,以便更容易地将它们与参数区分开。

Docker按顺序在Dockerfile中运行指令。Dockerfile必须以“FROM”指令开头。它可能会在解析器指令、注释和全局作用域的参数之后。FROM指令指定要从中构建的父映像。FROM之前可能只有一个或多个ARG指令,它们声明在Dockerfile的FROM行中使用的参数。

Docker将以#开头的行作为注释,行中任何位置的#标记都被视为注释,除非该行是有效的解析器指令。这允许这样的语句:

# Comment
RUN echo we are running some # of cool things

注释中不支持行延续字符。

解析器指令

解析器指令是可选的,并且影响Dockerfile中后续行的处理方式。解析器指令不向构建中添加层,也不会显示为构建步骤。解析器指令被编写为形式# directive=value中的一种特殊类型的注释。单个指令只能使用一次。

一旦一个注释,空的行和构建指令被执行,Docker就不再寻找解析器指令。相反,它将任何格式化为解析器指令的内容视为注释,并且不尝试验证它是否可能是解析器指令。因此,所有解析器指令必须位于Dockerfile的最顶层。

解析器指令不区分大小写。但是,习惯上它们都是小写的。约定还包括任何解析器指令后面的空行。解析器指令不支持行延续字符。

 

由于这些规则,下面的例子都是无效的:

  • 由于行延续无效:

# direc tive=value
  • 无效,因为出现两次:

# directive=value1
# directive=value2

FROM ImageName
  • 由于出现在构建指令之后而被视为注释:
FROM ImageName
# directive=value
  • 由于出现在非解析器指令的注释之后,所以被视为注释:
# About my dockerfile
# directive=value
FROM ImageName
  • 未知指令将被视为注释,因为它不被识别。此外,由于出现在注释之后,已知的指令被视为注释,而注释不是解析器指令。
# unknowndirective=value
# knowndirective=value
  • 解析器指令中允许非断行空白。因此,下列各行均被同等对待:
#directive=value
# directive =value
#    directive= value
# directive = value
#      dIrEcTiVe=value
  • 支持以下解析器指令:
  1. syntax
  2.  escape

syntax

格式:

# syntax=[remote image reference]
# syntax=docker/dockerfile
# syntax=docker/dockerfile:1.0
# syntax=docker.io/docker/dockerfile:1
# syntax=docker/dockerfile:1.0.0-experimental
# syntax=example.com/user/repo:tag@sha256:abcdef...

只有在使用BuildKit后端时该指令才有用。

syntax指令定义用于构建当前Dockerfile的构建器的位置。BuildKit后端允许无缝地使用构建器的外部实现,这些构建器以Docker镜像的形式分发,并在容器沙箱环境中执行。

自定义Dockerfile的实现允许你:

  • 在不用更新后台守护程序的情况下自动的获取错误修正
  • 确保所有用户使用相同的实现来构建Dockerfile
  • 在不升级后台守护程序的情况下获取最新的功能
  • 尝试新的实验性或第三方特性

官方的版本

escape

环境的替换

.dockerignore文件

.dockerignore文件的主旨是要“排除”一些发网daemon的文件,但是里面也有一些逻辑是不排除的,你要先明确这一点。

在docker CLI将上下文发送到docker守护进程之前,它在上下文的根目录中查找一个名为.dockerignore的文件。如果该文件存在,CLI将修改上下文以排除与其中模式匹配的文件和目录。这有助于避免不必要地向守护进程发送大型或敏感的文件和目录,并可能使用ADD或COPY将它们添加到映像中。

CLI将.dockerignore文件解释为一个新行分隔的模式列表,类似于Unix shell的文件globs。为了进行匹配,上下文的根被认为是工作目录和根目录。例如,模式/foo/bar和foo/bar都排除了路径的foo子目录或位于URL的git存储库根目录中名为bar的文件或目录。两者都不排斥其他任何东西。

如果.dockerignore文件中的一行以第1列中的#开始,那么这一行将被视为注释,并在CLI解释之前被忽略。

# comment
*/temp*
*/*/temp*
temp?

该文件导致以下构建行为:

规则行为
# comment 忽略掉.
*/temp* 排除在根目录的任何直接子目录中名称以temp开头的文件和目录。例如,排除了普通文件/somedir/temporary.txt,以及/somedir/temp目录。
*/*/temp* 从根目录下两层的任何子目录中排除以temp开头的文件和目录。例如,/somedir/subdir/temporary.txt被排除。
temp? 排除根目录中名称为temp的单字符扩展名的文件和目录。例如,排除/tempa和/tempb。

使用Go语言的filepath的Match方法来匹配规则。预处理步骤删除开头和结尾的空白并使用Go语言的filepath.Clean方法消除.和. .预处理后为空的行将被忽略。

依赖于filepath.Match提供的规则,Docker使用一个特殊的通配符**来匹配任意数量的目录,比如:**/*.go这个会匹配所有目录中.go扩展名的文件,包括构建的根目录。

以!(感叹号)开始的行可用于排除的例外情况。下面是一个例子,.dockerignore文件使用这个机制:

  *.md
    !README.md

除了README.md外所有的markdown文件都被排除在上下文外了。

放置!的地方影响如下行为:.dockerignore中与特定文件匹配的最后一行决定它是被包含还是被排除。考虑下面的例子:

 *.md
 !README*.md
  README-secret.md

首先所有的markdown文件都被排除了。

在!README*.md下面还有一行 README-secret.md那么结果就是除了这个README-secret.md的所有README开头的markdown文件不会被排除。

在来看下面这个例子:

 *.md
    README-secret.md
    !README*.md

首先所有的markdown文件都被排除了

然后第二行README-secret.md这个可以不写,因为第一行已经指定了规则,它也符合第一行的规则。

第三行又将所有README开头的markdown文件包含了进来,也就是说第二行根本不会起作用了,它指定的这个文件因为第三行的规则会被包括进去。

甚至可以使用.dockerignore文件来排除Dockerfile和.dockerignore文件。这些文件仍然被发送到守护进程,因为守护进程需要它们来完成自己的工作。但是ADD和COPY指令不会将它们复制到镜像。

最后,你可能希望指定要在上下文中包含哪些文件,而不是要排除哪些文件。要实现这一点,将*指定为第一个模式,然后是一个或多个模式!例外模式。

note:作为历史原因你应该了解,.模式被忽略了。

FROM

 

【翻译】Dockerfile参考

标签:tgt   osi   情况   文档   复制   增量   提交   match   存在   

原文地址:https://www.cnblogs.com/pangjianxin/p/11793894.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!