当前位置: 首页 > 后端技术 > Java

绘制Docker架构图,还有谁不会?

时间:2023-04-02 00:16:07 Java

01Docker的整体架构Docker是C/S模型架构,后端是松耦合架构,各模块各司其职。下图是它的整体架构:1.用户使用DockerClient与DockerDaemon建立通信,向后者发送请求。2.DockerDaemon作为Docker架构的主体部分,首先提供了DockerServer的功能,使其能够接受来自DockerClient的请求。3DockerEngine在Docker内部执行一系列作业,每个作业以Job的形式存在。4在Job运行过程中,当需要容器镜像时,从DockerRegistry下载镜像,通过镜像管理驱动Graphdriver将下载的镜像以Graph的形式存储。5当需要为Docker创建网络环境时,通过网管驱动Networkdriver创建并配置Docker容器网络环境。6当需要限制Docker容器的运行资源或执行用户指令等操作时,通过Execdriver完成。7Libcontainer是一个独立的容器管理包。Networkdriver和Execdriver都是通过Libcontainer实现对容器的具体操作。02Docker各模块组件解析2.1DockerClient“发起请求”1DockerClient是与DockerDaemon建立通信的客户端。用户使用的可执行文件是docker(一个命令行可执行文件)。docker命令使用后续参数的形式来实现一个完整的请求命令(例如:dockerimages,docker是不可变命令,images是可变参数)。2DockerClient可以通过以下三种方式与DockerDaemon建立通信:tcp://host:port、unix://pathtosocket和fd://socketfd3DockerClient发送容器管理请求后,DockerDaemon接受并处理该请求,当DockerClient收到并响应返回的请求并简单处理后,DockerClient一个完整的生命周期就结束了。(一个完整的请求:发送请求→处理请求→返回结果),与传统的C/S架构请求流程没有区别。2.2DockerDaemon(后台守护进程)Dockerdaemon架构图DockerServer架构图1DockerServer相当于C/S架构的服务器。功能是接受和调度DockerClient发送的请求。DockerServer接受请求后,通过路由和分发调度找到对应的Handler执行请求。2Docker在启动过程中,通过包gorilla/mux创建了一个mux.Router,提供请求的路由功能。gorilla/mux是Golang中功能强大的URL路由器和调度程序。mux.Router中添加了很多路由项,每个路由项由三部分组成:HTTP请求方法(PUT、POST、GET或DELETE)、URL、Handler。3创建mux.Router后,Docker以服务器的监听地址和mux.Router为参数,创建一个httpSrv=http.Server{},最后执行httpSrv.Serve()为请求服务。4在DockerServer的服务过程中,DockerServer在listener上接受DockerClient的访问请求,并创建一个全新的goroutine来为请求服务。在goroutine中,首先读取请求内容并做解析工作,然后找到对应的路由项并调用对应的Handler处理请求,最后Handler处理完请求后回复请求。2.3DockerEngine5DockerEngine是Docker架构中的运行引擎,也是Docker运行的核心模块。它扮演着一个DockerContainer存储仓库的角色,通过执行Jobs来操作和管理这些容器。6在设计和实现DockerEngine数据结构的过程中,有一个Handler对象。Handler对象存储特定Job的所有Handler处理访问。例子:DockerEngine的Handler对象中有一项:{“create”:daemon.ContainerCreate,},意思是当名为“create”的Job运行时,会执行daemon.ContainerCreate的Handler。Job1Job可以认为是Docker架构中DockerEngine内部最基本的工作执行单元。Docker可以做的每一个工作都可以抽象成一个Job。例如:在容器内运行进程是一项工作;创建一个新容器是一项工作。DockerServer的运行进程也是一个名为ServeApi的Job。2作业的设计者将作业设计为类似于Unix进程。例如:Job有名称、参数、环境变量、标准输入输出、错误处理、返回状态。2.4DockerRegistry(镜像注册中心)1DockerRegistry是存放容器镜像的仓库(注册中心),可以理解为云镜像仓库。按Repository分类,dockerpull根据[repository]:[tag]精确定义一个具体的Image。2Docker运行过程中,DockerDaemon会与DockerRegistry通信,实现搜索镜像、下载镜像、上传镜像三个功能。这三个功能对应的工作名称分别是:“search”、“pull”和“push”。3DockerRegistry可以分为公共仓库(DockerHub)和私有仓库。2.5Graph“DockerInternalDatabase”GraphArchitectureDiagramRepository1下载镜像(包括下载镜像和通过Dockerfile构建的镜像)的保管者。2一个Repository代表某种类型的镜像仓库(例如:Ubuntu),同一个Repository中的镜像通过Tag来区分(代表同一类镜像的不同标签或版本)。一个Registry包含多个Repositories,一个Repository包含多个相同类型的Images。3镜像存储类型有Aufs、Devicemapper、Btrfs、Vfs等,其中CentOS7.x以下版本使用Devicemapper存储类型。4同时,在Graph的本地目录中存储了每个容器镜像的具体信息,包括:容器镜像的元数据、容器镜像的大小信息、容器镜像所代表的具体rootfs。GraphDB1是下载的容器镜像之间关系的记录器。2GraphDB是建立在SQLite之上的小型数据库,实现了节点的命名和节点间关系的记录。2.6Driver“执行部分”Driver是Docker架构中的驱动模块。通过Driver驱动,Docker可以实现Docker容器执行环境的定制化。即Graph负责图片存储,Driver负责容器执行。GraphdriverGraphdriver架构图1Graphdriver主要用于完成容器镜像的管理,包括存储和获取。2存储:通过dockerpull下载的镜像,由Graphdriver存储在指定的本地目录(Graph中)。3获取:dockerrun(create)使用镜像创建容器时,Graphdriver从本地Graph获取镜像。NetworkdriverNetworkdriverArchitectureDiagramNetworkdriver的目的是完成Docker容器网络环境的配置,包括:在Docker启动时为Docker环境创建网桥。Docker容器在创建时会为其创建一个专用的虚拟NIC设备。Docker容器分配IP、端口并与宿主机进行端口映射,设置容器防火墙策略等。ExecdriverExecdriverArchitecture图1Execdriver作为Docker容器的执行驱动,负责创建容器运行命名空间,统计和限制容器资源的使用,以及容器内部进程的实际运行。2现在Execdriver默认使用Native驱动,不依赖LXC。2.7Libcontainer“函数库”Libcontainer架构图1Libcontainer是Docker架构下用Go语言设计实现的库。设计的初衷是希望库可以直接访问内核中容器相关的API,而不需要依赖任何依赖。2Docker可以直接调用Libcontainer来操作容器的Namespace、Cgroups、Apparmor、网络设备、防火墙规则。3Libcontainer提供了一套标准的接口来满足上层对容器管理的需求。也就是说,Libcontainer屏蔽了Docker上层直接管理容器的功能。2.8DockerContainer《服务交付的终极形态》DockerContainer架构1DockerContainer(Docker容器)是Docker架构中服务交付的最终形态。2、Docker根据用户的需求和指令定制相应的Docker容器:用户指定容器镜像,这样Docker容器就可以定制rootfs等文件系统。用户通过指定计算资源的配额,使Docker容器使用指定的计算资源。用户通过配置网络及其安全策略,使Docker容器拥有独立、安全的网络环境。用户通过指定要运行的命令,使Docker容器执行指定的工作。附:本文根据《docker源码分析》整理。