网易PaaS On Kubernetes实践

MacMillanDempsey 发布于13天前
0 条问题

【编者的话】随着Kubernetes日趋成熟与稳定,网易云将其列为最重要的基础设施,成为云计算的底座。在此背景之下,PaaS团队的目标自然也将适配Kubernetes列为了其首要支持目标。但是在实际落地过程中,我们遇到了很多问题,本文将分享一下网易在PaaS服务在迁移上Kubernetes过程中的问题和我们的应对之道。

调研

众所周知,Kubernetes处理无状态应用最为合适,Pod的短生命周期特性和无数据本地存储都是为无状态应用而生的,但是有状态应用是否也适合上Kubernetes呢?最开始我们对此是持怀疑态度的,直到发现Operator的存在。Operator是由coreos公司提出的一个概念,定位为一种打包、部署和管理Kubernetes应用的一种方法。关于Operator诞生的历史,可以参见:

Operator的工作原理并不复杂,如下图所示:

网易PaaS On Kubernetes实践

原理

Operator通过Watch ApiServer来捕获CR的请求,然后创建对应的资源来“组装”成我们需要的集群。CR所属的子资源的状态也通过ApiServer反馈给Operator,Operator来做相应的协调处理,整个过程清晰明了。

原理不复杂,关键在于Operator的开发模式与我们以前做PaaS管控的逻辑出入是很大的,主要表现在以下两个方面:

  1. 基于声明式的开发模式,而不是命令式。
  2. 假定资源的状态变化是高频的,而不是低频的。

对我们冲击最大的就是声明式的开发方式,它强调一开始就把最终的结果描述清楚,不管过程;而我们已经的开发模式基本上都是命令式的,由用户通过一些列的Restful“命令”来组装成他需要的集群。

声明式的优势:

  • 强调结果,而不是过程
  • 对使用者友好
  • 简化开发工作

缺点也很明显:

  • 性能。针对某些大规模的场景,声明式可能没有命令式处理高效。

    但是对于PaaS服务的管控端而言,性能不是主要指标,稳定性和可维护性更加重要。所以声明式的开发方式应该是对PaaS的管控端开发更加友好。

另外,还一个显著的区别在于,相比于传统的VM架构,Kubernetes集群上的资源似乎更加“不稳定”。我们分析发现,这种不稳定性来源于多个方面:

  • 混部。一个Kubernet集群可以承载的负载类型非常多,业务容器、PaaS容器和大数据相关的容器都可以跑在一个Kubernetes集群中。虽然可以通过给Node打标签,配合一些调度策略将不通的业务隔离开,但出于提高利用率的考虑,又不会隔离的非常严格。这样就可能造成资源的抢占,从而带来风险。
  • Docker较弱的隔离性。Docker是共性操作系统内容,基于Namespace的隔离还不够完善,可能带来潜在风险。
  • 复杂的Controller关系。Kubernetes的一大优势在于其高度的自治性,这种自治性通过各自各样的Controller来完成,同时Controller之间又存在着隐含的层级关系。

这种“不稳定”因素的存在迫使我们在设计之初就要考虑服务的自愈能力。实际上,Kubernetes已经提供了非常强大的自愈能力,我们更多要考虑的是让PaaS如何利用这些能力。

在调研过程中,我们发现其实现在已经有非常多的PaaS服务迁移上了Kubernetes,awesome-operators上有众多开源的Operator项目,有官方的也有第三方开源的。这进一步坚定了我们选择Operator的决心。

标准化

在云1.0和2.0的研发过程中我们发现了一个很大的问题,在于各个PaaS服务的管控端都是每个PaaS团队各自开发,基本上没有代码复用。有一两个团队出于自己代码维护性地角度方便,开发了一些SDK包来封装与IaaS之间的交互,但这些SDK包并没有经过良好的设计和抽象,导致其很难在其他PaaS之间共享。这样带来的一个直接问题就是研发效率低下。一个PaaS服务从立项、开发、测试和上线大概需要2~3个月的时间,这还不包括对接各种横向服务,如计费、SAM、资源池等。另外一个问题在于,管控端质量取决于PaaS人员的水平,一些共性的问题反复发生,没有集中性的技术手段来规避这些问题。

为了避免重蹈覆辙,在PaaS on Kubernetes立项之初我们就强调通过标准化规范来约束PaaS Operator,通过“中台”小组来解决PaaS共性的问题。(这里的中台应该叫PaaS公共服务更为合适)

我们在充分调研的情况下,结合Redis和Kafka迁移上Kubernetes的实际项目经验,制定了一套标准化的规范。该规范包含以下几个方面:

  • 文档规范:必须包含需求文档、概要设计和详细设计,尤其是需求文档,一定是要从业务方的痛点出发,说明该项目的价值和意义。
  • 设计规范:包括设计原则,最佳实践和CRD的详细设计要求。
  • 开发规范:使用Go为开发语言,OperatorSDK为开发框架,Api设计遵循社区规范。
  • 高可用要求:必须容忍单节点异常,多机房部署要容忍单机房异常。
  • 部署规范:所有的Operator都需要发布到轻舟应用商店;镜像制作要使用统一维护的基础镜像,禁止使用latest标签;统一使用脚本管理系统来分发宿主机上的管理脚本等。
  • 运维规范:定义Operator和人工运维的边界;日常巡检的内容;应急预案的要求。
  • 测试规范:由QA团队制定,包含单元测试、e2e测试、功能场景测试、数据面稳定性测试、管控面和数据面异常测试、性能测试等。
  • 监控报警:基础的监控指标、数据面的采集指标和采集方式、管控面的采集指标和采集方式、报警的规范和原则。

目前标准化的内容已经涵盖非功能性80%的内容,功能性大概40%左右,可以说做到了PaaS研发过程的基本覆盖了。有些内容很难通过标准化的规范来约束,我们通过白皮书的形式来进行说明,进一步覆盖实际开发过程中的可能遇到的问题。

扩展

PaaS迁移上Kubernetes的过程中遇到了很多问题,我们发现原生的Kubernetes的能力还不能满足我们的需求。为此,我们和Kubernetes团队合作,将我们的需求统一化,由Kubernetes团队来实现这些扩展能力。

调度

PaaS服务的调度与无状态应用还是存在很大的差别,主要在于PaaS对高可用的要求更高。比如,我们希望Redis Cluster不超过1/3的Pod分布到同一个Node上,不超过1/2的Pod分布到同一个机房里面等等。我们将这种扩展调度的需求放置到一个ConfigMap里面,由Kubernetes来实现统一的扩展调度器。

apiVersion: v1

kind: ConfigMap

metadata:

name: config-map-name

namespace: cluster-namespace #实例集群所在的ns

data:

cluster-size: 100  //集群大小

max-pod-on-node: 33 //单节点最多能调度的Pod(包含)

max-pod-in-zone: 50 //Zone内最多调度Pod(包含)

available-zones: cn-east-1a,cn-east-1b,cn-east-1c //必须调度的可用区

max-pod-on-node就可以限制整个集群在单个Node上调度Pod的数量

max-pod-in-zone可限制单个机房内调度Pod的数量

available-zone用来实现AZ的MUST IN语言,从而满足多机房特性

MUST IN语义的实现其实比较困难,这与Kubernetes的调度机制有关。Kubernetes是基于Pod进行调度,通过预选和优选来过滤出符合条件的Node。然而,PaaS服务很多时候需要有“全局视野”,局部调度最优但不代表全局调度就是最优的。

我们Redis Cluster采用了多个StatefulSet来管理分片,每个StatefulSet的0号Pod为主分片,1号Pod为复制分片,要求多机房的情况下主分片和复制分片不能在同一个机房。如果由Kubernetes随机调度,那么有可能就会发生死锁问题,可调度的Node越少发生死锁的概率就会越高。下图详细说明发生这一问题的过程,已经目前我们的解决方法。

网易PaaS On Kubernetes实践

死锁问题

但是这种解决方式存在局限性和特殊性,并不能应用于所有的情况。问题的核心还是在于PaaS调度需要有“全局视野”,我们需要提前规划好Pod的分布情况,但是现有Kubernetes的调度机制限制了这方面的能力,除非我们自定义PaaS的“专属调度器”。

本地盘

很多PaaS服务都有存储的需求,这也有状态服务的一大特点。云原生架构推荐我们存储架构分离,但是这需要强大的网络支持,所以本地盘还是相对现实靠谱的方案。Kubernetes原生对本地盘的支持不太好,主要在于Local PV需要手工管理和维护,为止Kubernetes团队帮助我们开发了基于LVM的本地盘管理插件。

管理员只需要按如下方式来申明可用的盘和机器信息即可。

apiVersion: node.netease.com/v1

kind: LocalStorage

metadata:

name: ls

spec:

disks:

- /dev/sde

node: 172.24.5.4

storageClass: localstorage-class

vg: k8svg

status:

allocatable: 676475Mi

capacity: 762491Mi

phase: Active

通过自定义storageclass的方式给我们提供了相当高的灵活的和扩展性,可以满足共享盘和独立盘的功能,只需要建立不同storageclass即可。

IP保持

IP保持Kubernetes团队开发的扩展能力,它是在Pod重建以后还能保持以前分配的IP,从使用方式上表现得更像VM一样。实际上这种使用方式是违反Kubernetes的设计理念的,但是出于调试、运维、查看日志等需求,业务方希望能保持Pod的IP。我们使用这一功能是因为我们遇到以下的场景。

Redis集群中某个Pod挂掉以后,原先分配给该Pod的IP可能被其他集群复用,造成元信息混乱,客户端有可能连接到一个另外一个集群的Pod,造成访问异常。

这是一个合理的场景,如果PaaS的节点之间或者Client与服务节点之间缺少认证机制,仅靠IP地址来建立信任关系,确实会存在上诉的场景。但IP被错误的Pod复用的概率取决于可分配IP池的大小,如果IP池足够大,出现这种概率的情况还是极低的。

目前我们还没有找到一种相对简单的方式来规避该问题,但我们还是不推荐使用该功能。

产品化

PaaS开发的Operator都将集成到轻舟平台的应用商店。标准化规范要求Operator统一使用OperatorSDK进行开发,它自动化生成CSV文件,而轻舟应用商店通过Operator Lifecyc Manager来统一管理和运维Operator,两者可以无缝对接,部署难度大大降低。

同时前端界面是一套,无须为PaaS服务做定制化开发,前端研发效率大大提高,使用方式也更加统一。业务方使用也是非常友好的。业务只需要在应用市场订阅所需要的Operator即可使用到PaaS服务。当然,在产品化集成方面,Operator离一个完整的产品还存在差距,但为了尽量剥离这些商业化逻辑,让PaaS Operator更加纯粹,我们正在开发Operator Assistor这样的统一适配组件,来满足权限、配额、计量计费的产品逻辑。

网易PaaS On Kubernetes实践

Operator应用商店

总结

从2019年8月开始做Operator,到年底已经上线了3个Operator(Redis Cluster、Kafka、Zookeeper),我们的研发速度大大提高。从大家的反馈来看也十分积极。经统计,编写Operator所需要的代码比起1.0和2.0的管控代码大概减少了80%以上,可用性提高的同时,运维成本还降低了很多。由于今年还未大规模部署,预计明年基于Operator托管的PaaS服务将遍地开花,我们人均的运维规模将大幅提升。

原文链接: https://michael-j.net/2019/12/24/ 网易PaaS-On-K8S实践/

查看原文: 网易PaaS On Kubernetes实践

  • greenlion
  • blacklion
需要 登录 后回复方可回复, 如果你还没有账号你可以 注册 一个帐号。