程序锅

  • 首页
  • 分类
  • 标签
  • 归档
  • 关于

  • 搜索
基础知识 Etcd LeetCode 计算机体系结构 Kubernetes Containerd Docker 容器 云原生 Serverless 项目开发维护 ELF 深入理解程序 Tmux Vim Linux Kernel Linux numpy matplotlib 机器学习 MQTT 网络基础 Thrift RPC OS 操作系统 Clang 研途 数据结构和算法 Java 编程语言 Golang Python 个人网站搭建 Nginx 计算机通用技术 Git

容器 | Docker 版本号变换及架构变化摘记

发表于 2021-07-11 | 分类于 容器 | 0 | 阅读次数 3589

1. 版本号变换

v1.11.0 --- 14 Apr 2016

v1.11.1 --- 27 Apr 2016

v1.11.2 --- 2 Jun 2016

v1.12.0 --- 29 Jul 2016

v1.12.1 --- 19 Aug 2016

v1.12.2 --- 12 Oct 2016

v1.12.3 --- 27 Oct 2016

v1.12.4 --- 13 Dec 2016

v1.12.5 --- 16 Dec 2016

v1.12.6 --- 11 Jan 2017

v1.13.0 --- 19 Jan 2017

v1.13.1 --- 9 Feb 2017

v17.03.0-ce --- 2 Mar 2017

v17.03.1-ce --- 28 Mar 2017

v17.04.0-ce --- 6 Apr 2017

v17.05.0-ce --- 6 May 2017

......

v18.05.0-ce --- 26 Apr 2018

v18.06.0-ce --- 19 Jul 2018

v18.06.1-ce --- 22 Aug 2018

v18.09.0 --- 8 Nov 2018

v18.09.1 --- 10 Jan 2019

......

v19.03.0 --- 23 Jul 2019

.......

v19.03.5 --- 15 Nov 2019

2. 架构变换

2.1. 最开始

Docker 首次发布时,Docker 引擎由两个核心组件构成:LXC 和 Docker daemon。

  • Docker daemon 是一个单一的二进制文件,包含了诸如 Docker 客户端、Docker API、容器运行时、镜像构建等。
  • LXC 提供了对诸如命名空间(Namespace)和控制组(CGroup)等基础工具的操作能力,它们是基于 Linux 内核的容器虚拟化技术。

2.2. LXC 变成 Libcontainer

Docker 公司开发了名为 Libcontainer 的自研工具,用于替代 LXC。Libcontainer 的目标是成为与平台无关的工具,可基于不同内核为 Docker 上层提供必要的容器交互功能。在 Docker 0.9 版本中,Libcontainer 取代 LXC 成为默认的执行驱动。

2.2.1. Docker 1.2.0 架构讲解

2.3. 拆解 daemon --- 现在的架构

Docker daemon 的整体性带来了越来越多的问题:难于变更、运行越来越慢。之后 Docker 公司开始努力拆解这个大而全的 Docker daemon 进程,并将其模块化。这项任务的目标是尽可能拆解出其中的功能特性,并用小而专的工具来实现它。这些小工具可以被替换,也可以被第三方拿去用于构建其他工具。

这遵循了 UNIX 中得以实践并验证过的一种软件哲学:小而专的工具可以组装成大型工具。

Docker 1.11.0 版本发布后 Docker Daemon 的架构由原来一个模块,被拆分成了 4 个模块:docker、containerd、docker-containerd-shim、docker-runc。关于容器执行和容器运行时的代码已经完全从 daemon 中移除,并重构为小而专的工具,比如容器运行代码就用 runc 实现了。runc 是 OCI 容器运行时标准的参考实现,它的目标就是与 OCI 规范保持一致。

OCI 定义两个容器相关的规范:镜像规范和容器运行时规范。这两个规范在 2017 年 7 月发布了 1.0 版本。但是在 1.0 版本发布之前,Docker 引擎就已经遵循该规范实现了部分功能。

2.3.1. 各个组件

2.3.1.1. daemon

当越来越多的功能从 daemon 中拆解出来并模块化之后,daemon 的主要功能就剩镜像管理、镜像构建、REST API、身份验证、安全、核心网络、卷以及编排等。

2.3.1.2. containerd

Docker daemon 的功能进行拆解后,所有的容器执行逻辑被重构到了 containerd 中。它的主要任务是容器的生命周期管理(start|stop|pause|rm),它可以指挥与 OCI 兼容的容器运行时来创建容器,默认情况下使用 runc。除此之外, containerd 组件还需要确保 Docker 镜像能够以正确的 OCI Bundle 的格式传递给 runc。

containerd 最初被设计为轻量级的小型工具,仅用于容器的生命周期管理。然而,随着时间的推移,它被赋予了更多的功能,比如镜像管理。containerd 额外的功能往往都是模块化的、可选的,便于自行选择所需功能。这样,像 kubernetes 这样的项目在使用 containerd 时,可以自己选择需要包含的功能。

containerd 在 Linux 中是以 daemon 的方式运行(从 1.11 版本之后就这样使用了,因为 containerd 是在 1.11 版本中被拆解出来的)。

containerd 是由 Docker 公司开发,并捐献了云原生计算基金会(Cloud Native Computing Foundation,CNCF)。2017 年 12 月发布了 1.0 版本,具体的发布信息可见 Github 中的 containerd/containerd。

2.3.1.3. shim

containerd 指挥 runc 来创建新容器。那么每次创建容器时都会 fork 一个新的 runc 实例。一旦容器创建完毕,对应的 runc 进程就会退出。一旦容器进程的父进程 runc 退出之后,相关联的 containerd-shim 进程就会成为容器的父进程。因此,即使运行上百个容器,也无须保持上百个运行中的 runc。

shim 的部分职责主要如下:

  • 保持所有 STDIN、STDOUT 流是开启状态,所以当 daemon 重启的时候,容器不会因为管道的关闭而终止,这样的好处就是对 daemon 的维护和升级工作不会影响到运行中的容器。
  • 将容器的退出状态反馈给 daemon。

2.3.1.4. runc

runc 是 OCI 容器运行时规范的参考实现,Docker 公司参与了规范的制定与 runc 的开发。runc 实质上一个轻量级的、针对 Libcontainer 进行了包装的命令行交互工具。

runc 只有一个作用那就是创建容器,它使用与 OCI 兼容的 bundle 来启动容器。runc 是一个 CLI 包装器,实质上就是一个独立的容器运行时工具。因此可以直接下载它并基于源码编译出一个二进制文件,即可拥有一个全功能的 runc。

runc 所在的那一层也称为 OCI 层,关于 runc 的发布信息见 Github opencontainers/runc 库。

上述提到的组件,在 Linux 中系统中都由单独的二进制文件来实现,具体包括 dockerd(Docker daemon)、containerd(containerd)、container-shim(shim)、docker-runc(runc)。通过 ps 命令可以看到上述这些组件的进程,只是有些进程只有在运行容器的时候才可见。

2.3.2. 启动一个新的容器的过程

当使用 Docker 命令行工具执行如下命令时,Docker 客户端会将其转换为合适的 API 格式,并发送到正确的 API 端点。

docker container run -it alpine sh

API 是在 daemon 中实现的(该 API 是一套功能丰富、基于版本的 REST API(也就是 HTTP API),这套 API 已经成为了 Docker 的标志,并且被行业接受成为事实上的容器 API)。

那么,一旦 daemon 接收到创建容器的命令,它就会向 containerd 发出调用(daemon 已经不再包含任何创建容器的代码了)。daemon 使用一种 CRUD 风格的 API,通过 gRPC 与 containerd 进行通信。

这套功能丰富、基于版本的 REST API 已经成为 Docker 的标志,并且被行业接收成为事实上的容器 API。

daemon 进程会监听 /var/run/docker.sock 这个 Unix 套接字文件,来获取来自客户端的 Docker 请求。

contaienrd 并不负责创建容器,而是指挥 runc 去创建容器。container 将 Docker 镜像转换为 OCI bundle,并让 runc 基于此创建一个新的容器。

runc 与操作系统内核接口进行通信,基于所有必要的工具(Namespace、cGroup 等)来创建容器。容器作为 runc 的子进程启动,启动完毕后,runc 将会退出。

整个启动过程如下图所示:

简单来说,docker daemon 就相当于一个服务器,接收客户端传来的数据,之后服务将这个数据发送给 containerd ,由 containerd 来创建管理容器。 daemon 其实就相当于一个接受者,实际管理容器的是 containerd。

2.3.3. 总结

将所有的用于启动、管理容器的逻辑和代码从 daemon 中移除,意味着容器运行时与 Docker daemon 实现了解耦(有时称之为无守护进程的容器)。这样的好处就是对 Docker daemon 的维护和升级工作不会影响到运行中的容器(在最开始的那个版本中,所有容器运行时的逻辑都在 daemon 中实现,启动和停止 daemon 都会导致宿主机上所有运行中的容器被杀掉,这在生产环境中是一个大问题)。

2.3.4. 小记

  • containerd 其实就是负责创建和管理容器的,虽然真正的创建工作由 runc 负责
  • runc 实质上一个轻量级的、针对 Libcontainer 进行了包装的命令行交互工具。

2.4. 巨人的肩膀

  1. 《深入浅出 Docker》
卷死我
dawnguo 微信支付

微信支付

dawnguo 支付宝

支付宝

  • 本文作者: dawnguo
  • 本文链接: /archives/134
  • 版权声明: 本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0 许可协议。转载请注明出处!
# 容器 # Docker
容器 | Containerd 完整介绍
容器 | 容器网络
  • 文章目录
  • 站点概览
dawnguo

dawnguo

215 日志
24 分类
37 标签
RSS
Creative Commons
© 2018 — 2025 程序锅
0%