Docker源码分析
Docker架构图及各模块功能与实现的分析
docker架构图
docker Client
Client是Docker架构中用户与Docker Daemon建立通信的工具。在一个安装docker的平台上,用户运行Client去使用Docker。
Client与Daemon之间的通讯有三种方式:
- tcp://host:port
- unix://path_to_socket
- fd://socketfd
当Client向Daemon发送容器管理请求时,请求在Daemon处理后,会返回一个消息,当Client收到这个响应并做一些简单处理后。Client的一次完整的生命周期就结束了。
Docker Daemon
Daemon是docker架构中常驻在后台的系统进程。它的作用主要有以下两个方面:
- 接受并处理Client发送来的请求。
- 管理所有的Docker容器。
Daemon运行时,后台会启动一个HTTP Server,该Server负责接收Client发送来的请求;接收请求后,Server通过路由与调度器,找到对应的Handler。
Docker Server
在Daemon启动中,DockerServer是第一个完成启动的。它通过Go语言包gorilla/mux
创建了一个mux.Router
路由器。
创建号mux.Router
后,Docker Server添加有效的路由项,每一个路由项是由HTTP请求方式、URL以及对应的Handler三部分构成。
当Daemon每收到来自Client的请求后,都会创建一个goroutine来进行请求的后续操作及其响应。在goroutine中,会首先读取请求内容,然后做解析工作,接着找到对应的路由项,在路由项中找到对应的Handler,然后执行Handler,当Handler处理完请求后,会进行响应工作,返回给Client一个回复。
观察前文的Docker Daemon架构图,发现其中有一些名为Job
的项,它们在架构上的作用和Docker Server不同的。其实,Docker Server和Job的本质是一样的,Server是通过一个名为serverapi
的Job实现的。
Engine
Engine是Docker架构中的运行引擎,在它其中,保存着大量的容器的信息,以及管理着众多的Job。Docker中大部分的操作都要Engine来协助完成。
在Docker源码中,Engine相关的数据结构定义在一个名为Handlers的对象中。该对象中存储着众多Job各自的Handler。
例如:handlers中有一项为 {"create": daemon.ContainerCreate}
,则说明这个是执行名为create的操作,具体的操作方法则为daemon.ContainerCreate。
Engine还会帮助Daemon在退出前进行准备工作。
Job
Job可以理解为Engine中运行的最基本的工作执行单元。Daemon每一项可以完成的工作都是一个Job。
例如,在Docker中运行一个进程,这就是一个Job;创建一个容器,这是一个Job;创建Server的HTTP的API,这也是一个Job。
Job的设计与Unix进程非常相似,有标准的输入(Stdin)输出(Stdout)及其标准错误(Stderr),并且通过使用Run()可以执行Job本身。