程序员苦了好久。多年前的一个晚上,风暴肆虐之际,一位名叫Docker的青年来到Linux帝国,与帝国的长老们见面。“Linux长老,长期以来全世界的程序员都在为应用部署而苦恼,我想改变这种现状,希望长老能帮帮我。”拜托,我想听听更多关于它的信息。”Docker坐下来开始说:“当今世界,应用程序的开发、测试、部署以及各种库依赖都很复杂,开发环境中经常会出现版本之间的差异。很正常,但是到了测试环境和线上环境,就出现了问题,程序员都深受其害,是时候改变这种情况了。”Docker回头看着长辈说:“我想做一个虚拟容器让应用程序运行在其中,并将它们的依赖环境打包成一个整体,这样移植到不同的机器上后,仍然可以提供一致的运行环境,彻底解放程序员!”闻言,Linux长辈微微点头:“年轻人的想法不错,不过从你的描述来看,虚拟机好像可以解决这个问题。把应用和它依赖的环境部署到虚拟机上,然后拍个快照,直接部署虚拟机,这不就行了吗?”Docker连连摇头:“前辈们不知道,虚拟机体积大如牛,体积大,动不动就是G里的大小。因为它需要在内部运行一个完整的操作系统,所以运行起来异常困难。不说慢,还占用不少资源。如果不能在一台机器上运行几个虚拟机,性能会被拖累!而我想做一个轻量级的虚拟容器,只提供一个运行环境,不需要运行一个操作系统,所有容器里的系统内核还是和外部主机共享的,这样可以批量复制很多容器,又轻又快。”老Linux站起来,来回踱了几步,想了想,突然拍了一张办公桌,大声说:“好主意,我投这个项目!”Docker见状,喜出望外,“这件事真的离不开长辈们的帮助,要达到我说的目的,进程Isolation的管理很重要,希望长辈们帮帮我!”““等一下,”Linux长老转身回到了内室。没多久就出来了,手里拿着一样东西。“小伙子,回去之后就放手努力吧,我教你三招,遇到困难,一一分解,用处很大。”Docker欣然接受了三个提示,告别了Linux的前辈们,雨中归来。Tip1:chroot&pivot_root在长辈们的鼓励下,Docker精神抖擞,很快就准备开始自己的项目了。作为容器,首要任务就是限制进程在容器中的活动范围——可以访问的文件系统目录。不能让容器内的进程随意访问真实的系统目录,必须将其活动范围划定在指定区域,不能超过门槛!如何限制这些进程的活动区域呢?Docker遇到的第一个难题。苦思冥想半天,Docker终于忍不住打开Linux前辈送给自己的第一个工具包,看到上面写着两个函数的名字:chroot&pivot_root。Docker从来没有用过这两个功能,所以我就在LinuxEmpire周围问了问他们是做什么的。后来才知道,通过这两个函数,可以修改进程和系统的根目录到新的位置。Docker大喜,长辈果然没有骗我!有了这两个功能,Docker开始琢磨如何“伪造”一个文件系统来欺骗容器中的进程。为了不暴露破绽,Docker非常聪明。它将操作系统镜像文件挂载到容器进程的根目录下,成为容器的rootfs,与真实的系统目录一模一样。系统问题终于解决了,但是Docker却不敢懈怠,因为在他的心里,还有一个很大的问题一直困扰着他,那就是如何隐藏真实系统所在的世界,让进程在容器中看不到它。例如,进程列表、网络设备、用户列表一定不能被容器中的进程知道,它们看到的世界必须是一个干净的新系统。Docker心里明白,虽然自己被称为容器,但这只是表面现象。容器中的进程其实和自己是一样的,都是运行在宿主机操作系统上的。多么容易的事情。Docker想过用HOOK来欺骗进程,但是实现起来太复杂,兼容性差,稳定性也得不到保证。想来想去,也没想到什么好主意。正在一头雾水之际,Docker想起了Linux的前辈们送给他的套件。他赶紧拿出来,打开第二个工具包,看到上面写着:命名空间。Docker还是不明白这是什么意思,于是他在Linux帝国四处打听什么是命名空间。琢磨了一会儿,Docker终于明白,这个命名空间是帝国提供的一种机制,通过它可以划定出每一个命名空间,然后把进程划分到这些命名空间中。并且每个命名空间都是独立存在的,命名空间内的进程看不到空间外的进程、用户、网络等。这不正是Docker想要的吗?真的好难找地方去,也不费什么力气!Docker赶紧加班,使用了这个命名空间,把进程的“视野”锁定在容器指定的范围内,于是,容器里的进程就好像被蒙蔽了一样,再也看不到外面了世界。Tip3:解决了CGroup文件系统和进程隔离的问题,Docker心中的石头终于放下了。着急测试自己的容器,不过很好奇最后一个kit里写的是什么,于是打开第三个kit,看到上面写着:CGroup。这是什么?Docker还是看不懂,不过这次也管不了那么多了,先跑起来吧。尝试运行一段时间后,一切都在Docker的计划之中,容器中的进程可以正常运行,但是却被他构建的虚拟文件系统和隔离的系统环境所欺骗。Docker很高兴!很快,Docker开始在Linux帝国中推广自己的容器技术,并大受欢迎,收获无数拥趸,就连nginx、redis等大牌纷纷入驻。然而,在鲜花和掌声的背后,多克尔并不知道,自己即将迎来一场浩劫。这一天,Linux帝国内存管理部门的人扣押了Docker,要“处决”他。Docker惊讶的问道:“怎么了,你为什么要攻击我?”管理人员厉声道:“帝国管理的内存都快被一个叫Redis的家伙用完了,现在我得挑一些进程杀掉,不好意思,你中奖了”Redis?这家伙不就是我容器里的进程吗?Docker惊讶道:“两位大人,我认识帝国长老,还请您多多包涵,再去找人吧,Redis这家伙,我有办法对付他。”没想到他也认识帝国的长老,管理层犹豫了一下,还是让Docker去别的地方了。还在震惊中的Docker想了想。如果容器中的进程不受控制,那简直太危险了!除了内存,还有CPU、硬盘、网络等资源,如果一个容器进程占用CPU不放,或者一个容器进程疯狂写硬盘,迟早要会伤到自己。看来必须对这些过程进行控制,防止它们做出离谱的事情。这时,他想到了Linux前辈的第三个秘诀:CGroup!或许可以解决这个燃眉之急。经过一番研究,Docker如获至宝。原来CGroup类似于命名空间,也是Linux帝国的一套机??制。通过它可以一个一个的定义groups,然后可以限制每个groups可以使用的资源,比如内存的上限。值、CPU使用率、硬盘总空间等。系统内核自动检查并限制这些组中进程的资源使用。linux前辈的三个tips简直太贴心了,一个比一个有用,Docker感激不尽。后来Docker加入了CGroup技术,加强了容器内的进程控制,才松了一口气。在Linux前辈三绝妙招的加持下,Docker可以说是一时荣光,成为了Linux帝国中的大名鼎鼎。然而,能力越大,责任也越大。令Docker惊讶的是,新的挑战摆在面前。
