Docker源码分析-第1章-Docker架构(1)

1.1 引⾔

Docker是Linux平台上的⼀款轻量级虚拟化容器的管理引擎。在全
球范围内,Docker还是⼀个开源项⽬,整个项⽬基于Go语⾔开发,代码托管于GitHub⽹站上,并遵从Apache 2.0协议。⽬前,Docker可以帮助⽤户在容器内部快速⾃动化部署应⽤,并利⽤Linux内核特性命名空间(namespaces)及控制组(cgroups)等为容器提供隔离的运⾏环境。Docker借助操作系统层的虚拟化实现资源的隔离,因此Docker容器在运⾏时与虚拟机(VM)的运⾏有很⼤的区别,Docker容器与宿主机共享同⼀个操作系统,不会有额外的操作系统开销。这样的优势很明显,因⽽⼤⼤提⾼了资源利⽤率,并且提升了I/O等⽅⾯的性能。

众多新颖的特性以及项⽬本⾝的开放性,导致Docker在不到两年的时间⾥迅速获得了诸多⼚商的⻘睐,其中更是包括Google、Microsoft 、 VMware 等 ⾏ 业 领 航 者 。Google 在 2014 年 6 ⽉ 推 出 了Kubernetes,宣布⽀持Docker容器的调度管理,⽽2014年8⽉Microsoft则宣布Azure上⽀持Kubernetes,随后传统虚拟化巨头VMware宣布与Docker强强合作。2014年9⽉中旬,Docker更是获得4000万美元的C轮融资,以推动分布式应⽤的发展。

⽬前,Docker的前景被普遍看好。未来的云计算领域乃⾄整个IT
领域,Docker都必将扮演不可或缺的⾓⾊。为了帮助⼤家更好地认识Docker、理解Docker并掌握Docker,本书从Docker源码的⾓度出发,详细介绍Docker的架构、Docker的运⾏以及Docker的特性。本章主要介绍Docker架构。

本章⽬的是在理解Docker源码的基础上分析Docker架构,分析过程主要按照以下三个部分进⾏:
·Docker的总架构图。
·Docker架构内部各模块功能与实现的分析。
·通过具体的Docker命令,阐述Docker的运⾏流程。

1.2 Docker总架构图

作为Linux平台上的⼀种容器的管理引擎,Docker并不像其他⼤型
分布式系统那样复杂。Docker的源码总量并不多,⽽且清晰的源码结构使得Docker的学习成本并不⾼。换⾔之,Docker源码的学习过程并不枯燥,我们可以从中学到很多东⻄,如Go语⾔的运⽤、Docker架构的设计原理等。Docker对⽤户⽽⾔是⼀个简单的C/S架构,⽤户通过客户端与服务器端建⽴通信,⽽Docker的后端是⼀个松耦合的架构,架构中的模块各司其职、有机组合,⽀撑着Docker运⾏。Docker 的 总 架 构 如 图 1-1 所 ⽰ 。架 构 中 主 要 的 模 块 有 :DockerClient 、 DockerDaemon 、 Docker Registry 、 Graph 、 Driver 、libcontainer以及Docker Container。对⽤户⽽⾔,Docker Client是与Docker Daemon建⽴通信的最佳途径。⽤户通过Docker Client发起容器的管理请求,请求最终发往DockerDaemon。Docker Daemon作为Docker架构中的主体部分,⾸先具备服务端的功能,有能⼒接收Docker Client发起的请求;其次具备Docker Client请求的处理能⼒。Docker Daemon内部所有的任务均由Engine来完成,且
每⼀项⼯作都以⼀个Job的形式存在。Docker Daemon需要完成的任务很多,因此Job的种类也很多。若⽤户需要下载容器镜像,Docker Daemon则会创建⼀个名为“pull”的Job,运⾏时从Docker Registry中下载镜像,并通过镜像管理驱动graphdriver将下载的镜像存储在graph中;若⽤户需要为Docker容器创建⽹络环境,Docker Daemon则会创建⼀个名“allocate_interface”的Job,通过⽹络驱动networkdriver分配⽹络接⼝的资源……

libcontainer是⼀套独⽴的容器管理解决⽅案,这套解决⽅案涉及了⼤量Linux内核⽅⾯的特性,如:namespaces、cgroups以及capabilities等。libcontainer很好地抽象了Linux的内核特性,并提供完整、明确的接⼝给Docker Daemon。当⽤户执⾏运⾏容器这个命令之后,⼀个Docker容器就处于运⾏状态,该容器拥有隔离的运⾏环境、独⽴的⽹络栈资源以及受限的资源等。

1.3 Docker各模块功能与实现分析
下⾯我们将从Docker的总架构图⼊⼿,抽离出架构内的各个模
块,并对各个模块进⾏更为细化的架构分析与功能阐述。

1.3.1 Docker Client
Docker Client是Docker架构中⽤户与Docker Daemon建⽴通信的客户端。在⼀台安装有Docker的机器上,⽤户可以使⽤可执⾏⽂件docker作为Docker Client,发起众多Docker容器的管理请求。Docker Client可以通过以下三种⽅式和Docker Daemon建⽴通信,分别为:tcp://host:port、unix://path_to_socket和fd://socketfd。为简单起⻅,本书主要使⽤第⼀种⽅式作为讲述两者通信的原型。通信⽅式确定后,DockerClient与Docker Daemon建⽴连接并传输请求时,可以通过命令⾏flag参数的形式,设置安全传输层协议(TLS)的有关参数,保证传输的安全性。Docker Client发送容器管理请求后,请求由Docker Daemon接收并处理,当Docker Client接收到返回的请求响应并做简单处理后,DockerClient⼀次完整的⽣命周期就此结束。若需要继续发送容器管理请求,⽤户必须再次通过可执⾏⽂docker创建Docker Client,并⾛完以上相同的流程。

1.3.2 Docker Daemon
Docker Daemon是Docker架构中⼀个常驻在后台的系统进程。所谓的“运⾏Docker”,即代表运⾏Docker Daemon。总之,DockerDaemon的作⽤主要有以下两⽅⾯:
·接收并处理Docker Client发送的请求。
·管理所有的Docker容器。
Docker Daemon运⾏时,会在后台启动⼀个Server,Server负责接收Docker Client发送的请求;接收请求后,Server通过路由与分发调度,找到相应的Handler来处理请求。启动Docker Daemon所使⽤的可执⾏⽂件同样是docker,与DockerClient启动所使⽤的可执⾏⽂件docker相同。既然Docker Client与DockerDaemon都可以通过docker⼆进制⽂件创建,那么如何辨别两者就变得⾮常重要。实际上,执⾏docker命令时,通过传⼊的参数可以辨别Docker Daemon与Docker Client,如docker–d代表Docker Daemon的启动,dockerps则代表创建Docker Client,并发送ps请求。Docker Daemon的架构⼤致可以分为三部分:Docker Server、Engine和Job。Daemon的架构如图1-2所⽰。1.Docker ServerDocker Server在Docker架构中专门服务于Docker Client,它的功能是接收并调度分发Docker Client发送的请求。Docker Server的架构如图1-3所⽰。

在 Docker Daemon 的 启 动 过 程 中 , DockerServer 第 ⼀ 个 完 成 。Docker Server通过包gorilla/mux,创建了⼀个mux.Router路由器,提供请求的路由功能。在Go语⾔中,gorilla/mux是⼀个强⼤的URL路由器以及调度分发器。创建路由器之后,Docker Server为mux.Router中添加有效的路由项,每⼀个路由项由HTTP请求⽅法(PUT、POST、GET或DELETE)、URL和Handler三部分组成。

由 于 Docker Client 通 过 HTTP 协 议 访 问 Docker Daemon ,故DockerServer 创 建 完 mux.Router 之 后 , 将 Server 的 监 听 地 址 以 及mux.Router 作 为 参 数 , 创 建 ⼀ 个 httpSrv=http.Server{} , 最 终 执 ⾏httpSrv.Serve()开始服务于外部请求。

在服务过程中,Docker Server在listener上接收Docker Client的访问请求。对于每⼀个Docker Client请求,DockerServer均会创建⼀个全新的goroutine来服务。在goroutine中,Docker Server⾸先读取请求内容,然后做请求解析⼯作,接着匹配相应的路由项,随后调⽤相应的Handler来处理,最后Handler处理完请求之后给Docker Client回复响应。

需要注意的是:Docker Server在Docker的启动过程中运⾏,通过⼀个名为“serveapi”的Job来实现。理论上,Docker Server的运⾏只是众多Job中的⼀个,但是为了强调Docker Server的重要性以及它为后续Job服务的重要特性,本书将“serveapi”的Job单独抽离出来分析,理解为Docker Server。

2.Engine
Engine是Docker架构中的运⾏引擎,同时也是Docker运⾏的核⼼模块。Engine存储着⼤量的容器信息,同时管理着Docker⼤部分Job的执⾏。换⾔之,Docker中⼤部分任务的执⾏都需要Engine协助,并通过Engine匹配相应的Job完成Job的执⾏。

在Docker源码中,有关Engine的数据结构定义中含有⼀个名为handlers的对象。该handlers对象存储的是关于众多特定Job各⾃的处理⽅ 式 handler 。举 例 说 明 , Engine 的 handlers 对 象 中 有 ⼀ 项 为 :{"create":daemon.ContainerCreate,},则说明当执⾏名为“create”的Job时,执⾏的是daemon.ContainerCreate这个handler。除了容器管理之外,Engine还接管Docker Daemon的某些特定任务。当Docker Daemon遭遇到⾃⾝进程需要退出的情况时,Engine还负责完成DockerDaemon退出前的所有善后⼯作。
3.Job
Job可以认为是Docker架构中Engine内部最基本的⼯作执⾏单元。DockerDaemon可以完成的每⼀项⼯作都会呈现为⼀个Job。例如,在Docker容器内部运⾏⼀个进程,这是⼀个Job;创建⼀个新的容器,这是⼀个Job;在⽹络上下载⼀个⽂档,这是⼀个Job;包括之前在DockerServer部分谈及的,创建Server服务于HTTP协议的API,这也是⼀个Job,等等。

有关Job接⼝的设计,与UNIX进程⾮常相仿。⽐如说,Job有⼀个名称,有运⾏时参数,有环境变量,有标准输⼊与标准输出,有标准错误,还有返回状态等。对于Job⽽⾔,定义完毕之后,运⾏才能完成Job⾃⾝真正的使命。Job的运⾏函数Run()则⽤以执⾏Job本⾝

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BinaryStarXin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值