如何为云原生应用带来稳定高效的部署能力?

简介:5 月 28 日,咱们发起了第 3 期 SIG Cloud-Provider-Alibaba 网研会直播。本文聚集了这次直播完整视频回顾及资料下载,并整理了直播过程当中收集的问题和解答,但愿可以对你们有所帮助~node

头图.png

做者 | 酒祝  阿里云技术专家、墨封  阿里云开发工程师git

直播完整视频回顾:https://www.bilibili.com/video/BV1mK4y1t7WS/github

关注“阿里巴巴云原生”公众号,后台回复 “528” 便可下载 PPTapi

5 月 28 日,咱们发起了第 3 期 SIG Cloud-Provider-Alibaba 网研会直播。本次直播主要介绍了阿里经济体大规模应用上云过程当中遇到的核心部署问题、采起的对应解决方案,以及这些方案沉淀为通用化能力输出开源后,如何帮助阿里云上的用户提高应用部署发布的效率与稳定性。网络

本文聚集了这次直播完整视频回顾及资料下载,并整理了直播过程当中收集的问题和解答,但愿可以对你们有所帮助~架构

讲师图片.jpg

前言

随着近年来 Kubernetes 逐渐成为事实标准和大量应用的云原生化,咱们每每发现 Kubernetes 的原生 workload 对大规模化应用的支持并不十分“友好”。如何在 Kubernetes 上为应用提供更加完善、高效、灵活的部署发布能力,成为了咱们探索的目标。app

本文将会介绍在阿里经济体全面接入云原生的过程当中,咱们在应用部署方面所作的改进优化、实现功能更加完备的加强版 workload、并将其开源到社区,使得如今每一位 Kubernetes 开发者和阿里云上的用户都能很便捷地使用上阿里巴巴内部云原生应用所统一使用的部署发布能力。less

阿里应用场景与原生 workloads

阿里巴巴容器化道路的起步在国内外都是比较领先的。容器这个技术概念虽然出现得很早,但一直到 2013 年 Docker 产品出现后才逐渐为人所熟知。而阿里巴巴早在 2011 年就开始发展了基于 LXC 的容器技术,通过了几代的系统演进,现在阿里巴巴有着超过百万的容器体量,这个规模在世界范围内都是顶尖的。运维

随着云技术发展和云原生应用的兴起,咱们近两年间逐步将过去的容器迁到了基于 Kubernetes 的云原生环境中。而在这其中,咱们遇到了很多应用部署方面的问题。首先对于应用开发者来讲,他们对迁移到云原生环境的指望是:ide

  • 面向丰富业务场景的策略功能
  • 极致的部署发布效率
  • 运行时的稳定性和容错能力

阿里的应用场景很是复杂,基于 Kubernetes 之上生长着不少不一样的 PaaS 二层,好比服务于电商业务的运维中台、规模化运维、中间件、Serverless、函数计算等,而每一个平台都对部署、发布要求各有不一样。

咱们再来看一下 Kubernete 原生所提供的两种经常使用 workload 的能力:

1.png

简单来讲,Deployment 和 StatefulSet 在一些小规模的场景下是能够 work 的;但到了阿里巴巴这种应用和容器的规模下,若是全量使用原生 workload 则是彻底不现实的。目前阿里内部容器集群上的应用数量超过十万、容器数量达到百万,有部分重点核心应用甚至单个应用下就有上万的容器。再结合上图的问题,咱们会发现不只针对单个应用的发布功能不足,并且当发布高峰期大量应用同时在升级时,超大规模的 Pod 重建也成为一种“灾难”。

阿里自研的扩展 workloads

针对原生 workload 远远没法知足应用场景的问题,咱们从各类复杂的业务场景中抽象出共通的应用部署需求,据此开发了多种扩展 workload。在这些 workload 中咱们作了大幅的加强和改进,但同时也会严格保证功能的通用化、不容许将业务逻辑耦合进来。

这里咱们重点介绍一下 CloneSet 与 Advanced StatefulSet。在阿里内部云原生环境下,几乎全量的电商相关应用都统一采用 CloneSet 作部署发布,而中间件等有状态应用则使用了 Advanced StatefulSet 管理。

2.png

Advanced StatefulSet 顾名思义,是原生 StatefulSet 的加强版,默认行为与原生彻底一致,在此以外提供了原地升级、并行发布(最大不可用)、发布暂停等功能。而 CloneSet 则对标原生 Deployment,主要服务于无状态应用,提供了最为全面丰富的部署发布策略。

原地升级

CloneSet、Advanced StatefulSet 均支持指定 Pod 升级方式:

  1. ReCreate:重建 Pod 升级,和原生 Deployment/StatefulSet 一致;
  2. InPlaceIfPossible:若是只修改 image 和 metadata 中的 labels/annotations 等字段,则触发 Pod 原地升级;若是修改了其余 template spec 中的字段,则退化到 Pod 重建升级;
  3. InPlaceOnly:只容许修改 image 和 metadata 中的 labels/annotations 等字段,只会使用原地升级。

所谓原地升级,就是在升级 template 模板的时候,workload 不会把原 Pod 删除、新建,而是直接在原 Pod 对象上更新对应的 image 等数据。

3.png

如上图所示,在原地升级的时候 CloneSet 只会更新 Pod spec 中对应容器的 image,然后 kubelet 看到 Pod 中这个容器的定义发生了变化,则会把对应的容器停掉、拉取新的镜像、并使用新镜像建立启动容器。另外能够看到在过程当中,这个 Pod 的 sandbox 容器以及其余本次未升级的容器还一直处于正常运行状态,只有须要升级的容器会受到影响。

原地升级给咱们带来的好处实在太多了:

  • 首先就是发布效率大大提高了,根据非彻底统计数据,在阿里环境下原地升级至少比彻底重建升级提高了 80% 以上的发布速度:不只省去了调度、分配网络、分配远程盘的耗时,连拉取新镜像的时候都得益于 node 上已有旧镜像、只须要拉取较少的增量 layer);
  • IP 不变、升级过程 Pod 网络不断,除本次升级外的其余容器保持正常运行;
  • Volume 不变,彻底复用原容器的挂载设备;
  • 保障了集群肯定性,使排布拓扑能经过大促验证。

后续咱们将会有专文讲解阿里在 Kubernetes 之上作的原地升级,意义很是重大。若是没有了原地升级,阿里巴巴内部超大规模的应用场景几乎是没法在原生 Kubernetes 环境上完美落地的,咱们也鼓励每一位 Kubernetes 用户都应该“体验”一下原地升级,它给咱们带来了不一样于 Kubernetes 传统发布模式的变革。

流式+分批发布

前一章咱们提到了,目前 Deployment 支持 maxUnavailable/maxSurge 的流式升级,而 StatefulSet 支持 partition 的分批升级。但问题在于,Deployment 没法灰度分批,而 StatefulSet 则只能一个一个 Pod 串行发布,没办法并行的流式升级。

首先要说的是,咱们将 maxUnavailable 引入了 Advanced StatefulSet。原生 StatefulSet 的 one by one 发布,你们其实能够理解为一个强制 maxUnavailable=1 的过程,而 Advanced StatefulSet 中若是咱们配置了更大的 maxUnavailable,那么就支持并行发布更多的 Pod 了。

而后咱们再来看一下 CloneSet,它支持原生 Deployment 和 StatefulSet 的所有发布策略,包括 maxUnavailable、maxSurge、partition。那么 CloneSet 是如何把它们结合在一块儿的呢?咱们来看一个例子:

apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
# ...
spec:
  replicas: 5          # Pod 总数为 5
  updateStrategy:
    type: InPlaceIfPossible
    maxSurge: 20%      # 多扩出来 5 * 20% = 1 个 Pod (rounding up)
    maxUnavailable: 0  # 保证发布过程 5 - 0 = 5 个 Pod 可用
    partition: 3       # 保留 3 个旧版本 Pod (只发布 5 - 3 = 2 个 Pod)

针对这个副本数为 5 的 CloneSet,若是咱们修改了 template 中的 image,同时配置:maxSurge=20%  maxUnavailable=0  partition=3。当开始发布后:

  1. 先扩出来 1 个新版本的 Pod,5 个存量 Pod 保持不动;
  2. 新 Pod ready 后,逐步把旧版本 Pod 作原地升级;
  3. 直到剩余 3 个旧版本 Pod 时,由于知足了 partition 终态,会把新版本 Pod 再删除 1 个;
  4. 此时 Pod 总数仍然为 5,其中 3 个旧版本、1 个新版本。

若是咱们接下来把 partition 调整为 0,则 CloneSet 仍是会先扩出 1 个额外的新版 Pod,随后逐渐将全部 Pod 升级到新版,最终再次删除一个 Pod,达到 5 个副本全量升级的终态。

发布顺序可配置

对于原生的 Deployment 和 StatefulSet,用户是没法配置发布顺序的。Deployment 下的 Pod 发布顺序彻底依赖于它修改 ReplicaSet 后的扩缩顺序,而 StatefulSet 则严格按照 order 的反序来作一一升级。

但在 CloneSet 和 Advanced StatefulSet 中,咱们增长了发布顺序的可配置能力,使用户能够定制本身的发布顺序。目前能够经过如下两种发布优先级和一种发布打散策略来定义顺序:

  • 优先级(1):按给定 label key,在发布时根据 Pod labels 中这个 key 对应的 value 值做为权重:
apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
spec:
  # ...
  updateStrategy:
    priorityStrategy:
      orderPriority:
        - orderedKey: some-label-key
  • 优先级(2):按 selector 匹配计算权重,发布时根据 Pod 对多个 weight selector 的匹配状况计算权重总和:
apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
spec:
  # ...
  updateStrategy:
    priorityStrategy:
      weightPriority:
      - weight: 50
        matchSelector:
          matchLabels:
            test-key: foo
      - weight: 30
        matchSelector:
          matchLabels:
            test-key: bar
  • 打散:将匹配 key-value 的 Pod 打散到不一样批次中发布:
apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
spec:
  # ...
  updateStrategy:
    scatterStrategy:
    - key: some-label-key
      value: foo

可能有同窗会问为何要配置发布顺序呢?好比 zookeeper 这类应用在发布时,须要先把全部非主节点升级,最后再升级主节点,这样才能保证在整个发布过程当中只会发生一次切主。这时用户就能够经过流程打标、或者写一个 operator 自动为 zookeeper 的 Pod 打上节点职责的标签,然后配置非主节点的发布权重较大,使得发布时可以尽可能减小切主的次数。

sidecar 容器管理

轻量化容器也是阿里巴巴在云原生阶段的一次重大改革,过去阿里的容器绝大多数都是以“富容器”的方式运行的,所谓“富容器”即在一个容器中既运行业务、也跑着各类各样的插件和守护进程。而在云原生时代,咱们在逐渐把原先“富容器”中的旁路插件拆分到独立的 sidecar 容器中,使主容器逐渐回归业务自身。

这里对于拆分的好处就不赘述了,咱们来看下另外一个问题,就是拆分以后这些 sidecar 容器如何作管理呢?最直观的方式是在每一个应用的 workload 中显示去定义 Pod 中须要的 sidecar,但这样带来的问题不少:

  1. 当应用和 workload 数量众多时,咱们很难统一的 sidecar 增减管理;
  2. 应用开发者不知道(甚至也不关心)本身的应用须要配置哪些 sidecar 容器;
  3. 当 sidecar 镜像须要升级时,要把全部应用的 workload 所有升级一遍,很不现实。

所以,咱们设计了 SidecarSet,将 sidecar 容器的定义与应用 workload 解耦。应用开发者们再也不须要再关心本身的 workload 中须要写哪些 sidecar 容器,而经过原地升级, sidecar 维护者们也能够自主地管理和升级 sidecar 容器。

4.png

开放能力应用

到了这里,你们是否是对阿里巴巴的应用部署模式有了一个基本的了解呢?其实上述的能力都已经开源到了社区,咱们的项目就叫作OpenKruise,目前它已经提供了 5 种扩展 workload:

  • CloneSet:提供了更加高效、肯定可控的应用管理和部署能力,支持优雅原地升级、指定删除、发布顺序可配置、并行/灰度发布等丰富的策略,能够知足更多样化的应用场景;
  • Advanced StatefulSet:基于原生StatefulSet之上的加强版本,默认行为与原生彻底一致,在此以外提供了原地升级、并行发布(最大不可用)、发布暂停等功能;
  • SidecarSet:对 sidecar 容器作统一管理,在知足 selector 条件的 Pod 中注入指定的 sidecar 容器;
  • UnitedDeployment:经过多个 subset workload 将应用部署到多个可用区;
  • BroadcastJob:配置一个 job,在集群中全部知足条件的 Node 上都跑一个 Pod 任务。

此外,咱们还有更多的扩展能力还在开源的路上!近期,咱们会将内部的 Advanced DaemonSet 开放到 OpenKruise 中,它在原生 DaemonSet 的 maxUnavailable 之上,额外提供了如分批、selector 等发布策略,分批的功能使 DaemonSet 在发布的时候可以只升级其中部分 Pod,而 selector 更是容许发布的时候指定先在符合某些标签的 node 上升级,这为咱们在大规模集群中升级 DaemonSet 带来了灰度能力和稳定性的保障。

然后续,咱们还计划将阿里巴巴内部扩展的 HPA、调度插件等通用化能力开放出来,让每一位 Kubernetes 开发者和阿里云上的用户都能很便捷地使用上阿里内部开发应用的云原生加强能力。

最后,咱们也欢迎每一位云原生爱好者来共同参与 OpenKruise 的建设。与其余一些开源项目不一样,OpenKruise 并非阿里内部代码的复刻;偏偏相反,OpenKruise Github 仓库是阿里内部代码库的 upstream。所以,每一行你贡献的代码,都将运行在阿里内部的全部 Kubernetes 集群中、都将共同支撑了阿里巴巴全球顶尖规模的应用场景!

Q & A

Q1:目前阿里最大规模的业务 pod 数量有多少,发布一次须要多少时间?
A1:这个只能透露数量目前最大规模的单个应用下数量是以万为单位的,一次发布时间要看具体分批灰度的时长了。若是分批较多、观察时间较长的话,多是会持续一两周的。

Q2:pod 的资源 request 和 limit 是怎么配置的?request 和 limit 是什么比例来配置?过多的 request 形成浪费,过少可能会致使热点 node 负载超高。
A2:这个主要仍是根据应用的需求来定的,目前大部分在线应用都是 1:1 的关系,部分离线和job 类型的会配置 request>limit。

Q3:kruise 升级问题,升级 kurise apiversion 版本的状况下,原有的版本的部署如何升级?
A3:目前 kruise 中资源的 apiVersion 还都是统一的。咱们计划在今年下半年将部分较为成熟的 workload 进行版本升级,用户在本身的 K8s 集群内升级后,存量的旧版本资源会自动经过 conversion 升级到新版本。

Q4:OpenKruise 有提供 go-client 吗?
A4:目前提供两个方式:1. 引入 github.com/openkruise/kruise/pkg/client 包,下面有生成好的 clientset / informer / lister 等工具;2. 使用 controller-runtime 的用户(包括 kubebuilder、operator-sdk),直接引入 github.com/openkruise/kruise-api 轻量化依赖,而后加到 scheme 里就能直接用了。

Q5:阿里 K8s 版本升级是如何作的?
A5:阿里集团内部使用 Kube-On-Kube 的架构进行大规模的 Kubernetes 集群管理,用一个元 K8s 集群管理成百上千个业务 K8s 集群。其中元集群版本较为稳定,业务集群会进行频繁升级,业务集群的升级流程事实上就是对元集群中的 workloads(原生 workloads 以及 kruise workloads) 进行版本或配置升级,与正常状况咱们对业务 workloads 的升级流程类似。

Q6:这个灰度以后,流量是怎么切的?
A6:在原地升级前,kruise 会先经过 readinessGate 将 Pod 置为 not-ready,此时 endpoint 等控制器会感知到并把 Pod 从端点摘掉。而后 kruise 更新 pod image 触发容器重建,完成后再把 Pod 改成 ready。

Q7:daemonset 的分批是经过相似 deployment 的暂停功能实现的么?统计已经发布数量而后暂停,而后继续,而后再暂停。
A7:整体过程上相似,升级过程当中对新旧版本进行统计并判断是否已达到指定终态。但相比 deployment,daemonset 须要处理比较复杂的边界状况(例如初次发布时集群中并无指定的 Pod),具体细节能够持续关注咱们即将开源的代码。

Q8:多集群发布页面上怎么开始发布的?
A8:直播中演示的是一个 demo 的发布系统结合 Kruise Workloads 的例子,从交互上是经过用户选择对应的集群,点击开始执行进行发布;从实现上实际是对新版本的 YAML 与集群中的 YAML 计算 diff 后 Patch 进集群,再操做 DaemonSet 的控制字段(partition / paused 等),控制灰度进程。

相关文章
相关标签/搜索