Docker是一个开源的应用容器引擎。它的理念是“Buildonce, Run anywhere, Configure once, Run anything”,这与Java提出的“Write Once, Run Anywhere”有殊途同归之妙。
Java与Docker在面对平台移植方面的问题时,采用了相似的解决方案。Java语言使用虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成能够在Java虚拟机上运行的目标代码(字节码),就能够在多种平台上不加修改地运行。docker
相似地,Docker使用容器引擎解决平台依赖问题,它在每台宿主机上都启动一个Docker的守护进程,守护进程屏蔽了与具体平台相关的信息,对上层应用提供统一的接口。这样,Docker化的应用,就能够在多个平台下运行,Docker会针对不一样的平台,解析给对应的执行驱动、存储驱动和网络驱动去执行。
这里说的平台主要针对不一样的Linux发行版,由于Docker的实现须要用到Linux的cgroups、namespaces等特性,因此目前只能运行在Linux环境下,要想在Windows和Mac上使用Docker,则要采用虚拟机的方式。网络
此外,Docker还有本身的生态圈,从官方镜像仓库下载的镜像,能够运行在任何装有Docker引擎的操做系统上,开发人员也能够将本身制做的镜像提交的官方仓库供别人使用。还能够搭建私有的镜像仓库。这就相似Android或iOS系统与应用商店的关系。架构
最后,Docker还具备版本控制功能,能够对镜像作修改后提交新的版本、能够在多个版本间快速切换。性能
综上,Docker是一个开源的应用容器引擎,它的应用以镜像的形式存在,Docker经过屏蔽环境的差别,能够方便地让应用在各类环境运行,并且Docker还具备对镜像的版本控制功能。ui
Docker有本身完善的生态圈,整体来讲分为Docker镜像仓库和Docker自身程序两部分。
其中Docker自身程序又分为Server和Client两部分,采用了C/S架构,用Go语言编写。
Docker的Server端又称做Docker Daemon,在宿主机上之后台守护进程的形式运行。Docker Client使用比较灵活,既能够在本机上以bin命令的形式(如Docker info、Docker start)发送指令,也能够在远端经过RESTful API的形式发送指令;Docker的Server端接收指令并把指令分解为一系列任务去执行。spa
当经过Docker client发送docker run指令来建立并启动容器的时候,Docker Daemon首先会检查本地是否有对应的镜像,若是没有就从官方仓库下载,而后基于下载的镜像建立并启动容器,最后把执行结果返回给Docker Client。操作系统
Docker会把软件和它依赖的环境(包括操做系统和共享库等)、依赖的配置文件打包在一块儿,以虚拟机镜像的形式放到官方仓库供别人下载使用。
但操做系统的体积相对软件的体积来讲太大了,为了运行软件,每次都下载配套的操做系统是不现实的。为了解决这个问题,Docker引入了分层的概念。把一个应用分为任意多个层,好比操做系统是第一层,依赖的库和第三方软件是第二层,应用的软件包和配置文件是第三层。若是两个应用有相同的底层,就能够共享这些层。越是处于底部体积大的层,共享的可能也就更大。版本控制
但分层方式还会面临共享层冲突的问题,因此Docker为文件层增长了优先级属性,上层和下层有相同的文件和配置时,上层覆盖下层。好比,应用A须要修改操做系统的某个配置,应用B不须要修改。这时给以应用A增长一个优先级最高的空白层,若是须要修改下层的文件,就把这个文件拷贝到这个空白层进行修改,保证下层的文件不作任何改变,这称为写时拷贝策略。日志
应用A: ====运行的应用====== ======空白层======== =====配置文件======= =====依赖的库======= =====操做系统=======
应用B: ====运行的应用====== =====配置文件======= =====依赖的库======= =====操做系统=======
KVM、Xen、VMWare、VirtualBox等主流的虚拟机通常比较笨重,在运行的时候,虚拟机自己就要消耗大量的系统资源(CPU、内存等),并且这类虚拟机启动时间也比较长,动辄耗时数分钟。
而以OpenVZ、VServer、LXC为表明的容器类虚拟机,是一种内核虚拟化技术,与宿主机运行在相同Linux内核,不须要指令级模拟,性能消耗很是小,是很是轻量级的虚拟化容器,虚拟容器的系统资源消耗和一个普通的进程差很少。Docker就是使用LXC(后来又推出libcontainer)让虚拟机变得轻量化。code
那么镜像与容器是什么关系呢,根据前面的描述得知:镜像指的是以分层的、能够被LXC/libcontainer理解的文件存储格式。Docker的应用都是以这种格式发布到Docker仓库中,供你们使用。而容器则是指:把应用镜像从Docker仓库下载到本地机器上,以镜像为模板,在一个容器类虚拟机中把这个应用启动,这个虚拟机叫就是容器了。
从另外一个角度来讲,镜像和容器能够看做是一个Docker化应用的两种不一样状态。镜像状态时,一个应用只有运行所需的必要文件、程序包等内容,并且应用也处于静止态;而容器状态时,应用要运行起来以对外提供服务,有可能修改文件,好比输出日志、动态更新某个配置等等,这时须要有空白层用于写时拷贝。
利用镜像分层存储的特性,Docker还能够作到灵活的变动管理。
好比一个Docker镜像它的V1.0版本有三层,如今要对它作以下修改:修改位于第一层的文件A;删除位于第二层的文件B;添加一个新文件C。
这时就会增长一个第四层,在这一层作修改:把第一层的文件A拷贝到第四层,修改文件A的内容;在第四层,把名称为B的文件设置为不存在;在第四层,建立一个新文件C。
v1.0: =====第三层 50M===== =====第二层 500M==== =====第一层 1G======
v1.1: ===第四层 修改 1M=== =====第三层 50M===== =====第二层 500M==== =====第一层 1G======
这样修改就完成了,在向仓库发布这个新版本时,由于前三层已经存储在仓库,只须要上传体积很小的第四层就能够了。使用这个镜像的其它机器要升级版本时,一样也只须要从仓库下载第四层。
因而可知这种分层的特性对于Docker的重要意义,利用分层特性,Docker能够作到镜像的增量变动,使得Docker镜像的下载上传变得很是轻量(除了第一次操做)。
参考资料 李金榜 尹烨 刘天斯 陈纯 著 《按部就班学Docker》