新的一年,如果我们对信息技术领域有所留意的话,就会发现“containers”和“Docker”成为了热词。在每个地方,我们都会将开发好的软件打包放入Docker容器,到处使用容器。从小型创业企业到大型微服务平台;从CI(Corporate Identity)平台到树莓派的研发;从数据库管理系统到…… 你说什么?确定在产品级的项目中要将数据库放到容器内吗?真的假的!遗憾之处在于这就是事实。我见过很多快速成长的项目将持久化的数据放到容器内。不仅如此,在同一台主机上还部署了计算服务!不幸中的万幸是有识者不会这样做,但很多新手都是这么干的。 下面我要抛出自己的观点,回答“为什么”不要这样做。注意,所谈论的一切都基于当前,即2017年01月29日当前的状况。我们也看到过一些项目,研究如何在Docker中安全地管理数据库。但是,目前数据库容器化完全是不合理的。 下面,我来逐一阐述其中的原因!共有7大理由: 1.数据不安全 从“Banned from DBA”这部分开始,Docker in Production: A History of Failure这篇文章中关于Docker的观点完全正确。即使是把Docker的volume创建在了数据原有的目录,也不能说就有了什么保障。没错,Docker的volume被设计成与联合文件系统(Unions FS)镜像层一起,提供持久化存储功能。但这并不意味着能得到什么保障。 目前Docker的存储机制仍然是不可靠的。一旦数据库未正确关闭而引发容器崩溃,数据就乱了,就会将服务最重要的部分丢失掉。 2.特定的资源需求 我看到过运行在同一主机的DBMS容器作为服务层容器。但这些服务层的容器与硬件需求并不兼容。 数据库,特别是关系型数据库,都需要额外的资源。这包括内存、磁盘I/O等。通常我们把数据库引擎专门用来避免资源并发的情况出现。将数据库放到容器内,会是一种浪费项目经费的行为。为啥呢?因为这种做法是将许多额外的资源放到了一个单一的实例,这会导致无法控制的局面。在云平台中,如果运行实例需要34G的内存资源,那我们就要创建64G的内存空间。而实际上很多这些资源是用不上的。 如何去解决这样的问题呢?我们可以把这些层分开,然后绑定固定资源的实例。横向扩展总是优于纵向扩展,基本就是这样的。 3. 网络问题 要理解Docker的网络部分,就必须对网络虚拟化有深刻的认识。并准备好处理意料之外的情况发生。还可能被环境所迫在没有帮助的情况下修复bug,或者为了彻底修复而使用额外的工具。 我们知道,数据库为了更高的负载需要特定且持续的吞吐量,还知道容器是hypervisor和虚拟主机之后更独立的一层。还有网络对数据的复制来说也至关重要。复制需要7x24小时不间断的网络连接。当然,还有Docker自身存在的网络问题,自从Docker 1.9以后还未解决的问题。 将上面这些问题汇总起来,我们可以断定,数据库容器是不容易被管理的。如果再加上网络,就会变得非常困难。尽管你是顶尖的工程师,从不知道什么叫“困难”和“不可能”。但是解决Docker的网络问题你要花费多长时间?而将数据库放到特定的环境,抓紧时间聚精会神去做真正重要的事情不是更好吗? 4. 运行环境的状态属性 使用Docker的时候,我们时常遇到“无状态”这个热词。顺便提一下,你知道现在的热词都有哪些吗?别告诉我还是“DevOps”! 在Docker中将无状态的服务打包是件很酷的事情,把这些服务放到一起,不再关注单点的失败。那数据库呢?把数据库放到相同的环境中,这样就变成了有状态的。我们将应用可能失败的可能性加大了。下次应用实例或应用程序本身崩溃的时候,很可能就要触及整个数据库的工作流程了。 5. 与Docker的主要功能特性不相匹配 就算我对Docker一无所知,还是学校里一位无足轻重的系统管理员,并不关心商业价值和创新。但我们考虑容器中的数据库,必须要评估其价值和收益。Docker的实质是什么,我们来看看官方的说法: Docker是为开发人员和系统管理人员开发、装载和运行分布式应用程序的开放平台。由Docker Engine和Docker Hub两个部分组成,Docker Engine是轻量级的实时运行的打包工具,Docker Hub为应用程序的共享和工作流的自动化提供云服务。Docker能够快速装配组件状态的应用程序,并消除开发,测试和产品环境之间的差异。因此,IT人员无须作任何修改,就可以更加快捷地在笔记本、数据中心虚拟机和任何云端装载并运行同样的应用程序。 根据上述说法,我们就可以轻松地对Docker的价值给出定义: 易于安装软件; 易于重复部署(持续集成); 易于横向展(此条来源于实践); 易于保持各个环境的平等地位。 接下来我们考虑一下,这些功能特性如何与数据库相匹配。易于安装数据库?在运行时与数据库有什么特别不同之处吗? docker run -d mongod:3.4 sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 0C49F3730359A14518585931BC711F9BA15703C6 echo "deb [ arch=amd64,arm64 ] http://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.4 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-3.4.list sudo apt-get update && sudo apt-get install -y mongodb-org 如果拿MongoDB集群举例,那么集群的配置管理(Configuration Management)系统会是什么情况呢?配置管理系统被设计成执行一条命令就可以完成例行的程序。就拿MongoDB的安装来说,Ansible模块可以用在十几个实例上。无论怎么样,开发自己喜欢的配置管理系统就可以。我们可以了解到,这并不像火箭科学那样,并不能带来太多的价值。 易于重复部署?为了升级将数据库升级到下一个版本而重新部署数据库的频度有多大?即使集群存在适用性(usability)的问题,但数据库升级不属于此类问题,而属于工程问题。思考一下,我们的应用程序如何与新版的数据库引擎协同工作,数据库引擎发生变化时会产生哪些破坏性的影响,这才是更有价值的思考。而Docker是无法解决这些问题的。 易于水平扩展?我们是否要在很多不同实例之间共享数据目录?难道不怕直接发生数据并发和可能发生的数据崩溃?不是在特定的数据环境下部署多个实例更安全吗?还有最后去完成主从服务的复制。 易于保持各环境的平等地位?数据库实例环境发生变化的频度有多大?我们每天都升级操作系统吗?也许数据库的版本或依赖软件就像类库和模块一样的形式存在呢?与工程团队保持一致岂不是更容易吗? 我们就当这些说法都成立。但是是否存在这种可能性,“蹩脚”的工程师不遵守规则,坚持要使用不同版本的数据库进行开发?或者“出色”的工程师遵守规则但难于理解使用什么?我想对于上述后两个问题是这样。Docker并不是解决环境平等地位问题的有效解决方案。 至此,与数据库容器化相关的所有功能特性都被梳理了一遍。 6. 数据库层特有的隔离状态极为重要 实际上,我在上述第二条和第三条的理由中已经表明了这一观点。但我把它单独作为一个主题是因为想再次重申一遍。被隔离的层级越多,我们获取资源就越容易。可以获得如此多的收益而不限于特定的环境并不是个问题。但是在Docker中,这些功能特性存在于无状态的服务中,而不适用于数据库。 在数据库当中并没有看到任何具有隔离属性的功能特性。因此,我们又何必将数据库放到容器中呢? 7. 与云平台不兼容 我们当中的大多数人已经开始使用云平台做项目了。云平台可以对虚拟机进行编排,实现弹性资源调度。例如,在夜间或周末无人值守的时候,为什么需要测试(testing)环境和上先前(staging)的环境?我们能够启动另一个有着相同配置和服务启动进程的实例时,为什么还会担心目前正常运行的实例? 这就是云平台主要的功能特性,也是我们向云服务商付费的原因。当把实例放到数据库容器当中后,云平台的这个功能特性就不存在了。由于数据不匹配,放到容器当中的实例与原有的实例不兼容。因此,我们会限制于只使用单个的物理机,也不会存在虚拟机编排的事情。数据库最好使用非容器化的环境。虚拟机的编排和自动扩展只放在计算服务层去完成。 所有数据库都存在同样的问题吗? 并不是所有的数据库都存在同样的问题。这些问题只存在于数据需要持久化的情况下。并且还要与特定资源需求相关的数据库才存在这样的问题。 如果拿Redis来做缓存或者会话数据的存储,就不存在这样的问题。由于这些数据不需要存储在硬盘上,因而也就不存在数据丢失的风险。但如果我们拿Redis用作持久化的数据存储,那就最好将数据库放在容器之外。即使我们不断获得了RDB快照文件,在不断快速变化的计算集群中找到快照也是一件复杂的事情。 我们也可以谈谈容器中的ES(ElasticSearch)搜索引擎。在ES中,可能只存储索引,并从持久化的数据源中不断重复构建索引。别忘了我们对特定资源的需求!默认情况下,ES需要占用2~3GB内存空间。内存是非持久化的,用作Java垃圾回收阶段。我们能够确定ES就是解决特定资源限制最好的容器吗?根据硬件的不同情况安排为ES组织不同的实例不是更好嘛? 本地的开发环境就不用担心了。在本地开发环境中将数据库放到容器中会节省很多时间和力气。在产品环境中也是一样。要知道OS X或Windows系统下原生的PostgreSQL都不会百分百地与Linux版本兼容。所以构建起容器代替在主机系统上直接部署可以弥补这点不足。 结论 与Docker相关的大肆宣传终将落幕,但这并不意味着人们会停止使用容器虚拟化技术。而是意味着人们开始正确地使用容器,并将其使用价值放在首位。 几天前,我观看了有关Ruby架构的精彩对话,并从中指出无关Ruby本身而与技术炒作周期相关的看法。通过这个炒作周期我们看到Docker正处在第二阶段,也就是膨胀预期的顶峰,已经很久了。在最后阶段我们会看到这种情况会趋于正常化。我觉得我们要认真负责地对待这样的过程,甚至有必要加速该过程的发展。 原文链接: https://myopsblog.wordpress.com/2017/02/06/why-databases-is-not-for-containers/(翻译/白云鹏,责编/魏伟)