【分享吧】带你初识Docker

一、引言

如今,Docker作为业界领先的轻量级虚拟化容器管理引擎,给全球开发者提供了一种新颖、便捷的软件集成测试与部署之道。Docker借助容器技术彻底释放了轻量级虚拟化技术的威力,让容器的伸缩、应用的运行都变得前所未有的方便与高效。同时借助强大的镜像技术,让应用的分发、部署与管理变得便捷。

二、虚拟化技术的比较

Docker是容器的一种,容器是一种轻量级的虚拟化技术,和容器对应的更为重量级的虚拟化技术是虚拟机。提及虚拟机,大家肯定都不陌生,例如VMware、XenServer这些虚拟化产品早已深入人心。容器的诞生并不是为了替代传统的虚拟化技术,但是它的诞生却让人能够仔细看待传统虚拟化技术的弊病。

虚拟机是一种基于硬件的虚拟化技术。它采用指令级的虚拟,完全虚拟一整套物理机,包含CPU、内存、磁盘、网卡等硬件设备,给用户呈现的就是一个物理主机的特性。用户可以在虚拟机里面安装各种各样的操作系统,例如Windows、Linux、或者是OS X,一切操作都看起来和真机一样。用户可以在一台主机上安装多个虚拟机,每一个实例都完整的包含硬件虚拟层、操作系统、公共库和应用等部件。然而,有时候这并不是我们想要的,因为这样太耗费资源,而且管理也并不方便。当新的需求出现后,自然会驱动新的技术出现,于是后来出现了一种更为轻量级的虚拟化技术——容器。容器是一种基于操作系统的虚拟化技术,它运行在操作系统之上的用户空间,所有容器都像运行在单独的操作系统之上,但又能够共享很多底层资源。比起虚拟机,容器更为轻量、快速、易于管理。除了Docker常见的容器还有Solaris Zones、BSD jails、OpenVZ和LXC等。

图2-1

从图2-1中可以看出,Docker并没用传统虚拟化中的Hypervisor层,其虚拟化技术是基于内核的Cgroup和Namespace技术,处理逻辑与内核深度融合,所以在很多方面,它的性能与物理机非常接近。

容器和虚拟机各有各的优缺点,容器也并不是虚拟机的替代品,只是二者在适应不同需求下各有优点。

1) 虚拟机

优势:

a) 对操作系统具有绝对的权限,对系统版本和升级具有完全的管理权限。

b) 具有一整套的资源:CPU、RAM和磁盘。QoS是有保证的。

劣势:

a) 为保证QoS,使得每一台虚拟机具有更大的负载,耗费更多的资源,因此启动时间也是在数秒至数十秒的量级。

b) 用户需要全权维护和管理。

2) 容器

优势:

a) 效率高,资源占用小,管理便捷,启动时间短,通常是秒级甚至是毫秒级。在需求部署的系统都是同一系列的操作系统时,这种性能和便捷性上的优势非常明显。

劣势:

a) QoS会尽量满足,但不保证一定满足。

b) 对内核没有控制权限,只有容器的提供者具备升级权限。只有一个内核运行在物理节点上,几乎不能实现不同的操作系统混合。容器提供者一般仅提供少数几款操作系统。

三、Docker的组件

Docker采用的是传统的C/S架构,客户端和服务器端统一在同一个二进制文件中,不过这只对于Linux系统而言,在其他平台如Mac上,Docker只提供了客户端。Docker客户端一般通过命令行或RESTful API来发起请求,与Docker守候程序进行通信,Docker守候程序提供Docker服务。

Docker包含三大核心组件——容器、镜像和库。

图3-1

3.1 Docker容器

在Docker的功能和概念中,容器是一个核心内容,相对于传统虚拟化,它作为一项基础技术在性能上给Docker带来了极大的优势。在功能上,通过libcontainer实现对容器生命周期的管理、信息的设置和查询,以及监控和通信等功能。而容器也是对镜像的完美诠释,容器以镜像为基础,同时又为镜像提供了一个标准的和隔离的执行环境。它是一个运行时环境,是一个镜像的运行状态,相对于静态的镜像而言,容器是镜像执行的动态表现。在概念上,容器则很好的诠释了Docker集装箱的理念,用户可以在容器中运行所想要的程序和服务,它并不关心你运行的到底是什么程序,所有应用的运行方式都一样——创建、开始、停止、重启和销毁;容器也不在乎你在什么样的环境中运行它,可以在个人电脑、虚拟机、云服务器、各种操作系统上运行。容器不是一个新的概念,但是Docker在对容器进行封装后,使容器易于交互、便于运输、易移植、易扩展,改变了软件的开发、部署形态,降低成本,提高效率。

3.2 Docker镜像

镜像是一个只读的静态模板。它保存着容器需要的环境和应用的执行代码,可以把镜像看成容器的代码,当代码运行起来后就成了容器。Docker的另一个优势是对层级镜像的创新应用,即不同的容器可以共享底层的只读镜像,通过写入自己特有的内容后添加新的镜像层,新增的镜像层和下层镜像一起又可以作为基础镜像被更上层的镜像使用。这种特性可以极大的提高磁盘利用率,所以当你的系统上有10个大小为1GB的镜像时,它们总共占用的空间大小可能只有5GB,甚至更少。另外Docker对Union mount的应用还体现在多个容器使用同一个基础镜像时,可极大的减少内存使用,因为不同的容器访问同一个文件时,只会占用一份内存。3.3Docket库

Docker采用注册服务器来存储和共享用户的镜像,库是某个特定用户存储镜像的目录。通常一个用户可以建立多个库来保存自己的镜像。库是注册服务器的一部分,一个个的库组成了一个注册服务器。注册服务器有公共和私有的,其中公共的如Docker官方的Docker Hub,这上面提供了大多数常用软件和发行版的官方镜像,还有无数个人用户提供的个人镜像。注册一个账号,你就可以在里面建立自己的镜像库。镜像库可以选择开放,也可以选择私有,仅被允许的组成员才可以访问,多数企业会选择自己部署注册服务器后进行二次开发。

四、Docker基础架构

Docker作为Linux平台上的一种容器管理引擎,Docker并不像其他大型分布式系统那样复杂。Docker对用户而言是一个简单的C/S架构,用户通过客户端与服务器端建立通信,而Docker的后端是一个松耦合的架构,架构中的模块各司其职、有机组合,支撑着Docker运行。

图4-1

Docker的总架构图如图4-1所示。架构中的主要模块有:DockerClient、DockerDaemon、Docker Registry、Graph、Driver、libcontainer以及Docker Container。

4.1 Docker Client

Docker Clinet是Docker架构中用户与Docker Daemon建立通信的客户端。在一台安装有Docker的机器上,用户可以使用可执行文件docker作为Docker Client,发起众多Docker容器的管理请求。

Docker Client 可以通过以下三种方式和Docker Daemon建立通信,分别为:tcp://host:port、unix://path_to_socket和fd://socketfd。Client和Daemon建立连接并传输请求时,可以通过命令行flag参数的形式,设置安全传输层协议(TLS)的有关参数,保证传输的安全性。发送容器管理请求后,请求由Docker Daemon接受并处理,当Docker Client接收到返回的请求响应并作简单处理后,Docker Client一次完整的生命周期就此结束。若需要继续发送容器管理请求,用户必须再次通过可执行文件docker创建Docker Client,并走完以上相同的流程。

4.2 Docker Daemon

Docker Daemon是Docker架构中一个常驻在后台的系统进程。所谓运行Docker就是代表运行Docker Daemon。它主要用于接收并处理Docker Client发送的请求,并管理所有的Docker容器。Docker Daemon的架构如图4-2所示,大致可以分为三个部分:Docker Server、Engine和Job。

图4-2 Docker Daemon

4.2.1 Docker Server

Docker Server在Docker架构中专门服务于Docker Client,它的功能是接受并调度分发客户端发送的请求。

图4-3 Docker Server

在Docker Daemon的启动过程中,Docker Server第一个完成。Docker Server通过包gorilla/mux创建了一个mux.Router路由器,提供请求的路由功能。创建路由器之后,Docker Server为mux.Router中添加路由项,每一个路由项由HTTP请求方法(PUT\POST\GET\DELETE)、URL和Handler三部分组成。Docker Server创建完mux.Router之后,将Server的监听地址以及mux.Router作为参数,创建一个httpSrv=http.Server{}最终执行http.Server{}开始服务于外部请求。

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

4.2.2 Engine

Engine是Docker架构中的运行引擎,同时也是Docker运行的核心模块。Engine存储着大量的容器信息,同时管理着Docker大部分Job的执行。除了容器管理之外,Engine还接管Docker Daemon的某些特定任务。当Docker Daemon遭遇自身进程需要退出的情况时,Engine还负责完成Docker Daemon退出前的所有善后工作。

4.2.3 Job

Job可以认为是Docker架构中Engine内部最基本的工作执行单元。Docker Daemon可以完成的每一项工作都会呈现为一个Job。例如,在容器内部运行一个进程,这是一个job;创建一个新的容器,这是一个job,从网络上下载一个文档,这是一个job;包括之前在Docker Server部分谈及的创建Server服务于HTTP协议的API,也是一个Job等等。

Job有一个名称,有运行时的参数,有环境变量,有标准输入和标准输出,有标准错误,还有返回状态等。对于Job而言,定义完毕之后,运行才能完成Job自身真正的使命。Job的运行函数Run()则用以执行Job本身。

4.3 Docker Registry

Docker Registry是一个存储容器镜像的仓库,它将大量的镜像汇集在一起,并为分散的Docker Daemon提供镜像服务。4.4 Graph

Graph在Docker架构中是镜像的保管着。不论是下载的镜像,还是构建的镜像,均有Graph统一化管理。由于Docker支持多种不同的镜像存储方式,如aufs、devicemapper、Btrfs等,故Graph对镜像的存储也会因以上种类而存在一些差异。对Docker而言,同一种类型的镜像被称为一个repository,如名称为ubuntu的镜像都同属于一个repository;而同一个repository下的镜像则会因tag存在差异而不同,如ubuntu这个repository下有tag为12.04的镜像,也有tag为14.04的镜像。

图4-4 Graph

4.5 Driver

Driver是Docker架构中的驱动模块。通过Driver驱动,Docker可以实现对Docker容器运行环境的定制,定制的维度主要有网络环境、存储方式以及容器执行方式。Driver的实现可以分为以下三种驱动:graphdriver、networkdriver和execdriver。

4.5.1 Graphdriver

Graphdriver主要用于完成容器镜像的管理,包括从远程Docker Registry上下载镜像并进行存储,也包括本地构建完镜像后的存储。

图4-5 Graphdriver

4.5.2 Networkdriver

Networkdriver的作用是完成Docker容器网络环境的配置,其中包括Docker Daemon启动时为Docker环境创建网桥;Docker容器创建前为其分配相应的网络接口资源;以及为Docker容器分配IP、端口并与宿主机做NAT端口映射,设置容器防火墙策略等。

图4-6 Networkdriver

4.5.3 Execdriver

Execdriver作为Docker容器的执行驱动,负责创建容器运行时的命名空间,负责容器资源使用的统计与限制,负责容器内部进程的真正运行等。

图4-7 Execdriver

4.6 libcontainer

libcontainer是Docker架构中一个使用Go语言设计实现的库,Docker可以直接调用libcontainer来操作容器的namespaces、cgroups、apparmor、网络设备以及防火墙等。Libcontainer提供了一整套标准接口来满足上层对容器管理的需求,屏蔽了Docker上层对容器的直接管理。

图4-8 libcontainer

4.7 Docker Container

Docker Container是Docker架构中服务交付的最终体现形式。Docker通过Docker Daemon的管理,libcontainer的执行,最终创建Docker容器。

图4-9 Docker Container

五、总结

通过对Docker架构的学习,可以全面深化对Docker设计、功能与价值的理解。同时在借助Docker实现用户定制的分布式系统时,也能更好的找到已有平台与Docker较为理想的契合点。另外,熟悉Docker现有架构以及设计思想,也能对云计算PaaS领域带来更多的启发,催生出更多创新想法。

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20171218G0HTRJ00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券