8

【Docker—基础】核心概念和架构

 3 years ago
source link: https://segmentfault.com/a/1190000038785571
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

核心概念

镜像

镜像是什么呢?通俗地讲,它是一个只读的文件和文件夹组合。它包含了容器运行时所需要的所有基础文件和配置信息,是容器启动的基础。所以你想启动一个容器,那首先必须要有一个镜像。镜像是 Docker 容器启动的先决条件。

容器

容器是 Docker 的另一个核心概念。通俗地讲,容器是镜像的运行实体。镜像是静态的只读文件,而容器带有运行时需要的可写文件层,并且容器中的进程属于运行状态。即容器运行着真正的应用进程。容器有创建、运行、停止、暂停和删除五种状态。

虽然容器的本质是主机上运行的一个进程,但是容器有自己独立的命名空间隔离和资源限制。也就是说,在容器内部,无法看到主机上的进程、环境变量、网络等信息,这是容器与直接运行在主机上进程的本质区别。

仓库

Docker 的镜像仓库类似于代码仓库,用来存储和分发 Docker 镜像。镜像仓库分为公共镜像仓库和私有镜像仓库。

目前, Docker Hub 是 Docker 官方的公开镜像仓库,它不仅有很多应用或者操作系统的官方镜像,还有很多组织或者个人开发的镜像供我们免费存放、下载、研究和使用。除了公开镜像仓库,你也可以构建自己的私有镜像仓库。

架构

基于开放容器计划(OCI)相关标准的要求,Docker 引擎采用了模块化的设计原则,其组件是可替换的。 Docker引擎由如下主要的组件构成:Docker 客户端(Docker Client)、Docker 守护进程(Docker daemon)、containerd 以及 runc。 它们共同负责容器的创建和运行。

目前Docker引擎的架构示意图如图所示:

QZ7VRf2.png!mobile

Docker客户端

Docker 客户端其实是一种泛称。其中 docker 命令是 Docker 用户与 Docker 服务端交互的主要方式。除了使用 docker 命令的方式,还可以使用直接请求 REST API 的方式与 Docker 服务端交互,甚至还可以使用各种语言的 SDK 与 Docker 服务端交互。

runc

runc 是 OCI 容器运行时规范的参考实现,实质上是一个轻量级的、针对 Libcontainer 进行了包装的命令行交互工具(Libcontainer 取代了早期 Docker 架构中的 LXC)。通俗地讲,runc 是一个用来运行容器的轻量级工具,是真正用来运行容器的。

containerd

containerd 是 Docker 服务端的一个核心组件,它是从 dockerd 中剥离出来的 ,它的主要任务是容器的生命周期管理——start | stop | pause | rm....。随着时间的推移,它被赋予了更多的功能,比如镜像管理。

containerd 位于 dockerd 和 runc 所在的 OCI 层之间,通过 containerd-shim 启动并管理 runc。Kubernetes 也可以通过 cri-containerd 使用 containerd,在Kubernetes中,containerd 是一个很受欢迎的容器运行时。

shim

shim 是实现无 daemon 的容器(用于将运行中的容器与 containerd 解耦,以便进行 dockerd 升级等操作)不可或缺的工具。

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

作为容器的父进程,shim 的部分职责如下:

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

延伸阅读: 从 docker 到 runC

各组件之间的关系

首先通过以下命令来启动一个 busybox 容器:

$ docker run -d busybox sleep 3600

容器启动后,通过以下命令查看一下 dockerd 的 PID:

$ sudo ps aux |grep dockerd


root      4147  0.3  0.2 1447892 83236 ?       Ssl  Jul09 245:59 /usr/bin/dockerd

通过上面的输出结果可以得知 dockerd 的 PID 为 4147。为了 Docker 各组件之间的调用关系,下面使用 pstree 命令查看一下进程父子关系:

$ sudo pstree -l -a -A 4147


dockerd


  |-containerd --config /var/run/docker/containerd/containerd.toml --log-level info


  |   |-containerd-shim -namespace moby -workdir /var/lib/docker/containerd/daemon/io.containerd.runtime.v1.linux/moby/d14d20507073e5743e607efd616571c834f1a914f903db6279b8de4b5ba3a45a -address /var/run/docker/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runc


  |   |   |-sleep 3600

事实上,dockerd 启动的时候, containerd 就随之启动了,dockerd 与 containerd 一直存在。当执行 docker run 命令(通过 busybox 镜像创建并启动容器)时,containerd 会创建 containerd-shim 充当 “垫片” 进程,然后启动容器的真正进程 sleep 3600 。这个过程和架构图是完全一致的。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK