Docker3.0项目总结

开篇

我们在2015年中的时候就在做Docker1.0(琥珀),当时主要针对离线场景到2016年初琥珀已经小有规模同时也解决了很多生产环境的问题得到大家认可。在2016年3月份中心内部开始讨论要做在线Docker版本,而这只是需求并不是目标,所以我们当时针对中间层(spp)业务进行了调研,设定了目标做业务的弹性伸缩,主要是通过Docker来解决资源的快速扭转,大家用机器时可以更方便拿到,另一方面是减少人为参与上下线,将有限的人力放到更重要的位置让大家能快速成长与学习。
围绕这一小目标, 从2016.3.31发出一封Docker邮件到目前已经有一年多了,内部经历了多次的PK,从技术选型、是否使用开源、人力的配备、项目的优先级等,外部也遭到很多的质疑,为什么搞了这么久没有上量,Docker搞了那么多版本有什么意义、Docker的长期目标是什么,是否可以保持现有体验等等。总感觉项目走在十字路口,选每条路都是对的,但每一条路都未必捷径,总是被挑战中,这里我承认有一点根本原因是,理想很丰满,现实很骨感,我们在谈理想时嘴上总挂着我们要把我们的运营系统往前在走一小步,多么美丽的理想,而落地到现实时,我们需要更多的时间、需要人力、需要每个人情怀、需要顶住外界压力、寻找更多合作团队一起努力才能达到目标。而这并非易事,本邮件主要总结我们在运作项目中遇到的问题、我们的思路、大家对项目的疑问等。

如何开发一个项目

因为我个人并不是专业的项目经理,所以项目开发的过程也是我学习的过程也在思考如何能把整个项目能做的更好能尽快达到短期小目标。前期我参考了软件工程的方法论需求分析、概要设计、详细设计、测试、维护和用户手册等,但感觉并不十分实用于互联网的项目管理,譬如详细设计基本拿到文档就可以开发写程序,而目前我们还做不到这样的详细设计。后期我参考了《打造Facebook》一书其中的一章个人感觉还是比较试用的,但再原有的基础上我也补充了一下本项目开发过程中的案例。

打造Facebook Docker项目
描绘远景,设置目标; 描绘远景,设置目标;
收集想法并排出优先级; 收集想法并排出优先级
跨团队沟通 跨团队沟通
告诉所有可能关心的人 设计产品
设计产品 指定责任人
指定责任人 定期碰头
定期碰头 了解进度,汇总报告
了解进度,汇总报告 发布产品监控数据
发布产品监控数据

描绘远景,设立目标

开篇中提到要寻找更多的合作伙伴才能达到目标,所以项目建立之初一定要描绘远景、建立短期、中期和长期目标,这样在不同的时间需要伙伴与切入点才一幕了然。以下使我们项目的一个基本项目流程图

Docker项目流程图

其实目前我们已经走到了Docker3.5版本,这里有同学会问,为什么Docker搞了这么久没见产出? 又为什么有这么多的版本? 有大版本为什么有小版本?

先来回答第一个问题,为什么Docker搞了这么久没见产出?
其实Docker2.0耗费了很多的时间,其实在2016.6月时,开发程序启动的3个月后我们就已经发现了很多问题,而且是难以解决的问题其主要的就是流程图中的三个问题(流程的不稳定、没有交付标准和Docker隔离型弱),但是这里不能轻易停工,毕竟投入一些人力物力,总是需要有个结论,所以我们也找到了Docker2.0的试用场景即长尾业务。从2016.9- 今,我们在开发Docker3.0版本,其中Docker3.0解决了Docker2.0的几个核心问题,从设计上来看是可以解决我们最开始的目标,但在讨论设计的过程中也对Docker3.0给予了很多希望,希望他们实现弹性伸缩的同时能把运维现状往前推一小步,但这一小步让现网出现了两个流程,即原有织云发布方式和镜像方式,如何尽量保持原有体验? 需要页面大量的开发改造。 如何保持新开发的接口稳定? 需要上量一些业务,而推开发开发觉得自己是小白鼠不愿配合,只能推运营系统与离线系统优先上线, 而这个过程在设立目标前是不能预知到的,所以耗得时间会很长。

头痛的需求分析

在收集想法排查优先级的过程中我们也出现了一些问题。
软件工程的方法论需求分析、概要设计、详细设计、测试、维护和用户手册等。关于需求分析前期我们会找很多业务运维与开发同学进行前期的需求分析,分析的结论是用户从不同的角度结合自己业务的需求来向平台提出需求,这就导致一个问题平台满足A用户就满足不了B用户。
开发观点:

  1. A开发,希望通过Docker能管理从开发->测试-> 上线到持续集成。
  2. B开发,希望能用开源工具譬如k8s来管理Docker,更符合业界玩法。
  3. C开发,只要系统稳定能提供资源,使用什么都无所谓。
  4. D开发……
    运维观点:
  5. A运维,保证与现网体验一致。
  6. B运维,可以实现弹性伸缩解快速扭转设备解决成本问题。
  7. C运维,能实现弹性伸缩,解决人力参与问题。
  8. D运维…..

这里有的问题是互斥的,有代表的譬如A运维与B\C运维的需求,保持一致是完全一致还是部分一致,这里还要分析老系统为什么不能实现弹性伸缩,分析出原因如果老系统不能实现弹性伸缩,新系统又要体验一致,这就是互斥的问题。 这只是举个例子类似情况很多这种感觉有点像数独游戏,业务只关注横向相加的结果,而平台关注横向纵向全局的结果。 所以分析下来比较头痛,不能完全按照大家观点来开发又需要权衡大家的观点与意见让全局相等, 同时要尽量反馈大家我们这样做的原因。

图2 数独游戏

内部Docker发展为什么三个版本?

首先要承认这里我自己有一些疏忽,不应该把内部开发版本透传给项目经理,而项目经理直接将我转的开发过程发给大家导致内部开发版本很多人不知道含义来追问我原因。所以切记要将项目邮件介绍的通俗易懂,并只周知关心项目的人。我们并不想开发过多版本,以目标为前提,以软件工程和facebook项目开发过程为理论,都不能预知项目到每个阶段会出现什么问题,而真的出现问题时,我们只能增加版本更改技术方案来标识每个方案的优缺点与定义。 下面来介绍一下三个版本的定义、相关属性和优缺点。

以弹性伸缩目标为目的我们演变了三个Docker平台版本,有人会问内部系统为什么通过三种方式提供? 我觉得如果是新的产品业务一切从新开始这样会简单的很多,但是面对老的业务与沉重的历史背景这就负责很多,而我们社交网络类业务正式这样也导致我们每走一个版本都会发现一些问题,在问题的基础上迭代了新的版本。以下来介绍一下各版本区别:

Docker 1.0

Docker1.0主要应对离线业务类场景。这里的背景在应对业务特殊情况时需要有备份的服务器资源也就是buffer来支撑,而我们海量运维就导致buffer有>1000台服务器属于常态,我们把一些离线的业务打包镜像跑buffer上,实现了离线业务在buffer上的弹性扩缩容,但也就是使用了buffer资源,在节假日时会导致buffer水位很低影响离线服务的正常运转,由于Docker1.0使用buffer池与低负载机器的原因为业务节约了很多成本,所以我们也在想是否可以通过Docker来解决在线业务场景。

Docker2.0

Docker2.0主要面对在线业务,应用场景是充分利用低负载资源与分时业务的混合部署。在Docker1.0的基础我们使用了现有运营系统“织云”,通过织云的图形化与流程系统降低了用户接入的成本。但我们也发现这里的问题:

  • 弹性扩缩容时对系统稳定与成功率要求的很高,而与现有流程系统混可用率不能满足需求;
  • 尽管运营系统降低用户使用成本,但部分业务还拿Docker当物理机玩而Docker的若隔离会有引发很多问题;
  • 业务的环境不“标准”

如截图我们建议用户将包、配置放到指定的目录下即(app)目录,将日志放到(/data/log)目录下,商业日志放到(/data/bulog)中,这样我们在构建镜像时就会把(app)目录提交到远程镜像仓库,而当容器重启时不会影响到日志。因为我们很多业务历史比较悠久这就导致不“标准”程序的包、配置、可执行文件和日志可能散落在系统的不同位置甚至日志达到了(app)目录中,导致构建镜像时日志也被提交到了远程镜像仓库中。

Docker3.0

Docker3.0主要解决量大问题业务环境的不“标准”与Docker若隔离。 这里与Docker2.0相比3.0有个变化:

  • 弹性扩缩容的前题是标准化,我们在构建镜像时使用了Dockerfile而镜像就是我们的“标准”。我们一直希望通过规章流程来制约我们的业务让他们变的更加的标准,但是面对历史和业务的kpi压力貌似规章制度并不能很好的约束各业务,所以我们一定要找到一个标准那就是镜像,但是面对所有人学习Dockerfile有一学习成本,所以我们也将Dockerfile实现web化,并在构建镜像的过程中绑定了业务的端口用于后续的质量检测,还绑定了业务的路由,用于镜像启动检测质量没有问题后加路由。
  • 资源使用了母机包(KVM+Docker)的方式,网络用的是host模式。其中母机一般是高配机器,将母机资源平均等分的KVM在KVM里启动Docker整体结果大概如截图。

有很多同学认为这种玩法比较怪,其实主要有以下几个原因:

  • 保持用户使用习惯,开发与运维依然可以通过IP登录到机器上,但开发debug日志可以在(/data)目录下查找,由于包、配置和代码都放在Docker容器中是不可以乱改的。
  • Docker2.0 N个容器跑在一台母机上,由于隔离性有问题,当用户修改系统时间时就会导致整个母机及所有容器系统时间都会改变,在则容器中的系统负责显示的是母机的系统时间,当然这里可以改造需要对Docker进行二次改造,而我们这里只是通过这两个例子来说明Docker隔离型差问题。
  • Docker3.0对于用户来说也有一些问题,其中最主要的问题就是发布变得更重了但过重换来的是我们将对现网的所有的入口都收归了镜像或者说“标准”,通过标准实现了自动化扩缩容。

项目版本控制的必要性

项目开发过程中需要走版本控制相信大家对这里都没有问题,笔者也将版本控制引入项目开发过程,但笔者并没有做过专业的项目经理也在学习过程中,这里遇到的问题是项目版本走邮件跟进并周知内部小团队,总结版本控制必要性三点:

方便总结与回顾。

记录每个版本的细节可以更好的回顾总结遇项目中遇到的问题、难点和后续优化空间等。为未来开发项目沉淀一些经验。

Deadline(截止时间)才是最大生产力。

每个版本都有版本的启动时间与截止时间且都由个人自己评估确定。我们工程师一般情况下每天或多或少会被一些紧急不重要的事打断,而项目在组内又有很多交集,如何确保合理安排项目时间交集部分减少不表要的等待时间管理,事物优先级排序就很重要,有了Deadline就是最大的生产力。

版本一旦确定不接受其他任何需求。

特别在开发与外界交集比较多的项目过程中时间难以把控,只能是尽量的协调控制外部交集的时间点所以一旦需求确定,哪怕加一个很小的需求,项目之间有依赖关系都可能会导致项目的延期或项目质量的下降。关于时间评估这里有一个经验值,在开发与外界交集比较多的项目过程中,尽量是自己评估时间的1.5倍到2.5倍间,具体视情况而定。

是否采用开源工具

我们现在采用了自研的方式来管理我们的Docker容器,但在开发的过程中也不断有同学推荐开源的工具,譬如messos\swarm和k8s等这些工具都非常优秀且有着庞大的用户人群和市场空间,我了解到的很多创业公司都有在应用,个人觉得这些工具的设计思路非常先进有很多借鉴的意义,更重要的是他就像一种行业的协议,特别在与其他公司交流时虽然公司的业务不同,但用了相同的协议这样交流起来更顺畅同时收益也更大。个人并不排斥开源工具甚至更推荐用谈理想没有问题,但现实把这些工具在内部落地就很困难,总结原因有以下两点:

  1. 因为部门大、产品多、产品历史背景长、复杂接口调用、高于一切的安全管控和与老运营系统兼容等,在落地的过程中都需要考虑周全,而开源工具内部落地遇到这些问题不免需要进行二次的开发能力、这种能力不是一个人而是一个组都需要具备的,特别在海量运维场景下不同产品有自己的业务特性,开源组件未必满足业务特性,导致一场查找成本会很高。还有在看到其他的部门在使开源工具为符合内部业务情况下进行大量二次开发,当业界升级工具时又需要持续迭代等头痛问题。
  2. 引入开源工具譬如k8s需要开启NAT功能而内部系统都是定制的为了安全关闭了部分功能的情况下又要打开,又要保障系统安全这两个问题是需要慎重思考与权衡的。
    所以按短期目标来看,我们还是使用了自研的方式来管理我们的Docker容器。

原生Docker思路其实是错的

Docker 官方文档强调(build - ship - run) 其中:

  • build: 构建镜像,把整体环境软件依赖包和操作系统用户态构建成镜像,并通过版本区分镜像。而构建镜像方式又分为两种,一种直接将软件包安装到已经生成的Docker中来打包构建,另一种是通过Dcokerfile来构建镜像,这两种方式我们都有应用;
  • ship: 通过Docker register 来分发构建好的镜像;
  • run : 只要kernel支持,上层使用用标注的协议镜像,就可以运行在各种环境下,迁移非常方便。

问题出在构建镜像通过版本区分不同镜像间差异,这种方式有优势也有缺点,看在什么场景下:
优点:

  • 在并行开发环境下,通常最头痛的问题就是环境不一致引发的线上故障。 而在Docker场景下开发只需要关注镜像版本,运维只要关注资源利用率,OD分离互补干扰,解决资源利用率同时也解决环境的问题。
  • 现网环境一致实现标准化,有了标准化就可以实现自动化。
  • 镜像生命周期短,每次更新版本镜像需要重启镜像,如果程序质量有问题,譬如运行时间长oom ,进程不释放fd 导致磁盘满情况都能很好的解决。

缺点:
海量运维场景下,线上环境频繁的变更,Docker生命周期短频繁重启不现实。当然Docker在这方面也是有考虑的,譬如分层文件系统,但分层文件系统有128层限制,且目前测试情况看到40多层性能出现下降,而部分业务可能1内发布的内容就超过128层限制,所以这种方案是有问题的。
在开始我一直认为推动我们的系统往前走一小步,让频繁变更的业务适应Docker比较短的生命周期是正确的,但实践证明海量运维场景下,Docker原生思路中的优点在我们验证下是不可以的,很难推动。 或许在不久的将来,整体运维观念改变,运维架构上有更方便的调度系统与服务发现功能
的背景下,使用Docker原生思路才是对的。

“规范”如果没有工具的辅助就相当没有规范

以下来自部门群。

我们为什么要制定规范,因为规范是标准化的前题,而自动化又是基于标准化基础之上,所以我们要制定规范。但问题来了有规范就一定可以实现标准化自动化? 这个真的不一定。生活中法律是一种规范,如果一个美女穿着很暴露的衣服走在夜晚12点后的街道小巷,即便有法律这种规范遇到色狼的风险也是很高的,如何避免呢? 提高法律的惩罚力度? 我觉得会有点效果但治标不治本,这时美女要尽量不穿着暴露的衣服,尽量不要在夜晚12点后出门,即便出门也不要走街道小巷,才会大大降低遇色狼的风险概率。做系统与架构也一样,通过规范来让系统标准化收效不大,规范与法律相比并没有更多的处罚力度,这就直接导致了规范不到位,标准化没有里程碑,自动化遥遥无期。
我曾想借鉴一下业界譬如某阿是否也遇到过我们目前面临的问题,他们是如何解决的?是否可以借鉴。一次机会听某阿朋友分享容器其中也提到了规范,某阿一直想试着梳理规范流程因为某阿也分很多bg(business group)不同bg运营的业务不同人也不同导致规范也不同,在一个公司体系下业务有可能会被轮换,不同业务轮转到不同的规范下又要保持业务正常运行短期只能加人,长期需要梳理规范,分享的嘉宾也说曾多年试图将这里的规范梳理统一但是发现比较难,推动成本也比较高,所以这里container(集装箱)是解决的方案之一,试想一下集装箱的发明正式把很多不标准的东西变成了标准尺寸,这样在码头才可以通过工具自动的搬运这些集装箱提升人们的效率。而先有了规范再通过工具去约定,这样才能达到我们预期的效果。