万字长文:彻底搞懂容器镜像构建

本文深入 Docker 源码,探讨镜像构建的原理,包括 Docker 架构、API 请求详解、CLI 客户端行为、Builder v1 和 Buildkit 的构建过程,以及服务端 dockerd 的工作原理。通过对 CLI 和服务端的逐步分析,揭示 Docker 镜像构建的完整流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

大家好,我是张晋涛。

我将在这篇文章中深入 Docker 的源码,与你聊聊镜像构建的原理。

文章过长,目录如下:

Docker 架构

这里我们先从宏观上对 Docker 有个大概的认识,它整体上是个 C/S 架构;我们平时使用的 docker 命令就是它的 CLI 客户端,而它的服务端是 dockerd 在 Linux 系统中,通常我们是使用 systemd 进行管理,所以我们可以使用 systemctl start docker 来启动服务。(但是请注意,dockerd 是否能运行与 systemd 并无任何关系,你可以像平时执行一个普通的二进制程序一样,直接通过 dockerd 来启动服务,注意需要 root 权限)

实际上也就是

Docker 架构

(图片来源:docker overview)

docker CLI 与 dockerd 的交互是通过 REST API 来完成的,当我们执行 docker version 的时候过滤 API 可以看到如下输出:

➜  ~ docker version |grep API
 API version:       1.41
  API version:      1.41 (minimum version 1.12)

上面一行是 docker CLI 的 API 版本,下面则代表了 dockerd 的 API 版本,它的后面还有个括号,是因为 Docker 具备了很良好的兼容性,这里表示它最小可兼容的 API 版本是 1.12 。

对于我们进行 C/S 架构的项目开发而言,一般都是 API 先行, 所以我们先来看下 API 的部分。

当然,本文的主体是构建系统相关的,所以我们就直接来看构建相关的 API 即可。

接下来会说 CLI,代码以 v20.10.5 为准。最后说服务端 Dockerd 。

API

Docker 维护团队在每个版本正式发布之后,都会将 API 文档发布出来,可以通过 Docker Engine API 在线浏览,也可以自行构建 API 文档。

首先 clone Docker 的源代码仓库, 进入项目仓库内执行 make swagger-docs 即可在启动一个容器同时将端口暴露至本地的 9000 端口, 你可以直接通过 http://127.0.0.1:9000 访问本地的 API 文档。

(MoeLove) ➜  git clone https://github.com/docker/docker.git docker
(MoeLove) ➜  cd docker
(MoeLove) ➜  docker git:(master) git checkout -b v20.10.5 v20.10.5
(MoeLove) ➜  docker git:(v20.10.5) make swagger-docs
API docs preview will be running at http://localhost:9000

打开 http://127.0.0.1:9000/#operation/ImageBuild 这个地址就可以看到 1.41 版本的构建镜像所需的 API 了。我们对此 API 进行下分析。

请求地址和方法

接口地址是 /v1.41/build 方法是 POST ,我们可以使用一个较新版本的 curl 工具来验证下此接口(需要使用 --unix-socket 连接 Docker 监听的 UNIX Domain Socket )。dockerd 默认情况下监听在 /var/run/docker.sock ,当然你也可以给 dockerd 传递 --host 参数用于监听 HTTP 端口或者其他路径的 unix socket .

/ # curl -X POST --unix-socket /var/run/docker.sock  localhost/v1.41/build 
{"message":"Cannot locate specified Dockerfile: Dockerfile"}

从上面的输出我们可以看到,我们确实访问到了该接口,同时该接口的响应是提示需要 Dockerfile .

请求体

A tar archive compressed with one of the following algorithms: identity (no compression), gzip, bzip2, xz. string

请求体是一个 tar 归档文件,可选择无压缩、gzipbzip2xz 压缩等形式。关于这几种压缩格式就不再展开介绍了,但值得注意的是 如果使用了压缩,则传输体积会变小,即网络消耗会相应减少。但压缩/解压缩需要耗费 CPU 等计算资源 这在我们对大规模镜像构建做优化时是个值得权衡的点。

请求头

因为要发送的是个 tar 归档文件,Content-type 默认是 application/x-tar 。另一个会发送的头是 X-Registry-Config,这是一个由 Base64 编码后的 Docker Registry 的配置信息,内容与 $HOME/.docker/config.json 中的 auths 内的信息一致。

这些配置信息,在你执行 docker login 后会自动写入到 $HOME/.docker/config.json 文件内的。这些信息被传输到 dockerd 在构建过程中作为拉取镜像的认证信息使用。

请求参数

最后就是请求参数了,参数有很多,通过 docker build --help 基本都可以看到对应含义的,这里不再一一展开了,后面会有一些关键参数的介绍。

小结

上面我们介绍了 Docker 构建镜像相关的 API,我们可以直接访问Docker Engine 的 API 文档。或者通过源码仓库,自己来构建一个本地的 API 文档服务,使用浏览器进行访问。

通过 API 我们也知道了该接口所需的请求体是一个 tar 归档文件(可选择压缩算法进行压缩),同时它的请求头中会携带用户在镜像仓库中的认证信息。这提醒我们, 如果在使用远程 Dockerd 构建时,请注意安全,尽量使用 tls 进行加密,以免数据泄漏。

CLI

API 已经介绍完了,我们来看下 docker CLI,我以前的文章中介绍过现在 Docker 中有两个构建系统,一个是 v1 版本的 builder 另一个是 v2 版本的即 BuildKit 我们来分别深入源码来看看在构建镜像时,他们各自的行为吧。

准备代码

CLI 的代码仓库在 https://github.com/docker/cli 本文的代码以 v20.10.5 为准。

通过以下步骤使用此版本的代码:

(MoeLove) ➜  git clone https://github.com/docker/cli.git
(MoeLove) ➜  cd cli
(MoeLove) ➜  cli git:(master) git checkout -b v20.10.5 v20.10.5
逐步分解

docker 是我们所使用的客户端工具,用于与 dockerd 进行交互。关于构建相关的部分, 我们所熟知的便是 docker build 或者是 docker image build,在 19.03 中新增的是 docker builder build ,但其实他们都是同一个只是做了个 alias 罢了:

// cmd/docker/docker.go#L237
if v, ok := aliasMap["builder"]; ok {
    aliases = append(aliases,
        [2][]string{
   {"build"}, {v, "build"}},
        [2][]string{
   {"image", "build"}, {v, "build"}},
    )
}

真正的入口函数其实在 cli/command/image/build.go;区分如何调用的逻辑如下:

func runBuild(dockerCli command.Cli, options buildOptions) error {
 buildkitEnabled, err := command.BuildKitEnabled(dockerCli.ServerInfo())
 if err != nil {
  return err
 }
 if buildkitEnabled {
  return runBuildBuildKit(dockerCli, options)
 }
    // 省略掉了对于 builder 的实际逻辑
}

这里就是判断下是否支持 buildkit

// cli/command/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张晋涛-MoeLove

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值