实录分享 | 那些年容器落地,企业为Docker填过的坑

数人云“容器助力产品迭代力MAX”沙龙干货分享实录持续上新,今天是来自人人贷高级运维工程师杜天鹏的分享,与我们细数了人人贷容器化实践过程中遇到的问题以及解决方法。

很高兴站在这里和大家一起交流容器技术,我叫杜天鹏,是人人贷的运维工程师。人人贷是一家做P2P的互联网公司,现在业务量上升比较快,业务组件也比较多,这个过程给运维增加了很大的压力,所以人人贷考虑了容器化技术。

为什么使用容器技术

Docker官网有一句话:build once,run anywhere,容器一次构建,在其他服务器上就可以运行。第二,容器使用的是Unionfs,在传输的过程中,实际上传递的是变更的部分,而不需要拉取完整的image。第三,容器为人人贷提供了一个隔离的环境,在测试的过程中,一台机器可能运行了很多服务,一旦测试或者开发人员更改服务器环境或者其他参数,会导致其他的测试环境运行不起来。容器带来了环境的隔离性,一个容器只需运行一个Docker,可以避免很多问题。第四,容器能够结合Jenkins以及如Hudson、Teamcity这些持续交付软件来进行持续交付、持续集成、持续部署。第五,容器可以结合如K8S、Mesos、Swarm等调度器然后进行横向扩展。

这是人人贷的传统上线流程。首先开发人员推送他们的代码到Git仓库,人人贷使用的是Stash,测试人员在测试的时间输入仓库名称和版本号,来进行使用Jenkins构建。在测试环境中,测试完成之后会重新构建一次,然后推送代码到类生产环境。这个类生产环境实际上使用的是生产环境的配置,只不过再做一次校验,防止出现问题。最后运维人员使用Ansible推送代码到生产环境,在这个过程中会产生很多问题。

比如刚才说的环境不统一,或者是无意中修改了环境,或者有临时的需求上线的时间,需要准备新的虚拟机。这个临时的需求或许非常着急,但是从运维的角度来看,创建服务器,修改配置,初始化操作都需要一个过程,因此会影响整体的工作进展。Docker解决了这个问题,因为可以使用提前准备好的Docker镜像进行所有的初始化操作,让运维可以从容应对突发的情况。

还有资源浪费的问题。在开发或者测试环境,人人贷运维人员为开发创建了很多测试虚拟机,假如不做定期巡检的话,就无法得知这个虚拟机是否正在被开发或者测试人员使用,导致了资源的浪费。使用了Docker技术后,运维就可以随时为开发或者测试同事部署一套环境,并且做定期的清理。对于大规模的部署过程,可以实现灵活调度,因为人人贷的业务峰值是不一样的。比如白天交易系统比较繁忙,可以调整交易系统节点数量;晚上要做计算和统计,计算资源则会多跑一些任务。

为什么选择Mesos

人人贷在使用Docker时,考虑了三种容器技术,分别是Mesos,Kubernetes以及Swarm。最终选择Mesos主要基于三点考虑:最主要的是学习成本,对于Kubernetes,它的功能很多也很强大,但是它更新迭代非常快,里面很多功能现在仍处于Beta版本,但是官方并没有明确其使用环境。第二,成熟度的问题,Mesos推出时间早,实践的公司也比较广泛,成熟度高于其他两个技术。第三,Mesos有很多调度器例如Marathon,在界面上可以有一个直观的展示。而Kubernetes和Swarm之前是没有界面的,现在Kubernetes有一个Dashboard,但是功能尚不完整。

迁移到虚拟机的种种问题

人人贷从物理机迁移到虚拟机过程中遇到很多问题,一个完整的技术就是一个成熟的技术在应用到生产环境中,这个过程中的问题并不是技术引起的,而是落地的过程中没有标准,所以人人贷需要有一个标准化来面对需求。

首先,配置不可见。运行在Docker内部的程序,并不不推荐进入容器,因为Docker就是一个容器,需要连接到里面来看配置项。在Marathon上面就可以看到配置项,具体配置项是通过ENV传入的。

第二,项目无法相互调用。人人贷的业务比较多,所有的项目需要相互调用,包括交易所、 P2P以及基金,它们之间需要进行资源交互。但是由于人力精力有限,Docker技术在整套系统的实现尚需要一个过程。

第三,无法通过SSH连接Docker。比如在测试环境中测试或开发进行一些debug操作,需要通过SSH连接上去,了解Docker现在的配置。

第四,容器IP不可见。

如何解决这些问题

接下来我会通过运用的技术来为大家解释人人贷是如何解决这些问题的,Docker落地过程中主要有七点需要关注。

第一,编排。Marathon是使用json文件进行部署的,里面会写到具体的资源配置,镜像名称以及挂载目录。首先进行配置文件模板化,在人人贷,运维人员分别负责不同业务部门的运维工作,所以运维并不清楚其他部门是如何配置的,模板化之后只需要让开发人员按照规则来表述,就可以清晰地传递和表达。

例如上图中两个配置,这是exchange(人人贷的一个项目名)环境里面的MySQL以及服务。开发只要按照这个标准往里面写配置,运维就可以明白项目和配置项。然后进行配置项ENV化,配置都是通过ENV传入,通过命令进行渲染,当然也可以使用shell命令或者其他的程序进行配置渲染。之后修改上线json,因为每一次json文件并不是一成不变的,需要更改文本配置。

第二,网络。人人贷使用的是Calico,它本身可以划分网段,来指定范围。我们在路由器上面添加了路由,让开发环境可以直接访容器内部的网络。Calico本身可以支持Docker1.10版本后,可以通过 - 指定 --IP。人人贷使用的是CNM模式,Calico是支持CNI与CNM的,人人贷使用的是calico-containers,因此可以使用Docker命令,并且指定驱动为Calico,非常便于管理。指定路由后,可以直接访问,不再需要使用例如Marathonlb这些指定端口,也不需要维护端口列表。Calico使用BGP协议,不需要封包。对于Mesos来说,我比较推荐使用Calico。

第三,服务发现。人人贷使用Calico可以固定IP地址,虽然并不推荐把容器作为一个虚拟机来使用,但是对于固定IP地址这种情况可能仍需要一个容器。当其他服务需要灵活调度时,则需要IP动态划分。人人贷使用Mesos-DNS来获取动态分配的IP,所有的组件配置域名相互调用,测试环境同样使用的配置域名化,即服务调度之间都是使用域名来调用的。因此Mesos-DNS只需要转发现有域名服务器的域名解析,就可以直接调用原有的服务,在里面写域名,而不需要知道其IP地址,亦不需要配置。

第四,存储。对于一些需要持久化的数据,人人贷使用的是本地化持久卷,这个绑定在host上,当这个容器挂掉之后,它会在物理机上重新起一个容器。Docker通常运行的都是无状态应用,所以如果MySQL里面的数据非常重要,我还是更推荐使用物理机或者虚拟机进行部署。对于分布式如MongoDB或者其他具有高可用性的数据库,部署在Docker里面也还是可以的。

第五,监控。人人贷使用的就是Cadvisor+Influxdb+Grafana这套开源方案,Cadvisor是谷歌的一个开源产品,Influxdb是一个时序数据库,Grafana是一个漂亮的界面展示。对于Zabbix,人人贷用过一个叫Zabbix-Grafana的插件,可以在Grafana里面显示Zabbix的数据。Cadvisor主要起到作用就是收集容器里面的资源使用情况,例如内存,CPU以及磁盘IO,然后存入到Influxdb中。当然监控的同时,也可以使用Dockerstats等实现一些数据采集。

第六,日志收集。人人贷现在主要使用的是ELK的数据方案。为了实现SSH登录容器内部, Docker是需要一个前台进程来保持Docker程序不退出的,因此人人贷所有的容器都是使用SSHD守护进程,来保持Docker一直运行下去。

人人贷有一个start的脚本,例如Tomcat,我们会在这个SSHD进程启动之前来启动它。所以日志通过Docker logs是看不到的,只能在容器里面部署一个Logstash agent,但是会加重容器的负担。对于没有接入容器内部需求的同学,可以直接接入运行进程,将日志打入到Docker控制台,通过Docker logs进行日志收集,在Docker的宿主机上面指定Docker日志的产出目录实现收集,而不再需要在Docker里面部署agent。

第七,镜像仓库。Docker官方的镜像仓库本身是没有认证功能的,但是在真实生产环境中,需要有镜像的权限划分。现在Registry用的比较多就是Apphouse以及Habor,据我之前了解,Habor的BUG比较多一点,所以人人贷使用了Apphouse。但是现在我了解到Habor支持分布式以及主从关系进行主从复制,所以将来人人贷可能会弃用Apphouse,使用Habor来做私有仓库。Habor是一个开源产品,可以看到它内部的实现原理,Apphouse虽然免费,但是它是闭源的。

最终流程及总结

最终人人贷落地实现了这个过程,由开发人员提交代码到Stash,输入版本号以及分支名通过Jenkins进行构建,推送到image。在发布的时间通过调用Marathon的API进行发布,拉取image,最终运行在Mesos Slave节点上。

接下来人人贷希望实现部署多套环境,对于项目名称进行模板化处理,并且通过Jenkins实现完全自动化。个人认为落地的过程中,主要问题就在于配置管理。谢谢大家。