肖劲 译 分布式实验室 

容器、Docker与Kubernetes——从基础设施的容器化谈起_Jav

作为一名长期从事运维的工程师来说,我会时常审视维护服务器工作的简单性与可重现性;而我的一个最重要的工作原则便是“永远不要手动操作服务器”。所有服务器都必须由工具进行启动(provisioned)与配置以运行,同时通过工具来监控、维护服务器的状态——而我的选择是Chef;当然你也可以有很多其他选择如:Ansible、Salt与Puppet。

在Collective Idea中,Chef确实运行得非常好,它管理着公司内部与外部客户的很多服务器。但是,渐渐的我也意识到了Chef的一个缺陷:对变化的处理不好。生产环境的应用与基础设施都是有很多复杂的构件(creatures)组成,这些构件都由很多变化的组件(moving parts)组成,组件之间又有大量的显式或者隐式的依赖——它们随时都会由于不可预知的原因发生变化。其中,有些变化容易处理,如配置文件更改或者对系统进行微调;但是其他一些就比较复杂,如,不停机升级一个应用依赖的Ruby运行时版本。而且,还有一些对服务器的调整需要人工操作,如,升级操作系统内核后的重启等。

简而言之,以我多年使用Chef的经验,它在搭建新的运行环境与配置系统上确实工作得非常好,而且也是我需要的;但是在处理一些升级,变更等需求的时候,就会变得非常费事而且容易出错。有没有工具能够减轻服务器升级变配带来的痛苦呢?

不变性基础设施

容器、Docker与Kubernetes——从基础设施的容器化谈起_Jav_02

解决问题的一个方案是“不变性基础设施”应用部署模式;具体表现为,相对于一个个机器的升级(针对上面所讲的情况)基础设施,这种方式会直接丢弃掉老版本的基础设施,然后将应用程序整体迁移到一个已经升级完毕的新的基础设施中运行。但是,本质上“不变性基础设施”部署方式仍然需要一个类似于Chef的工具用于初始化、配置与启动基础设施,不同的是一旦一个基础设施在运行了,它的状态与配置就不允许发生变更;如果有配置变更需求则启动新的基础设施来代替老的。当然,这种部署方式有其自己的复杂性,它必须能够随时删除或者下线一个老的基础设施然后启动一个新的——任何时候都有可能发生。那么问题就来了,对于数据库来说怎么升级?升级新的web服务器后怎么重新注册到老的负载均衡器上?升级新的负载均衡器又如何能保持其下诸多的Web服务器不掉线的升级?

实际上,要完全实现不变性基础设施的服务器部署是有很多技术瓶颈的,导致其在现实环境中很难实现。有些工具如:Packer能够在一定程度上减轻创建虚拟机镜像的工作难度的,但是你仍然需要面对一整套的环境搭建工作,这通常需要花费很长的构建与生成时间,因为你一般需要下载数G的文件来搭建一个单独的系统。

有没有方法能够同时兼顾不变性基础构架的方便直观,而且镜像文件又能保持足够小呢?有没有工具使我们打包镜像时剔除掉操作系统与底层抽象只保留应用程序本省与其依赖呢?这样我们就能只部署一个很小的镜像,迁移那些发生变化的数据,最后节约大量的部署时间。这就是容器技术为我们带来的改变,如Docker与rkt(读音同“rocket”)。在容器为基础的基础环境中,底层的服务器与虚拟机都被抽象成了资源如:CPU与内存。

因为我平时使用Docker所以在以下介绍中我用Docker为工具来讲述我的观点,当然还有其他类似的容器化工具如rkt,效果是一样的。

Docker

容器、Docker与Kubernetes——从基础设施的容器化谈起_Jav_02

Docker,简单来说,它将应用程序的执行文件、命令都打包在一起,称为镜像(image),然后在宿主机或者虚拟机上部署运行这个镜像;而运行起来的镜像被称为“容器”,反过来说,容器就是运行时的镜像。容器在一个封闭、隔离的环境中运行,在这个环境中它认为自己是系统中唯一运行的程序,这种隔离性保证一个宿主机可以同时运行多个容器,但是互相并不知道对方的存在。

Docker镜像文件是一次写入的(write-once,就像一张光盘),这使得Docker基础环境看上去就是一个不可变基础构架。镜像与容器永远不会更新,新的镜像生成伴随着老的容器的关闭,而这个过程相对于关闭与启动一个服务器或者虚拟机来说只需要非常短暂的时间。

所以,你会问,那我们Collective Idea是不是把所有的服务都迁移到了Docker上了?我的回答是,没有,现在还没有。容器的使用有个单一职责的原则需要遵循:运行多个容器,各个容器只完成一个单一的工作。进一步说,将服务容器化的过程就是基础构架SOA化的过程;这个过程一样面临很多问题与困难:

  • 容器与容器之间如何发现与通信?

  • 如何决定在哪运行以及运行多少个容器?

  • 如何获取容器运行的日志与运行状态信息?

  • 如何部署新的镜像?

  • 容器崩溃时都发生了什么?

  • 如何只将特定的一部分容器暴露在公网或者内网环境下?

直至当下,相比现在服役的Chef工具来说,回答这些问题以及大规模在Collective Idea部署Docker应用都还不太成熟。但是,现在还是涌现出了很多解决我提出的问题的工具,而且还提供了可用于生产环境的容器化部署方案,如:Docker公司自己的Docker Compose;但是我们还是选择了Google的方案——Kubernetes ,它号称融合了Google在十几年来在其超大规模数据中心运行了数十亿个容器的经验。

在我下一篇文章中我会详细阐述我们如何使用Kubenetes以及为什么它是部署Docker容器的绝佳方案。

本文为翻译文章,点击阅读原文链接即可查看原文。