文章目录
- 一. docker引擎介绍
- 1. Docker daemon:实现Docker API,通过API管理容器
- 2. containerd:负责容器的生命周期
- 3. runc:用于创建和启动容器
- 二. 启动容器的过程
- 1. 启动过程
- 2. docker daemon的维护不会影响到运行中的容器
- 3. shim:让容器独立于docker daemon
一. docker引擎介绍
docker基于OCI的开放标准,引擎采用模块化设计
。
- OCI 规范定义了容器镜像的格式,使得不同的工具和平台能够创建、分享和运行容器镜像而不受限于特定的实现。兼容 OCI 镜像格式的系统可以使用标准化的镜像文件进行容器部署。
- OCI 还定义了容器运行时的规范,确保容器能够在任何支持 OCI 运行时规范的环境中启动和运行。这使得容器的运行不依赖于特定的实现或平台。
Docker引擎的组成
Docker引擎由如下主要的组件构成:Docker客户端(Docker Client)、Docker守护进程(Docker daemon)、containerd以及runc。它们共同负责容器的创建和运行。如下图:
1. Docker daemon:实现Docker API,通过API管理容器
Docker daemon:
- Docker daemon实现了Docker API,Docker API 是 Docker 提供的应用编程接口,允许开发者通过编程方式与 Docker 引擎进行交互。
- Docker daemon中的功能包括但不限于API、镜像管理、身份认证、安全特性、核心网络以及卷。
- daemon使用一种CRUD风格的API,通过gRPC与containerd进行通信。
Docker API 的作用包括:
1. 容器管理
创建和启动容器:通过 API,可以程序化地创建新的容器并启动它们。例如,
通过 POST /containers/create 和 POST /containers/(id or name)/start。
停止和删除容器:可以通过 POST /containers/(id or name)/stop 停止容器,
通过 DELETE /containers/(id or name) 删除容器。
2. 镜像管理
拉取和推送镜像:可以使用 API 拉取新的镜像(POST /images/create)或将镜像推送到 Docker 仓库(POST /images/(name)/push)。
列出和删除镜像:通过 GET /images/json 列出本地镜像,通过 DELETE /images/(name) 删除镜像。
3. 网络管理
创建和删除网络:可以通过 API 创建新的网络(POST /networks/create)或删除现有网络(DELETE /networks/(id))。
管理网络设置:可以查看网络配置和连接状态(GET /networks/(id))。
4. 卷管理
创建和删除卷:通过 API 可以创建新的数据卷(POST /volumes/create)或删除现有卷(DELETE /volumes/(name))。
查看卷信息:可以获取卷的详细信息(GET /volumes/(name))。
5. 日志和监控
获取容器日志:可以获取特定容器的日志输出(GET /containers/(id or name)/logs),帮助调试和监控容器运行状态。
查看容器状态:通过 GET /containers/(id or name)/json 获取容器的详细状态信息。
6. 系统信息
查看 Docker 版本:通过 GET /version 获取 Docker 引擎的版本信息。
获取系统统计信息:通过 GET /system/df 获取 Docker 使用的磁盘空间统计信息。
7. 安全性和权限
管理访问权限:API 可以用于设置和管理 Docker 引擎的访问权限,控制不同用户或应用的操作权限。
8. 自动化和集成
与 CI/CD 工具集成:Docker API 允许在持续集成和持续部署(CI/CD)流程中自动化容器的构建、测试和部署。
自定义管理工具:开发者可以使用 Docker API 创建自定义的管理界面或工具,以满足特定的业务需求。
使用场景
- 自动化管理:通过 API 可以编写脚本或程序自动化容器的创建、启动、停止等操作。
- 集成和扩展:将 Docker 功能集成到现有的应用程序或系统中,比如在云平台、监控工具或开发环境中。
- 自定义应用:构建自定义的用户界面或控制面板,提供更符合业务需求的容器管理功能。
2. containerd:负责容器的生命周期
containerd 是 Docker 的一个核心组件,主要用于容器的运行时管理。它负责以下几个方面:
- 容器生命周期管理:启动、停止、删除容器。
- 容器镜像管理:拉取、存储和管理容器镜像。
- 资源管理:管理容器的资源分配和限制。
- 日志管理:处理容器的日志输出。
3. runc:用于创建和启动容器
runc是OCI容器运行时规范的参考实现,它使用与OCI兼容的bundle(2?)来启动容器。runc生来只有一个作用——创建容器!
Docker使用runc作为其默认的容器运行时
- containerd调用runc,并确保Docker镜像以OCI bundle的格式交给runc。
- runc可以作为独立的CLI工具来创建容器。它基于Libcontainer(3?),也可被其他项目或第三方工具使用。
二. 启动容器的过程
下面的docker container run命令会基于alpine:latest镜像启动一个新容器。
$ docker container run --name ctr1 -it alpine:latest sh
1. 启动过程
当使用Docker命令行工具执行如上命令时,
- Docker客户端会将其转换为合适的API格式,并发送到正确的API端点(3?)。
- 一旦daemon接收到创建新容器的命令,它就会向containerd发出调用。daemon已经不再包含任何创建容器的代码了。
- containerd指导runc启动容器:containerd不负责创建容器,而是指挥runc去做。containerd将Docker镜像转换为OCI bundle,并让runc基于此创建一个新的容器。
- runc与操作系统内核接口进行通信,基于所有必要的工具(Namespace、CGroup等)来创建容器。容器进程作为runc的子进程启动,启动完毕后,runc将会退出。
现在,容器启动完毕了。如下图容器启动过程:
2. docker daemon的维护不会影响到运行中的容器
为什么对于docker daemon的维护和升级不会影响到运行中的容器
因为Docker将所有的用于启动、管理容器的逻辑和代码从daemon中移除,意味着容器运行时与Docker daemon是解耦的,有时称之为“无守护进程的容器(daemonless container)”,所以,对Docker daemon的维护和升级工作不会影响到运行中的容器。
在旧模型中,所有容器运行时的逻辑都在daemon中实现,启动和停止daemon会导致宿主机上所有运行中的容器被杀掉。这在生产环境中是一个大问题——想一想新版Docker的发布频次吧!每次daemon的升级都会杀掉宿主机上所有的容器。
3. shim:让容器独立于docker daemon
上图展示了shim组件。shim是将运行中的容器与daemon解耦(,以便daemon进行升级等操作)不可或缺的工具。
containerd指挥runc来创建新容器。事实上,每次创建容器时它都会fork一个新的runc实例。不过,一旦容器创建完毕,对应的runc进程就会退出。因此,即使运行上百个容器,也无须保持上百个运行中的runc实例。
一旦runc退出,相关联的containerd-shim进程就会成为容器的父进程。作为容器的父进程,shim用于管理容器与容器运行时之间的通信。它主要承担以下功能:
- 保持所有STDIN和STDOUT流是开启状态,从而当daemon重启的时候,容器不会因为管道(pipe)的关闭而终止;
- 容器进程管理:shim 负责启动和管理容器内的主进程,并确保容器进程在后台正确运行。
- 日志转发:将容器的标准输出和错误日志转发到 Docker 引擎或日志系统。
- 容器终止处理:处理容器的正常或异常退出,并将退出状态报告给 daemon。
- 生命周期管理:支持容器的启动、停止、重启等操作,确保容器生命周期的正常管理。
在 Docker 中,shim 的作用是让容器进程独立于 Docker 守护进程,使得容器可以更稳定地运行,同时也提供了更好的隔离和资源管理。