Docker 容器技术 — 软件架构

目录

容器引擎的构成

首先以 CNCF 的 containerd 容器引擎为例,讲述容器引擎大致的构成。

在这里插入图片描述
上图如果把它分成左右两边的话,可以认为 containerd 提供了两大功能。

  1. runtime,也就是对于容器生命周期的管理。
  2. storage,也就是对一个镜像存储的管理。

按照水平层次来看的话:

  • 第一层是 GRPC,containerd 对于上层来说是通过 GRPC serve 的形式来对上层提供服务的。Metrics 这个部分主要是提供 cgroup Metrics 的一些内容;
  • 下面一层的左边是容器镜像的一个存储,中间是 images、containers,下面是 Metadata,这部分 Matadata 是通过 bootfs 存储在磁盘上面的。右边的 Tasks 是管理容器的容器结构,Events 是对容器的一些操作都会有一个 Event 向上层发出,然后上层可以去订阅这个 Event,由此知道容器状态发生什么变化;
  • 最下层是 Runtimes 层,这个 Runtimes 可以从类型区分,比如 runC 或者是 kata container 之类。

Docker 的组件

在这里插入图片描述

Docker 的软件架构包括:

  • Docker Client:向 Docker Server 进程发起请求,如:build、pull、run 等操作。Docker Client 既可以在访问本地守护(local host)进程,也可以访问远程(remote host)守护进程。
  • Docker Server:侦听 REST API 请求并管理 Docker 对象,例如:镜像,容器,网络和卷。守护程序还可以与其他守护程序通信以管理 Docker 服务。
  • Docker Registry(注册表,仓库注册服务器):存储 Docker Image 的中央仓库。其中 Docker Hub 是任何人都可以使用的 Public Registry,Docker Server 默认配置在 Docker Hub 上查找 Images。个人也可以运行 Private Registry,如果使用 Docker DataCenter,则其中包括 Docker Trusted registry(DTR)。使用 docker pull 或 docker run 指令时,所需的 Image 将从 Docker Server 配置的 Registry 中提取。

注意,仓库(Repository)和注册表(Registry)是有区别的。Registry 上往往存放着多个 Repository,每个 Repository 中又包含了多个Images,每个 Image 有着不同的 Tag(标签)。

在这里插入图片描述

Docker 的软件架构

在这里插入图片描述

从上图可以看出,Docker 主要的模块有:

  • Docker Client
  • Docker Daemon
  • Docker Registry
  • Graph
  • Driver
  • Libcontainer
  • Docker Container

用户使用 Client 与 Daemon 建立通信,并发送请求给后者 Daemon 作为 Docker 的核心,首先提供 Server 来接受 Client 的请求,而后通过 Engine 执行 Docker 内部的一系列工作,每一项工作都是以一个 Job 的形式的存在。

  • 当需要为 Container 提供 Image 时,则从 Registry 中下载镜像,并通过镜像管理驱动 Graphdriver 将下载镜像以 Graph 的形式存储;
  • 当需要为 Container 创建网络环境时,则通过网络管理驱动 Networkdriver 创建并配置 Container 网络环境;
  • 当需要为 Container 限制运行资源或执行用户指令等操作时,则通过 Execdriver 来完成。

而 Libcontainer 则作为一个独立的 Container 管理模块,Networkdriver 以及 Execdriver 都是通过 Libcontainer 来完成对 Container 进行的操作。当执行 docker run 的一系列工作后,一个实际的 Container 就处于运行状态,该 Container 拥有独立的文件系统,独立并且安全的运行环境等。

Docker Client

Docker Client 在 Linux 上表现为一个 docker 可执行文件,当 Client 接收到 Daemon 返回的响应并进行简单处理后,Client 一次完整的生命周期就结束了。Client 可以通过 3 种方式和 Daemon 建立通信:

  1. tcp://host:port
  2. unix:path_to_socket;fd://socketfd
  3. 通过设置命令行参数设置 TLS 连接

Docker Daemon

Docker Daemon 在 Linux 上表现为一个常驻在后台的系统进程,可以通过 systemd 来进行管理,实际上跟 Docker Client 是同一个 docker 可执行文件。

Docker Daemon 可以细分为以下模块:

  • API Server:Daemon 会在后台启动一个 Docker Server,是一个 API Server,基于 Golang 的 Gorilla/Mux 包,接受 Client 发送的请求并路由分发到不同的 Handler 进行处理。

值得注意的是:Docker Server 的启动是靠一个名为 serveapi 的 Job 运行来完成的。所以 Server 的本质是众多 Job 中的一个。

  • Engine:是 Docker 的运行引擎,它扮演 Docker Container 存储仓库的角色,并且通过执行 Job 的方式来操纵管理这些容器。Docker Engine 有两个不同的版本:Docker Engine Enterprise(企业版)和 Docker Engine Community(社区版)。

  • Job:一个 Job 可以认为是 Engine 内部最基本的工作执行单元。Docker 做的每一项工作,都可以抽象为一个 Job。例如:在容器内部运行一个进程,这是一个 Job;创建一个新的容器,这是一个 Job,从 Internet上 下载一个文档,这是一个 Job,等等。Job 的设计者,把 Job 设计得与 Unix Processor 相仿。比如说:Job 有一个名称,有参数,有环境变量,有标准的输入输出,有错误处理,有返回状态等。

在这里插入图片描述

Docker Registry

Docker Registry 是一个存储 Images 的仓库。在 Docker 的运行过程中,Daemon 会与 Registry 通信,并实现搜索镜像、下载镜像、上传镜像三个功能,这三个功能对应的 Job 分别为 search、pul 与 push。

Docker 可以使用公有的 Docker Registry,即:Docker Hub,可以从中找到来自开源项目、软件供应商、乃至个人账户的 Docker Image。同时,Docker 也允许用户构建本地私有的 Docker Registry,这样可以保证容器镜像的获取在内网完成。

Graph

Graph 充当已下载镜像的保管者,以及已下载镜像之间关系的记录者。一方面,Graph 存储着本地具有版本信息的文件系统镜像,另一方面也通过 GraphDB 记录着所有文件系统镜像彼此之间的关系。

其中,GraphDB 是一个构建在 SQLite 之上的小型图数据库,实现了节点的命名以及节点之间关联关系的记录。它仅仅实现了大多数图数据库所拥有的一个小的子集,但是提供了简单的接口表示节点之间的关系。

同时在 Graph 的本地目录中,关于每一个的容器镜像,具体存储的信息有:该容器镜像的元数据,容器镜像的大小信息,以及该容器镜像所代表的具体 Rootfs。

在这里插入图片描述

Driver

Driver 作为驱动模块,Docker 通过 Driver 来实现对 Container 执行环境的定制。可以分为以下三类驱动:

  1. Graphdriver
  2. Networkdriver
  3. Execdriver

Graphdriver

Graphdriver 用于完成 Image 的管理,包括存储与获取。当用户需要下载指定的镜像时,Graphdriver 就将镜像存储在本地的指定目录;当用户需要使用指定的镜像来创建容器的 Rootfs 时,Graphdriver 就从本地镜像存储目录中获取指定的容器镜像。

在 Graphdriver 初始化之前,有 4 种文件系统或类文件系统在其内部注册,它们分别是:

  1. Aufs
  2. Btrfs
  3. Vfs
  4. Devmapper

而 Graphdriver 在初始化之时,通过获取系统环境变量 DOCKER_DRIVER 来提取所使用 Driver 的指定类型。而之后所有的 Graph 操作,都使用该 Driver 来执行。

Graphdriver 的架构如下:

在这里插入图片描述

Networkdriver

Networkdriver 用于完成 Container 网络环境的配置,其中包括:

  • Docker deamon 启动时为其创建 Bridge 网桥;
  • Container 创建时为其创建专属虚拟网卡设备,以及为 Container 分配 IP、Port 并与宿主机做端口映射,设置容器防火墙策略等。

Networkdriver 的架构如下:

在这里插入图片描述

Execdriver

Execdriver 作为 Container 的执行驱动,负责创建 Container 运行时 namespace,负责容器资源使用的统计与限制,负责容器内部进程的真正运行等。

在 Execdriver 实现的初期使用了 LXC Driver 调用 LXC 的接口,来操纵容器的配置以及生命周期,而现在 Execdriver 默认使用 Native 驱动,不再依赖于 LXC。可以通过启动 Daemon 时指定 ExecDriverflag 参数来进行选择,默认为 native。

Execdriver 架构如下:

在这里插入图片描述

Libcontainer

Libcontainer 是 Docker 架构中一个使用 Golang 实现的库,设计初衷是希望该库可以不依靠任何依赖,直接访问 Kernel 中与容器相关的 API。

正是由于 Libcontainer 的存在,Docker 最终得以操纵 Container 的 Namespace、Cgroups、Apparmor、网络设备以及防火墙规则等。这一系列操作的完成都不需要依赖 LXC 或者其他库。

Libcontainer 架构如下:

在这里插入图片描述

Docker 将底层容器运行时剥离出来,实现更好的平台无关性。LibContainer 是对各种容器的抽象,发展为 RunC,并贡献给 OCP 组织作为定义容器环境的标准。

Docker Container

Docker Container 变现为一个运行在 Linux 操作系统之上的容器进程,是 Docker 服务交付的最终形式。

  • 用户通过指定 Image,使得 Container 可以自定义 Rootfs 等文件系统。
  • 用户通过指定计算资源的配额,使得 Container 使用指定的计算资源。
  • 用户通过配置网络及其安全策略,使得 Container 拥有独立且安全的网络环境。
  • 用户通过指定运行的命令,使得 Container 执行指定的工作。

·

猜你喜欢

转载自blog.csdn.net/Jmilk/article/details/108894978