Docker是PaaS提供商dotCloud开源的一个基于LXC的高级容器引擎,源代码托管在Github上,基于go语言并遵从Apache2.0协议开源。Docker近期非常火热,无论是从github上的代码活跃度,还是Redhat在RHEL6.5中集成对Docker的支持,就连Google家的ComputeEngine也支持docker在其之上运行,最近百度也用Docker作为其PaaS的基础(不知道规模多大)。一款开源软件能否在商业上成功,很大程度上依赖三件事-成功的usercase,活跃的社区和一个好故事。dotCloud自家的PaaS产品建立在docker之上,长期维护且有大量的用户,社区也十分活跃,接下来我们看看docker的故事。环境管理复杂-从各种OS到各种中间件到各种app,一款产品能够成功作为开发者需要关心的东西太多,且难于管理,这个问题几乎在所有现代IT相关行业都需要面对云计算时代的到来-AWS的成功,引导开发者将应用转移到cloud上,解决了硬件管理的问题,然而中间件相关的问题依然存在(所以openstackHEAT和AWScloudformation都着力解决这个问题)。开发者思路变化提供了可能性。虚拟化手段的变化-cloud时代采用标配硬件来降低成本,采用虚拟化手段来满足用户按需使用的需求以及保证可用性和隔离性。然而无论是KVM还是Xen在docker看来,都在浪费资源,因为用户需要的是高效运行环境而非OS,GuestOS既浪费资源又难于管理,更加轻量级的LXC更加灵活和快速LXC的移动性-LXC在linux2.6的kernel里就已经存在了,但是其设计之初并非为云计算考虑的,缺少标准化的描述手段和容器的可迁移性,决定其构建出的环境难于迁移和标准化管理(相对于KVM之类image和snapshot的概念)。docker就在这个问题上做出实质性的革新。这正式笔者第一次听说docker时觉得最独特的地方。面对上述几个问题,docker设想是交付运行环境如同海运,OS如同一个货轮,每一个在OS基础上的软件都如同一个集装箱,用户可以通过标准化手段自由组装运行环境,同时集装箱的内容可以由用户自定义,也可以由专业人员制造。这样,交付一个软件,就是一系列标准化组件的集合的交付,如同乐高积木,用户只需要选择合适的积木组合,并且在最顶端署上自己的名字(最后个标准化组件是用户的app)。这也就是基于docker的PaaS产品的原型。WhatDockerCanDo在docker的网站上提到了docker的典型场景:AutomatingthepackaginganddeploymentofapplicationsCreationoflightweight,privatePAASenvironmentsAutomatedtestingandcontinuousintegration/deploymentDeployingandscalingwebapps,databasesandbackendservices由于其基于LXC的轻量级虚拟化的特点,docker相比KVM之类最明显的特点就是启动快,资源占用小。因此对于构建隔离的标准化的运行环境,轻量级的PaaS(如dokku),构建自动化测试和持续集成环境,以及一切可以横向扩展的应用(尤其是需要快速启停来应对峰谷的web应用)。1.构建标准化的运行环境,现有的方案大多是在一个baseOS上运行一套puppet/chef,或者一个image文件,其缺点是前者需要baseOS许多前提条件,后者几乎不可以修改(因为copyonwrite的文件格式在运行时rootfs是readonly的)。并且后者文件体积大,环境管理和版本控制本身也是一个问题。2.PaaS环境是不言而喻的,其设计之初和dotcloud的案例都是将其作为PaaS产品的环境基础3.因为其标准化构建方法(buildfile)和良好的RESTAPI,自动测试和持续集成/部署能够很好的集成进来4.因为LXC轻量级的特点,其启动快,而且docker能够只加载每个container变化的部分,这样资源占用小,能够在单机环境下与KVM之类的虚拟化方案相比能够更加快速和占用更少资源WhatDockerCanNOTDoDocker并不是全能的,设计之初也不是KVM之类虚拟化手段的替代品,个人简单总结了几点1.Docker是基于Linux64bit的,无法在windows/unix或32bit的linux环境下使用(虽然64-bit现在很普及了)2.LXC是基于cgroup等linuxkernel功能的,因此container的guest系统只能是linuxbase的3.隔离性相比KVM之类的虚拟化方案还是有些欠缺,所有container公用一部分的运行库4.网络管理相对简单,主要是基于namespace隔离5.cgroup的cpu和cpuset提供的cpu功能相比KVM的等虚拟化方案相比难以度量(所以dotcloud主要是安内存收费)6.docker对disk的管理比较有限7.container随着用户进程的停止而销毁,container中的log等用户数据不便收集针对1-2,有windowsbase应用的需求的基本可以pass了;3-5主要是看用户的需求,到底是需要一个container还是一个VM,同时也决定了docker作为IaaS不太可行。针对6,7虽然是docker本身不支持的功能,但是可以通过其他手段解决(diskquota,mount--bind)。总之,选用container还是vm,就是在隔离性和资源复用性上做tradeoff另外即便docker0.7能够支持非AUFS的文件系统,但是由于其功能还不稳定,商业应用或许会存在问题,而AUFS的稳定版需要kernel3.8,所以如果想复制dotcloud的成功案例,可能需要考虑升级kernel或者换用ubuntu的server版本(后者提供deb更新)。我想这也是为什么开源界更倾向于支持ubuntu的原因(kernel版本)DockerUsage由于篇幅所限,这里就不再展开翻译,可参见链接-由于篇幅所限,这里就不再展开翻译,可参见链接-核心解决的问题是利用LXC来实现类似VM的功能,从而利用更加节省的硬件资源提供给用户更多的计算资源。同VM的方式不同,LXC其并不是一套硬件虚拟化方法-无法归属到全虚拟化、部分虚拟化和半虚拟化中的任意一个,而是一个操作系统级虚拟化方法,理解起来可能并不像VM那样直观。所以我们从虚拟化要docker要解决的问题出发,看看他是怎么满足用户虚拟化需求的。用户需要考虑虚拟化方法,尤其是硬件虚拟化方法,需要借助其解决的主要是以下4个问题:隔离性-每个用户实例之间相互隔离,互不影响。硬件虚拟化方法给出的方法是VM,LXC给出的方法是container,更细一点是kernelnamespace可配额/可度量-每个用户实例可以按需提供其计算资源,所使用的资源可以被计量。硬件虚拟化方法因为虚拟了CPU,memory可以方便实现,LXC则主要是利用cgroups来控制资源移动性-用户的实例可以很方便地复制、移动和重建。硬件虚拟化方法提供snapshot和image来实现,docker(主要)利用AUFS实现安全性-这个话题比较大,这里强调是host主机的角度尽量保护container。硬件虚拟化的方法因为虚拟化的水平比较高,用户进程都是在KVM等虚拟机容器中翻译运行的,然而对于LXC,用户的进程是lxc-start进程的子进程,只是在Kernel的namespace中隔离的,因此需要一些kernel的patch来保证用户的运行环境不会受到来自host主机的恶意入侵,dotcloud(主要是)利用kernelgrsecpatch解决的.LinuxNamespace(ns)LXC所实现的隔离性主要是来自kernel的namespace,其中pid,net,ipc,mnt,uts等namespace将container的进程,网络,消息,文件系统和hostname隔离开。pidnamespace之前提到用户的进程是lxc-start进程的子进程,不同用户的进程就是通过pidnamespace隔离开的,且不同namespace中可以有相同PID。具有以下特征:1.每个namespace中的pid是有自己的pid=1的进程(类似/sbin/init进程)2.每个namespace中的进程只能影响自己的同一个namespace或子namespace中的进程3.因为/proc包含正在运行的进程,因此在container中的pseudo-filesystem的/proc目录只能看到自己namespace中的进程4.因为namespace允许嵌套,父namespace可以影响子namespace的进程,所以子namespace的进程可以在父namespace中看到,但是具有不同的pid正是因为以上的特征,所有的LXC进程在docker中的父进程为docker进程,每个lxc进程具有不同的namespace。同时由于允许嵌套,因此可以很方便的实现LXCinLXCnetnamespace有了pidnamespace,每个namespace中的pid能够相互隔离,但是网络端口还是共享host的端口。网络隔离是通过netnamespace实现的,每个netnamespace有独立的networkdevices,IPaddresses,IProutingtables,/proc/net目录。这样每个container的网络就能隔离开来。LXC在此基础上有5种网络类型,docker默认采用veth的方式将container中的虚拟网卡同host上的一个dockerbridge连接在一起。ipcnamespacecontainer中进程交互还是采用linux常见的进程间交互方法(interprocesscommunication-IPC),包括常见的信号量、消息队列和共享内存。然而同VM不同,container的进程间交互实际上还是host上具有相同pidnamespace中的进程间交互,因此需要在IPC资源申请时加入namespace信息-每个IPC资源有一个唯一的32bitID。mntnamespace类似chroot,将一个进程放到一个特定的目录执行。mntnamespace允许不同namespace的进程看到的文件结构不同,这样每个namespace中的进程所看到的文件目录就被隔离开了。同chroot不同,每个namespace中的container在/proc/mounts的信息只包含所在namespace的mountpoint。utsnamespaceUTS(“UNIXTime-sharingSystem”)namespace允许每个container拥有独立的hostname和domainname,使其在网络上可以被视作一个独立的节点而非Host上的一个进程。usernamespace每个container可以有不同的user和groupid,也就是说可以以container内部的用户在container内部执行程序而非Host上的用户。有了以上6种namespace从进程、网络、IPC、文件系统、UTS和用户角度的隔离,一个container就可以对外展现出一个独立计算机的能力,并且不同container从OS层面实现了隔离。然而不同namespace之间资源还是相互竞争的,仍然需要类似ulimit来管理每个container所能使用的资源-LXC采用的是cgroup。参考文献1h