Kubernetes 遇上企业应用
作者:陈晓宇
才云科技
2017-12-19 06:23


陈晓宇 / 新智云数据服务有限公司/PaaS 平台首席架构师
嘉宾介绍:
北航硕士毕业,从事多年 IaaS 和 PaaS 相关开发工作,对于云计算相关领域有深入了解,热衷于 SDN、云存储等相关技术。多年 Java、Python、Golang 开发经验,Kubernetes、Harbor 和 Openstack 等多个开源软件的 Contributor。当前就职于新智云数据有限公司,负责整个 PaaS 平台的架构设计工作。

大家下午好,我叫陈晓宇,来自新智云,我主要跟大家分享一下我们在使用 Kubernetes 整个过程当中如何去选型、落地,如何使用,使用过程当中遇到的问题和大家做一些分享。 第一,容器相关的知识。第二,Kubernetes 和企业应用的差距;第三,我们做了什么;第四,我们现在正在做的,以及以前踩过的坑;最后,介绍一下我们的客户案例。


PaaS 云平台相关技术介绍

我简单介绍一下我们公司,我们公司是一个能源公司,主要是在全国铺设天然气管道为主的,为每个城市铺设天然气管道,从中收取利润。我们公司现在也有千亿市值,4.5 万员工,旗下 300 多家子公司,我们也是其中的一个子公司,我们这个子公司主要负责其余 300 家子公司的 IT 建设,所以我们可以相当于整个集团下面的 IT 部门。

PaaS 平台

我们的 Paas 平台是基于 Kubernetes 的企业级容器云平台,这是我们平台的特点,第一是基于Kubernetes。我们之前也走过一些弯路,之前选择了其他的一些方案,后来也慢慢地摒弃才转到了 Kubernetes,也不是说一蹴而就,一开始就选择 Kubernetes 的,之前也使用了 Rancher 等其他的管理软件,现在只剩下 Kubernetes。第二它是一个容器云平台,这不同于虚拟机,首先它是一个基于容器的云平台,在此之上做了自己的 DevOps 等。


Docker

关于 Docker 这方面就简单地说一下,因为有些人对于它接触的时间不是很长,Docker 本身并没有什么新的技术,它只是将 Namespace 和 Cgroup 这些相关的技术整合在一起了,这并不是 Docker 首创的,只是 Docker 将这些开源的东西整合在一起了。譬如PID、IPC、Network、Mount、User 和 UTS,这六种 Namespaces 随着内核版本的升级与发布,本身都是内核支持的,Docker 只是将它们整合在一起的。个人认为 Docker 最大的贡献是它定义了一个镜像,Docker 的 Image,这是 Docker 最大的贡献。从 Docker 运行容器到 Docker 镜像最终推送到 Docker 仓库然后再拉取下来运行,Build、Ship、Run 整个流程都是 Docker 最大的设计理念。


Kubernetes 结构

下面看 Kubernetes 整个的结构,是 Master 和 Slave 结构的,Master 也可以做成高可用的部署,首先前端是一个认证和授权,用户认证即你是谁,Kubernetes 没有常规的用户信息,没有保存用户信息;授权只是针对某些角色做一些授权,譬如 RBAC,下面是一个 API,API 对接的后端是 ETCD,就是说 Kubernetes 所有的元数据信息都在 ETCD 存储,包括 PODs 信息、Services 信息、Replicaset 信息全部放在 ETCD 里存储的,旁边是一个 Controller  Manager,Controller  Manager 是资源管理,如保持副本数是通过 Controller  Manager 完成的,而上面的 Scheduler 只是创建做调度用的。
第一个是过滤,如对主机上端口冲突过滤,第二是打分,排列优先级,譬如资源使用率。最右侧是 Kubelet,这个是真正做事情的,它去同步 Master 状态,如果发现自己的节点被 Scheduler 调度:Scheduler 会将节点信息 Bind 到 Pod 上面,Kubelet 监听到这个事件以后会创建容器,Kubelet 是真正负责启动和管理容器的。


K8S 和企业应用的差距

既然 Kubernetes 这么好,我们是不是可以直接将 Kubernetes 拿来直接用呢?并不是。其实 Kubernetes 本身也有很多的问题和真正企业落地之间有很多的差距。


最简单的问题是多租户如何解决?这家企业有 300 多家子公司,Kubernetes 如何给 300 家子公司使用,是部署一套,还是给每个子公司部署一套?这是 Kubernetes 最大的问题。
还有就是它只管容器,那企业里边的应用如何迁移到这个 Kubernetes 平台上?而 Kubernetes 使用 yaml 文件的方式去做声明的,不是所有人都会写 yaml 文件的,对于传统用户来说不知道容器,也不知道 Kubernetes,也不知道如何编写 yaml 文件,以及把服务放到平台上去,服务如何对外提供,如何暴露,如何请求服务,还有就是容器的一些配置及管理,怎么在 Kubernetes 上完成。

我们做了什么

针对以上问题,我们做了什么呢?我们做的是让 Kubernetes 容易使用,我们希望对于一个不太了解容器,甚至不太了解 Kubernetes 的人不用关心底层是到底平台就可以将应用放在我们的平台上去跑。


它是开源方案的整合,我们的系统里很少是东西是自己去自己研发的,除了 CI/CD 是 Golang 是自己写的,其他东西都是利用开源包括 Kubernetes、Prometheus,CEPH、Harbor、Calico 这些东西都是开源的。在开源之上我们构建了自己的一套用户管理系推、容器管理系统、应用管理系统、服务管理系统、网络管理、镜像管理、存储管理、监控告警,整个一套东西是我们基于开源的中心构造了整个外围的东西,包括了一些日志、监控。

多集群管理

第一,我们做的是多集群管理,这是一个场景。这个多集群并不是说了 Kubernetes 的联邦,多集群管理来自于我们以前做 IaaS 的经验,我们以前做 IaaS 有一个 Openstack 资源池,但可能有一个 VMware 资源池,所以这个管理系统既可以管理 VMware 又可以管理 Openstack,你需要有一个统一的管理平台。
左边和右边分别是两个 Kubernetes 资源池,我们通过对接 Kubernetes API 来管理两个或多个 Kubernetes 资源池,这是多集群管理。每个 Kubernetes 资源池都会部署监控、网络管理和存储,都是独立的,只是在上面的独一资源管理的试图里边可以看到多个 Kubernetes 的集群,这一点与 Kubernetes 联邦最大的区别。上面是一套 CI/CD 系统和监控告警系统。


应用管理

第二是应用管理,这是我们做的第一个事情,将应用给抽象出来。虽然 Kubernetes 有一个 ymal 文件,相信很多没有做 Kubernetes 的人根本不会写 Kubernets 的 yaml 文件,如何将应用迁移过来?我们首先要定义好什么叫应用,什么叫服务,什么叫容器,这套东西要先搞清楚。我们自己这边定义的应用,比如我的网站有前端和后端,前端的页面是前端服务,后端的数据库是数据库服务,所以应用和服务是应用下的多个服务,应用服务有多个容器,比如 Redis 是一个集群,所以我这个服务下有多个容器,所以一个应用里边有多个服务,一个服务里面有多个容器,是这样的概念。所以这个概念先要搞清。


我们在服务创建的流程,就相当于用户以前需要自己写 yaml 文件,现在通过图形化的方式让用户选择镜像,即设置 ymal 文件 Image,我们可以设置副本数、配置资源、Limit 和 Request,设置容器的网络和环境变量,这些东西原本需要用 yaml 文件做的方式现在通过图形化的方式将它简单化了,将 yaml 文件变成一个图形,这是我们做的最重要的一件事情。


还要设置容器的数量,就是一个 yaml 文件里的副本数,下边还有一个访问方式,这是很特殊的,这个访问方式有集群类、内网和公网。我们在集团内部有 300 家子公司,其实我们的网络是分为三层的,第一层是我们的网络是集群内部的访问,是在整个 Kubernetes 集群内,因为是集群内调用服务的方式,所以是 Kube-proxy。


还有是内网,只能在集团内网,公网是不允许访问的,最右边是外网出口,可以暴露到互联网上,所以服务在创建时需要选择服务到底暴露在哪里去,这个是用户选择的。而且支持多租户,每个用户只能看到自己创建以及公共的网络出口,网络出口就是一个Haproxy 的负载均衡,这个支持多租户,回话保持。之所以看到集群内是 TCP/UDP,因为这是 Kube-proxy 支持的,Haproxy 不支持 UDP 的,所以内网和外网没有 UDP,只有 TCP/HTTP,是这个原因。
当然,在此基础上我们将 Kubernetes 滚动的升级和版本回滚全部整合到页面,通过页面的方式可以选择用户升级到哪个版本。左边是示意图,右边是页面截图。


我们将 Kubernetes 支持的 Comfigmap 和 Secret 全部整合进来了,上面是页面的截图,我只要定义好一个配置文件就可以将配置文件挂到文件里去,这是 Kubernetes 的 Configmap 的使用。下边 Secret,我有一些加密的东西传输到容器里,我通过这种方式挂到容器里去。


这是应用商店,我们所有的用户都会存在这样一个问题,现在已经有了东西,他也不会是 yaml 文件,对容器也不太了解,怎样做一个集群?比如要做一个 ETCD 集群?我们定义了一个模板文件,你只要按照模板文件去写,ETCD 里边需要配置兄弟节点的只要用一 “PEER” 的符号去标识,生成文件时会会自动替换成兄弟节点,改完之后的文件会注入到容器里边,这样的话整个 ETCD 集群就可以搭起来了,从公网上拉取一个镜像就可以直接做成集群,这是我们想要做的目标。
有很多应用,比如我是 MYSQL 或 REDIS,我可以从公网上拉一个 ETCD 的单独的镜像就可以做成 ETCD 的集群,这可以降低用户的使用难度。通过定义的模板文件,我们自动将模板文件替换成相应的真正的容器,比如定义成一个 ”ALL”,在后台系统读到 “ALL” 会自动将 “ALL” 替换成所有的节点信息,这个信息就会被容器里的应用所使用了。


还有一个是我们底层先有 IaaS 再有 PaaS,这是基于青云自由云,我们是借助青云的能力去做的,如数据库,很多人支持将数据库放在容器里边,但我们还是有所保留的,比如数据库的监控和备份单纯用容器做的话会带来很多麻烦,所以很多时候将容器直接使用青云数据库,这也是 Kubernetes 支持的外部服务的方式。我们定义一个服务的名称,可以在集群内通过服务名称进行访问,这是 Kubernetes 本身支持的外部服务,即容器可以调用 Kubernetes 集群之外的服务。


我们集成了 Harbor 的镜像仓库,这 300 家子公司,每个公司都有一个私有的镜像仓库,但整个集团还有整个集团的公有的镜像仓库,公共仓库可以被任何人访问,但每个私有镜像仓库只能被自己公司访问,这是用户关联仓库的整个流程。


用户登录时,我们在 Kubernetes 给每个客户建立一个 Namespace,而且还会在 Harbor 里边建一个 Project,这样用户使用时登录进去就能看到自己的空间,并且可以使用 Harbor 上的 Project。然后创建 Image Pull Secrets,这个是在镜像拉取时候使用的。


我们在 Harbor 之上还加了一些自己的功能,Harbor 本身是不支持从公网上拉取镜像,并且 Harbor 不支持从一个 Project 拷到另外一个 Project,在自己的场景里是有的。用户觉得公网镜像非常好,直接填写公网镜像下载下来。
第二个功能是从一个 Project 拷到另外一个 Project,这是一个公司的两个部门,想要两个镜像做共享,窗口的方式必须要 PULL 下来再 PUSH 上去,这样的话很麻烦,我们能做的是把它从一个 Project  拷贝到另外一个 Project,这是我们在 Harbor上开发的东西。


我们后端是青云 S3 的镜像存储,这是 Harbor 的高可用的方案,大家可以共享一下。


我们自己做了一套基于自己的 Golang,CI/CD,我们当时建基础团队时全部写 Golang,所以整个技术站全部用 Golang,但我们想要做一套自己的 CI/CD,当时我们也是用 Jenkins,但 Jenkins 无法支持多租户,300 多家公司不可能每个公司支持 Jenkins,这样维护难度过大,我们要做的是做一套 CI/CD 系统让 300 家子公司可以用。
这是我们自己定的开发生产整个流程,从开发提高代码,到代码编译,打包,然后到测试环境,这是整个流程。

我们做的 CI/CD 是让用户在页面用 TAP 页的方式自己配置,配置完一个一个的 TAP 页,我们像工作流一样将用户定义的 TAP 页做完。当用户提交完代码到 GITLAB、SVN  或是我们自己用的 Golong 写的 GOGS。当代码提交触发了 Webhook,我们就开始拉取代码做代码的编译,编译完之后打包成一个 Docker 镜像推送到 Docker 仓库里,这是整个流程。这个流程是用户在 WEB 页面里自己去定义的流程,定义完了之后把这个流程走完。从源代码编译成二进制文件,再用二进制文件编译成 Docker 镜像到 Docker 仓库。整个流程 CI/CD,我们是通过这样的方式来完成的。


这是 CI/CD 的一个结构,它后端对接了各种 GOGS、SVN、GITLAB 等各种代码仓库,从代码仓库拉取代码。在这个过程当中还有 JOB 的管理,我们这个代码是怎么编译的?其实是用 Kubernetes 的 JOB 来编译代码的,各个任务都使用了 Kubernetes 的JOB,整个流程采用 Filebeat 的日志采集。这样的话,在编译的整个过程当中我们就看到代码编译到哪一步了,哪一步出现问题都能够派上用场。


多租户的管理,300 多家子公司都都到同一个平台里边,看到的系统不同,怎么做资源隔离、组织管理?在整个系统里边,中间是主机上面有一层网络虚拟化和存储系统化,在下面是 CEPH 存储资源池,上面是 Calico 的网络。如果你是用新版本的话是支持Pod 跟 Pod 之间的隔离的,我们用的还是原版本,只能支持到 Namespace之间的隔离,之间是不互通的,每个子公司之间的网络不互通。



我们还提供了日志和监控管理,在传统的日志监控里边,只能监控到容器的标准输出,传统的应用是这样的,它不仅有标准输出还有目录输出,还有 Warn 输出、Info 输出、标准输出等各种级别的输出,将这些些日志输入到某些特定的目录下,我们就可以把目录挂到 Emptydir 上面去,这样就可以通过 Filebeat 采集目录下的日志了。
还有多集群日志采集,在每个集群里边的容器里边都有自己集群的 Label 标签去筛选出来,现在将日志到对象存储里边去,你的用户保存的时间比较长一点。我们现在只保存一周的日志量,日志量大的时候 Elasticsearch 就会出现性能瓶颈,查询就会慢了。前端有 API,通过用户查询到自己的日志,A 用户不可能查询到 B 用户的日志,这是最基本的。


这是监控系统、监控告警,我主要做的是告警出发,然后回调 ENN-API,一旦触发告警就可以通过 ENN-API 做多租户的告警。


简单说一下监控,它是通过 Cadvisor 的方式去采的,具体通过 Cadvisor API 去收集监控信息的,如果你们觉得自己的监控信息量比较大的话建议采用 Prometheus 联邦的部署方式。
我们为何做这个 PaaS 平台?很大原因是为了支持之前说的微服务系统,一套是 PaaS 平台,我们有另外一个团队基于 Protobuf+grpc 做了 Ceres 微服务管理系统,我们的应用做了微服务改造以后并不是简单了,反而是复杂的。单体的应用改造成微服务,不仅没有简化整个部署关系流程,反而加大了部署管理的难度,所以我们希望有一个 PaaS 平台去支撑整个微服务的系统部署、运行、升级与上线,起到支撑作用。



那些我们踩过的坑

下面介绍一下我们遇到一些坑,譬如 CEPH 的挂载,Haproxy 的稳定性,关于 Haproxy 我们建议单个 Haproxy 不要超过 20 个监听,这样性能会急剧地下降。Docker 资源占用,如果你使用 Docker devicemapper,它会有一个存储的大小设置,这一定要控制住,特别是挂到系统盘时,建议你们把 Docker 存储单独挂到一个盘,还有一些版本升级,后面会讲。

Prometheus 挂掉

Prometheus 挂掉,下面 storage.local.target-heap-size 参数设置,这个值请大家要注意,最好是设置成主机内存的三分之二,不能设置得太大不能设得太小,设得太小的话,热数据无法加载,导致查询的效率降低,如果设置太大会直接导致崩溃,因为它这个值的设置,Prometheus 达到一定的值,它会偏向于靠近这个值,但并不一定能够保证这个值,所以这个值不能设得太大。

CEPH 存储挂载与解挂

第二是 CEPH 挂载与解挂,我们自己改进的一个 Kubernetes 的问题,避免 Lock。


Kubernetes 新版升级

还有一个是 Kubernetes 新版升级问题,我们从 1.2 升到 1.4 再升到 1.6,这个版本的升级要保存数据,一般情况下的方式是直接导成 yaml 文件的方式批量导出,然后通过脚本将它改了,以批量导入的方式,这是我们现在使用的方式。


Caolico 网络规模

还有一点,如果你用的是 Calico 网络的话,一定要注意 BGP 的规模,我们当时开始网络规划并不是规划得特别好,单个网络也就是 254 个主机,24 位掩码情况,Calico 跨网段,需要在路由器或者三层交换机上打通 BGP 协议的,不然的话这个 BPG 是无法通过的,所以你们在初始时一定要把这个网段规划好,不要设得太小。而且 Calico 用 Mesh 的方式互联。全互联的方式,如果集群部门大的时候会导致网络性能急剧下降,建议是 400 个节点以下,如果超过 400 个节点就建议你用 Reflector 模式,不建议使用互联的方式。

我们正在做的

这是我们做的灰度发布,Kubernetes 的升级只是一个滚动升级,并不支持的灰度切换,我们在应用访问时可以根据 Header 将某些流量导入到版本 1 上,让某些流量导入版本 2 上,做到真正的灰度发布。


第一是历史日志对象存储对接。我们会定时地将 ES 数据放到对象存储,因为数据只保存 7 天。还有与 IaaS 联动的,因为我们有一些青云的资源,所以我们有些东西,譬如说我们的容器是跑到虚拟机的,而虚拟机资源不足就会去调用青云 API 去创建虚拟机,创建其他节点。


第二是服务的链路跟踪。这也是我们现在做的。我们能够跟踪微服务里面的服务之间的调用的顺序,从 A 调到 B,B 掉到 C,追踪问题。

客户案例

这是我们自己的网络设计平台。每个员工都会有一个 ICOME 的客户端,发工资发信息都会通过这个客户端去做,这整个后台已经放在平台上去跑了。


还有市场洞察,这是做舆情分析的子公司。



169