docker1:引擎

引言

我的电脑是windows,当我构建jenkin时,考虑了很多方法,包括使用java,docker,其中java构建失败,docker构建成功,但当我进一步在docker下使用jenkins时,我发现网络上多数docker教程并不深入,我遇到了很多很多的问题,包括docker的守护进程是什么,docker的命令执行过程是什么?本文将为你解惑docker技术。

我为什么使用docker

docker有着更快的运行速度,有着更完美的虚拟化技术,但这不是我们使用它的原因,我们经常会遇到以下这种情况,软件不兼容,程序无法移植等问题,这实在是鞋底的石头,解决它要费很多时间,不解决它却不能继续行走。

%title插图%num

docker的虚拟化技术提供了思路,只要您安装好docker,就可以在docker中配置开发环境,比如python,jenkins,甚至是ubuntu系统,配置过程全程无障碍。

%title插图%num

docker宏观技术

docker是一种建立在操作系统之上的虚拟化技术,这种技术的具体过程是这样的:docker中的软件A需要执行操作a,docker则利用操作系统来实现操作a,更详细一些,软件A其实直接运行在操作系统上,docker并没有使用自己的内核支持软件A的运行。

%title插图%num
%title插图%num

docker就是靠偷内核来运行软件,偷谁的内核?偷操作系统的内核,多个软件一起共享操作系统,对,你没看错!是共享而不是分享,有什么区别呢?

%title插图%num

如果docker是个小偷,他并不坏,因为他把偷来的操作系统救济了三毛(这是个不幸运的小孩,我暂且把他比喻成软件)。多个三毛只能用一个包裹,三毛和三毛间是独立的,这也意味着docker中的软件运行环境相互独立

%title插图%num

好了,到这里进行下总结,docker利用操作系统的内核来运行软件,那么通常的虚拟机是怎么做的?他与docker有什么不同?下图左边是docker,右边是虚拟机,虚拟机也是基于操作系统,但他有自己的内核(操作系统B),软件的运行依赖操作系统B,这就是docker为什么快的原因啦。

%title插图%num

docker微观技术

docker采用的是C/S架构,这是一种服务器和客户端的通讯架构,他们有两种通讯模式,如果两者都安装在同一个机器,就没什么好说的了,直接传吧,如果在不同的机器上,则通过socket或者RESTful API来进行通信。服务端(Docker Daemon)就是客服小姐姐,时刻应答着客户端的请求。

%title插图%num

单独谈论下服务端(Docker Daemon),由于小姐姐名子太长,通常叫她另一个名子:守护进程。守护进程是一个完整的小姐姐,实际上她由多个模块组成,这些模块可以被替换,也可以被拿走构建其他工具,这种模块化设计遵循了在 UNIX 中得以实践并验证过的一种软件哲学:小而专的工具可以组装为大型工具。

以前的守护进程是一个大整体,这项拆解和重构守护进程的工作仍在进行中,目前所有容器执行和容器运行时的代码已经完全从Docker Daemon中移除,并重构为小而专的工具—Docker引擎(engine)详解:http://c.biancheng.net/view/3137.html

%title插图%num

总结一下,现在你们知道了docker是C/S架构,守护进程和客户端之前存在通讯,守护进程是由多个可替换模块组成。接下来,我将讲解docker命令的执行过程。

  1. 使用Docker客户端执行创建容器命令,Docker 客户端会将其转换为合适的 API格式(API在daemon中实现)
  2. daemon接收到创建新容器的命令,它就会向containerd发出调用。daemo不包含任何创建容器的代码!
  3. containerd将Docker镜像转换为OCI bundle,并让runc基于此创建一个新的容器。
  4. runc与操作系统内核接口进行通信,基于所有必要的工具(Namespace、CGroup等)来创建容器。容器进程作为runc的子进程启动,启动完毕后,runc退出。
%title插图%num

上面这个过程取自:c语言中文网http://c.biancheng.net/view/3137.html

如果你觉得上面的图太生硬的话,可以把命令看成一个排球,客户端发出排球给Daemon,但是Daemon身边没有代码,他必须把球丢给contained大哥,contained大哥可以执行,但他和操作系统比较生疏,操作系统大哥不会卖他的面子,于是contained不得不把球传给runc小弟,让runc小弟向操作系统要资源,完成容器的创建。

需要注意的是,每次创建容器时contained大哥都会 fork 一个新的 runc 小弟,一旦容器创建完毕,对应的 runc 进程就会退出。因此,即使运行上百个容器,也无须保持上百个运行中的 runc 小弟。

%title插图%num

眼尖的观众可能会发现,我们没有提到shim大哥,他是这场球赛的裁判吗?事实上,每一个命令都要有Daemon小姐姐来接收,但小姐姐很忙的,不可能24小时追踪这个命令,而此时,老好人shim 出现了,它将运行中的容器与 daemon 解耦,以便进行 daemon 升级等操作,一旦容器进程的父进程 runc 退出,相关联的 containerd-shim 进程就会成为容器的父进程。作为容器的父进程,shim 的部分职责如下。

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

结束语

docker就这点东西?不,远不止这些,今天只是个引子,消化完今天的知识后,请期待下次更新:docker的生命周期镜像,容器,仓库。

更多

霍格沃兹测试学院官网首页:https://testing-studio.com