进阶:Dockerfile 高阶使用指南及镜像优化

在上次的 Chat 《高效构建 Docker 镜像的最佳实践》 中,我们重点深入内部介绍了 Docker 镜像是什么;以及构建 Docker 镜像的最佳实践等。本次 Chat 我们来分享 Dockerfile 的高阶使用指南和对构建系统的解读,希望能对你有所帮助。

Dockerfile 高阶使用及新特性解读

通过之前的学习,我们已经知道 Dockerfile 是一种可用于镜像构建,具备特定语法的文本文件。而 Docker 自身在使用此文件进行构建镜像的过程中,遵循其固定的行为。

比如在上次 Chat 提到的缓存

Docker 构建系统中,默认情况下为了加快构建的速度,会将构建过程中的每层都进行缓存,我们建议在编写 Dockerfile 的时候,将更新最为频繁的步骤写到最后面,以避免因为该步骤的内容变更,进而导致后续步骤的缓存失效(缓存的控制是 Docker 固定的行为,我们在之后的 Chat 中会进一步深入内部进行分析)。

而同时,我们通过深入到 Docker 镜像内部,发现了它内部的组织形式,对于镜像而言,它其实是使用配置元信息,将对应内容的层(layer)组织起来的一个集合。

那么在使用 Dockerfile 构建镜像的时候,除了上次 Chat 聊到的内容外,有哪些值得掌握的高级技巧呢? 我们来正式开始本次 Chat 。

打开 BuildKit 支持

在上次 Chat 的最后,我们提到可以通过 BuildKit 以提高构建效率,这里我们来对它进行更加详细的解读和分析。

首先,我们知道 Docker 是一个典型的 C/S 架构模型,我们平时使用的 docker 命令,是它的 CLI 客户端,而它的服务端是 dockerd ,在 Linux 系统中,通常它是由 systemd 进行管理的,我们可以通过 systemctl status docker 查看当前 dockerd 的运行状态。

对于构建镜像而言,它同样是需要将待构建的内容(我们称之为 context),发送给 dockerd,并由 dockerd 的特定模块最终完成构建。

builder

这里我们需要引入一个概念 builder .

builder 就是上面提到的特定模块,也就是说构建内容 context 是由 Docker CLI 发送给 dockerd;并最终由 builder 完成构建。

enter image description here

docker 的顶级命令中,我们可以看到有一个 builder 的命令组。它有一个子命令 prune 用于清理所有构建过程中的缓存。

以下是 Docker 18.09 的输出信息。

/ # docker builder

Usage:  docker builder COMMAND

Manage builds

Commands:
  prune       Remove build cache

Run 'docker builder COMMAND --help' for more information on a command.

而在 Docker 19.03 中,它新增了一个子命令:

/ # docker builder

Usage:  docker builder COMMAND

Manage builds

Commands:
  build       Build an image from a Dockerfile
  prune       Remove build cache

Run 'docker builder COMMAND --help' for more information on a command.

这里新增的这个 build 子命令,其实就是我们平时使用的 docker build 或者是 docker image build,现在将它放到 builder 的子目录下也是为了凸显 builder 的概念。

builder 其实很早就存在于 Docker 当中了,我们之前在使用或者说默认在使用的就是 builder 的 v1 版本(在 Docker 内部也将它的版本号定为 1),但是由于它太久了,有一些功能缺失和不足,由此诞生了 builder 的 v2 版本,该项目被称之为 BuildKit 。

BuildKit

BuildKit 的产生主要是由于 v1 版本的 builder 的性能,存储管理和扩展性方面都有不足(毕竟它已经产生了很久,而且近些年 Docker 火热,问题也就逐步暴露出来了), 所以它的重点也在于解决这些问题,关键的功能列在下面:

  • 支持自动化的垃圾回收
  • 可扩展的构建格式
  • 并发依赖解决
  • 高效的缓存系统
  • 插件化的架构

这些功能我们暂且略过,先回到我们的主线上来。

BuildKit 在 Docker v18.06 版本之后可通过 export DOCKER_BUILDKIT=1 环境变量来设置是否启用。对于 Docker v18.06 需要将 dockerd 也以实现性模式运行。即,修改 /etc/docker/daemon.json 文件,增加 "experimental": true 配置,然后使用 systemctl restart docker 重启 dockerd 。

如果将 /etc/docker/daemon.json 文件中添加以下配置:

{
  "experimental": true,
  "features": {
    "buildkit": true
  }
}

则会默认使用 BuildKit 进行构建,就不再需要指定环境了。

小结

  • 在上面的内容中,我们知道了 Docker 是 C/S 架构,而我们通常使用的 docker 命令便是它的 CLI 客户端,服务端是 dockerd 通常由 systemd 进行管理;
  • 我们介绍了一个概念 builder,它是 Docker 构建系统中的实际执行者;用于将构建的上下文 context 按照 Dockerfile 的描述最终生成 Docker 镜像(image);
  • BuildKit 是 v2 版本的 builder ;
  • 我们可以通过增加 export DOCKER_BUILDKIT=1 的环境变量,或是修改 dockerd 的配置文件来临时启用或者默认启用 BuildKit 作为 builder。

我们来体验一下开启 BuildKit 的镜像构建:

(MoeLove) ➜  ~ docker build -t local/spring-boot:buildkit https://github.com/tao12345666333/spring-boot-hello-world.git
[+] Building 0.2s (0/1)
[+] Building 0.6s (0/1) 
...
[+] Building 6.4s (0/1)
 => [internal] load git source https://github.com/tao12345666333/spring-boot-hello-world.git                6.4s 
 => => # 已初始化空的 Git 仓库于 /var/lib/docker/overlay2/xieo69jwu3qd18uqmuwa6er9l/diff/
         898cc478c6bbec5dab019a36fdfdd2dd172cee9erefs/heads/master
[+] Building 394.0s (12/12) FINISHED
 => [internal] load git source https://github.com/tao12345666333/spring-boot-hello-world.git                6.4s 
 => [internal] load metadata for docker.io/library/openjdk:8-jre-alpine                                     3.6s
 => [internal] load metadata for docker.io/library/maven:3.6.1-jdk-8-alpine                                 3.3s 
 => CACHED [stage-2 1/2] FROM docker.io/library/openjdk:8-jre-alpine@sha256:f362b165b870ef129cbe730f29065f  0.0s
 => => resolve docker.io/library/openjdk:8-jre-alpine@sha256:f362b165b870ef129cbe730f29065ff37399c0aa8bcab  0.0s
 => [builder 1/6] FROM docker.io/library/maven:3.6.1-jdk-8-alpine@sha256:16691dc7e18e5311ee7ae38b40dcf98e  14.3s
 => => resolve docker.io/library/maven:3.6.1-jdk-8-alpine@sha256:16691dc7e18e5311ee7ae38b40dcf98ee1cfe4a48  0.0s
 => => sha256:e4ef40f7698347c89ee64b2e5c237d214cae777f33735c52039824eb44feb796 2.18MB / 2.18MB              2.7s
...
 => => extracting sha256:c2274a1a0e2786ee9101b08f76111f9ab8019e368dce1e325d3c284a0ca33397                   0.7s
 => [builder 2/6] WORKDIR /app                                                                              0.3s
 => [builder 3/6] COPY pom.xml /app/                                                                        0.0s
 => [builder 4/6] RUN mvn dependency:go-offline                                                           352.4s
 => [builder 5/6] COPY src /app/src                                                                         0.1s
 => [builder 6/6] RUN mvn -e -B package                                                                    16.3s
 => [stage-2 2/2] COPY --from=builder /app/target/gs-spring-boot-0.1.0.jar /                                0.1s

                        
收藏 收藏
分享
购买文章 ¥7.99