反骨仔

一个业余的 .NET Core 攻城狮

0%

05 Docker 引擎

5.1 Docker 引擎 – 简介

Docker 引擎是用来运行和管理容器的核心组件。通常人们会简单地将其代指为 Docker 或 Docker 平台。

基于开放容器计划(OCI)标准,Docker 引擎采用了模块化的设计原则,其组件是可替换的。

Docker 引擎就像汽车引擎 – 二者都是模块化的,并且由许多可交换的部件组成。

Docker 引擎主要组件构成:

  • Docker 客户端(Docker Client)

  • Docker 守护进程(Docker daemon)

  • containerd

  • runc

Docker总体逻辑

5.2 Docker 引擎 – 详解

Docker 引擎核心组件:

  • LXC
  • Docker daemon

Docker daemon 是单一的二进制文件,包含 Docker 客户端、Docker API、容器运行时、镜像构建等。

LXC 提供了对命名空间(Namespace)和控制组(CGroup)等基础工具的操作能力,它们是基于 Linux 内核的容器虚拟化技术。

先前的Docker架构

5.2.1 摆脱 LXC

LXC 的问题?

  • 基于 Linux,无法跨平台
  • 它属于核心组件,如果依赖于外部工具,会给项目带来巨大风险

后来,使用自研工具 Libcontainer 替代 LXC。

5.2.2 摒弃大而全的 Docker daemon

Docker daemon 的整体性所带来的问题:

  • 难于变更
  • 运行越来越慢

解决方案:

拆解进程,从而将其模块化。这项任务的目标是尽可能拆解出其中的功能特性,并用小而专的工具来实现。

UNIX 的软件哲学:小而专的工具可以组装为大型工具。

Docker引擎的架构

5.2.3 开放容器计划(OCI)的影响

OCI 定义的规范(标准):

  • 镜像规范
  • 容器运行时规范

于 2017 年 7 月发布了 1.0 版。

5.2.4 runc

runc 是 OCI 容器运行时规范的参考实现。

runc 实质上是一个轻量级的、针对 Libcontainer 进行了包装的命令行交互工具。

runc 的作用:创建容器

  • 它是一个 CLI 包装器
  • 它是一个独立的容器运行时工具

runc 所在的那一层称为“OCI 层”。

5.2.5 containerd

主要包含容器的执行逻辑,主要任务是容器的生命周期管理。

5.2.6 启动一个新的容器(示例)

启动一个新容器

1
docker container run --name ctrl -it alpine:latest sh

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

API 是在 daemon 中实现的。

一旦 daemon 接收到创建新容器的命令,就后悔向 containerd 发出调用命令。

启动新容器的过程

5.2.7 该模型的显著优势

将所有的用于启动、管理容器的逻辑和代码从 daemon 中移除,意味着容器运行时与 Docker daemon 是解耦的。对 Docker daemon 的维护和升级工作不会影响到运行中的容器。

在旧模型中,所有容器运行时的逻辑都在 daemon 中实现,启动和停止 daemon 会导致宿主机上所有运行中的容器被杀掉。这在生产环境中是一个大问题。

5.2.8 shim

部分职责:

  • 保持所有 STDIN 和 STDOUT 流是开启状态,从而当 daemon 重启时,容器不会因为管道(pipe)的关闭而终止
  • 将容器的退出状态反馈给 daemon

5.2.9 daemon 的作用

当前,daemon 的主要功能包括镜像管理、镜像构建、REST API、身份验证、安全、核心网络以及编排。

5.3 本章小结

基于 OCI 的标准,Docker 引擎目前采用模块化设计。

Docker daemon 实现了 Docker API,基于 HTTP。

对容器的操作由 containerd 完成。

containerd 需要指挥与 OCI 兼容的容器运行时来创建容器。

runc 可以作为独立的 CLI 工具来创建容器。

目前仍然有许多的功能是在 Docker daemon 中实现。多数功能接下来会一步步进行拆解,进行模块化。

参考