百分点大规模Kubernetes集群实践

更新时间:2017-01-05 18:06:23 点击次数:2512次

去年8月底,百分点与云知声联合发布了Google开源的集群管理系统Kubernetes的“发行版”——Sextant。在百分点大规模Kubernetes集群经过四五个月的应用实践后,到目前为止,集群上已经承载了百分点推荐系统的大部分业务组件和部分的运维组件。那么,在使用过程中会遇到哪些问题?如何解决?本篇将详尽总结百分点在实践中的经验教训,期望能够更多地回馈社区。

从0到1

在传统的集群管理方法下,百分点服务器利用率长期处于20%以下。通常为了完成某个业务目标,团队会申请各自的服务器,然后工程师使用跳板机登陆到这些服务器上完成程序的部署。

这样的弊端是:首先,这些服务器上的空闲资源并不会贡献出来为其他团队所使用;其次,这些服务器在解决业务高峰问题之后,负载下降,而这时团队并不希望服务器被回收,因为不知道如何备份服务器之上的数据。

这样,集群服务器利用率逐步降低,整体集群的维护和管理也变得异常困难,在百分点AI技术运用增多的趋势下,常遇到计算资源不足而导致业务进展缓慢的情况。

如何解决呢?

我们做了很多尝试,终决定选择CoreOS、Kubernetes(以下简称K8s)、Ceph相结合的技术方案。

对于Kubernetes在生产环境中的应用,百分点是比较早的一批实践者,从开始关注Kubernetes1.0,到将1.2版本实际部署到我们的生产环境中,围绕Kubernetes做了很多周边工作,使Kubernetes能够更好地服务于业务场景。

限于篇幅原因,这里不展开介绍Kubernetes的基本原理和概念了,感兴趣的读者可以在我们的githubsextant项目中,找到相当丰富的文档。

为了达成这样的目标,我们要求开发者使用Docker将自己的应用程序完成封装,逐步将手动的集群部署,切换到使用K8S的集群容器编排之上。如下图所示,需要在团队项目的gitlab repo中增加相应的Dockerfile和编排文件内容,CI环境会自动将应用完成编译->单元测试->docker镜像打包->镜像提交的工作。封装在容器中的应用使用Ceph存储数据,并通过ingress LoadBalancer对外部提供服务。

图片描述

对于Kubernetes在生产环境上的部署,我们希望大限度的简化K8S集群维护人员的工作。比如扩容一台机器、下架维修一台机器等,只需要维护人员直接完成开机/关机的操作即可。由于K8S的调度编排,可以屏蔽这类操作对应用的影响。

三步完成集群安装

首先要解决的问题,就是如何能够高效的、自动化的进行组件的部署以减少手动部署可能带来的问题。

百分点、云知声在百度科学家王益带领下,合作开发了基于PXE自动化安装CoreOS+Kubernetes集群的开源Sextant项目,只需要简单的三个步骤即可完成集群的安装:规划集群->启动bootstrapper->节点开机自动安装。

图片描述

操作顺序:

下一步就是应用迁移,在收获中也充满了痛。

收获和痛

至此,我们自认为可以开始像习大大元旦助词说的那样“撸起袖子”,进行逐步的迁移工作了。但经过简单的性能测试后,结果并不理想。运行在K8S之上的服务响应延迟,导致出现至少20%的性能损耗。在踩坑之后,我们对K8S的网络有了更加深入的理解。

一、打造kubernetes高性能网络

熟悉Docker的读者可能会了解到,Docker容器有三种网络模式,但为了达到容器内的网络环境隔离,通常会选择使用NAT方式完成容器内的网络包转换和转发。这样,在同一台主机上启动的容器或不同主机启动的容器之间,除了配置NAT端口的4层地址可访问外,都不可以直接互相访问。

Kubernetes的解决思路和Bridged模式的虚拟机群很像——用一个通用的IP地址分配服务,为运行在各个host上的container统一分配IP地址。这样运行在不同host上的containers之间通信,直接使用对方的container IP地址就可以了,而不需要考虑host IP。这实际上把Docker模式中的host IP和containerIP这两层IP地址变成了一层。

在Kubernetes的文档里阐述了一个叫Pod的概念,并且解释一个Pod里可以运行一个或者多个Docker containers。实际上,一个Pod就是一个Docker container。所谓在Pod里运行的多个containers,实际上是启动的时候加了–net=container:参数的containers,它们不会得到自己的IP地址,而是和pod container共享IP地址。这样一来,一个pod里的containers之间通信的时候可以用localhost地址,而跨越pod的通信用pod IP。 看上去Kubernetes的做法里相对于Docker的做法,多了一层Pod的概念。

但是实际上每个container里约定俗成地只运行一个服务进程,所以还是三层概念:

图片描述

Kubernetes实现这种网络结构有多种方法,如overlay networking、BGP和其他SDN技术,常见的实现包括:Flannel、 Calico、 L2 networking、OpenVSwitch等,我们对常用并活跃的项目进行了针对性评测,结论如下:

图片描述

可以看到,在L2模式下,针对高性能web应用场景可以达到佳性能。当然如果有专用的SDN交换机设备,也可以大大提高SDN的网络性能。但综合成本、方案复杂程度、方案后续可扩展性考虑,终选择flannel host-gw模式。这个模式,要求所有host保持稳定的2层网络连接,然后通过Linux路由表,将Docker bridge的包完成3层转发。

另外一点,在评测过程中发现,linux加在netfilter和iptables相关内核模块之后,平均网络延迟会下降10%左右。但就目前状态来说,使用iptables NAT作为Kubernetes的service负载均衡仍然是性能高、简单的方式。后续如果可以使用更的方法提供service负载均衡,可以去掉iptables以降低容器之间的网络延迟。

在这种网络部署下,使用普通的千兆网卡和千兆交换机,即可以较低成本来搭建大规模的集群,并获得相对可观的性能。在针对网络延迟有更高要求的服务,比如Redis等,则考虑直接物理部署作为折中方案。

二、打造高可用的前端负载均衡器

从上面的介绍可以看出,Kubernetes service主要仍是针对数据中心内部互相访问,若要方便地提供HTTP web服务的创建,则需要引入Ingress的概念。

众所周知的是,Kubernetes中的Service可以将一组pod提供的服务暴露出来供外部使用,并默认使用iptables的方式提供负载均衡的能力。Service通过使用iptables,在每个主机上根据Kubernetes service定义,自动同步NAT表,将请求均衡的转发到后端pod上,并在pod故障时自动更新NAT表。相对于使用userspace方式直接转发流量有更高的效率。常用的Service有ClusterIP、Loadbalancer以及NodePort方式。

从上面的介绍可以看出,Kubernetes service仍是主要针对数据中心内部互相访问,若要方便地提供HTTP web服务的创建,则需要引入Ingress的概念。

1.Ingress

对于对外提供服务的web应用来说,需要提供7层反向代理的机制,使得公网的流量可以转入集群之中。百分点采用的是Nginx,通过WatcherKubernetes中Ingress资源信息,动态修改对应的service匹配endpoint的地址,使得整个配置流程只需通过kubctl提交一个配置即可。Ingress作为数据中心web请求的入口,将流量引入到集群内部,完成处理后经由Ingress返回外部请求者。这样一来,任何一个部署在kubernetes上的web应用,都可以简单的通过提交一个Ingress资源,完成web请求对外的开通。

2.Ingress HA

Ingress的机器是整个集群的入口,如果其中一台机器出现故障,带来的影响将会是致命的。我们也曾考虑过使用F5等技术做前端的高可用,但后基于成本和可维护性考虑,终使用Keepalived+vip的方案。 
图片描述

3.Ingress优化

三、打造一体化Kubernetes集群服务

作为一个集群化的操作系统,基础服务必不可少,开发者通常需要经常查看服务的日志,查看监控数据,查看运行状态等。我们为Kubernetes集群配置了很多基础类服务,使集群使用起来更加高效。

1.日志管理

当我们的应用运行在集群操作系统上时,如何高效地查看、分析服务日志是一个必须要解决的问题。百分点采用了Fluented+Elasticsearch+Kibana的方案,整个套件也都是运行在Kubernetes集群上的。

图片描述

2 . 系统监控

通过heapster+collectd+influxdb+grafana解决多源数据采集、监控数据存储、查询展现的问题。

图片描述

3.统一Dashboard 
为了简化kubernetes集群的使用,百分点的技术团队开发了Sirius系统,使用户使用起来更加的方便,并且此项目也在Github上进行了开源。

图片描述

4.持续化集成

Docker是我们落地Devops理念的核心技术,从开发人员写下行代码开始,我们构建了这样一条持续集成的流水线。

我们选择了Gitlab作为代码仓库,当开发人员向Gitlab提交代码,Jenkins会监听每个tag,每次push事件,有选择的自动构建为docker image,并推向Docker Registry,存储在我们的Docker仓库中。随后,Jenkins会将新版本的镜像推到集成测试的Kubernetes集群中,完成一次构建、测试、预上线的流程。待测试通过后,再发布到生产环境。

图片描述

5.持续化部署

在逐步将线上应用迁移到kubernetes集群过程中,当然也遇到不少问题,每个应用在提交之后需要经过多次修改和更新才可以正式上线,为了方便更新、并尽量减少人为操作的失误,我们使用“编排文件版本管理+kubernetes deployment”完成持续化部署。

四、打造统一持久化存储平台

Kubernetes在运行时是基于容器技术的,这就意味着容器的停止会销毁容器中的数据。若应用要使用持久化的存储,如果直接挂在容器所在主机的磁盘目录,这个编排系统会显得十分混乱。虽然Kubernetes提供了诸如hostPath机制,除非应用和主机具有非常明确的绑定关系,否则不推荐使用。这样,我们需要一个通过网络可访问的存储池,作为统一的集群存储平台。选型的问题这里不详细展开,我们中使用ceph作为Kubernetes的后端存储。

在部署时,考虑到kubernetes编排的网络请求可能和ceph的数据存储请求抢占网卡带宽而导致整体集群瘫痪,预先将kubernetes访问ceph集群的网络使用单独的两个网口做bond0之后连接ceph集群的交换机。同时为了防止多个容器突发性的高IOPS对ceph集群的访问,我们正在开发storage-iops的qos限制功能。

虽然ceph提供了3种存储访问的方式,我们还是选用了相对稳定的rbd,没有使用ceph filesystem模式。在rbd模式下,首先要保证内核已经加在了rbd.ko内核模块,和ceph-common包。这一步,我们在前面提到的sextant自动安装系统中已经完成打包。

接下来在使用rbd作为pod存储时可以参考示例:

{
     "apiVersion": "v1beta3",
     "id": "rbdpd2",
     "kind": "Pod",
     "metadata": {
         "name": "rbd2" },
     "spec": {
         "containers": [
             {
                 "name": "rbd-rw",
                 "image": "kubernetes/pause",
                 "volumeMounts": [
                     {
                          "mountPath": "/mnt/rbd",
                          "name": "rbdpd" }
                 ] }
         ],
         "volumes": [
             {
                 "name": "rbdpd",
                 "rbd": {
                      "monitors": [ "192.168.0.1:6789" ],
                      "pool": "rbd",
                      "image": "foo",
                      "user": "admin",
                      "secretRef": {
                                                     "name": "ceph-secret" },
                      "fsType": "ext4",
                      "readOnly": true } }
         ] } }

目前,我们已经使用kubernetes+ceph rbd部署使用了MySQL、MongoDB、Redis、InfluxDB、ElasticSearch等服务和应用。

百分点实践总结

到目前为止,百分点的Kubernetes集群上承载了推荐系统的大部分业务组件和部分的运维组件。Kubernetes相对来说还比较新,集群上也需要更多的工具才能让用户应用起来更加的方便。非常感谢Kubernetes社区、王益以及云知声公司的技术团队,百分点会持续专注在Kubernetes的建设,期望能够更多地回馈社区。

本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责,本站只提供参考并不构成任何投资及应用建议。本站是一个个人学习交流的平台,网站上部分文章为转载,并不用于任何商业目的,我们已经尽可能的对作者和来源进行了通告,但是能力有限或疏忽,造成漏登,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

回到顶部
嘿,我来帮您!