乐趣区

关于运维:阿里巴巴云原生应用安全防护实践与-OpenKruise-的新领域

作者 | 王思宇 (酒祝)
起源 | 阿里巴巴云原生公众号

得益于 Kubernetes 面向终态的理念,云原生架构人造具备高度自动化的能力。然而,面向终态的自动化是一把“双刃剑”,它既为利用带来了申明式的部署能力,同时也潜在地会将一些误操作行为被终态化放大。
因而,充沛理解云原生环境下那些潜在的影响利用平安的问题,提前把握多方位的平安防护、拦挡、限流、熔断等技术手段来保障云原生利用的运行时稳定性至关重要。

本文整顿自作者阿里云容器服务技术专家,OpenKruise 作者 & 初创人员之一,Kubernetes、OAM 社区贡献者王思宇(酒祝)于 1 月 19 日在阿里云开发者社区“周二开源日”的直播分享,介绍了云原生环境下利用平安与可用性的“处处危机”,分享阿里巴巴保障云原生利用运行时稳定性教训,并且具体解读了后续这些能力将如何通过 OpenKruise 赋能给开源。

点击回看残缺视频:https://developer.aliyun.com/live/246065

云原生环境利用平安“危机”

1. 阿里巴巴云原生利用部署构造

这里的云原生利用部署构造是在阿里巴巴原生环境最简化的形象图,如下图所示。

首先咱们来看几个 CRD。CloneSet CRD 能够了解成 deployment 的一个 workload,也就是给利用部署 Pod 的模板。有了 CloneSet CRD 之后,不同的业务以及不同的利用会建设对应的 CloneSet,在 CloneSet 上面再建设对应的 Pod,以及对 Pod 做一些部署、公布相干的治理。

除了 CloneSet 之外,还提供了 SidecarSet CRD,这个 CRD 做的事件是在业务 Pod 创立阶段注入 SidecarSetCRD 中定义的 Sidecar 容器。也就是说,在 CloneSet 中业务只须要定义 Pod 中的 app 容器,也就是业务容器。在 Pod 创立过程中,通过 SidecarSet 在其中定义业务中要注入哪些 sidecar 容器。

2. OpenKruise:阿里巴巴利用部署基座

开源的 OpenKruise 是阿里巴巴利用部署的基座。OpenKruise 提供了多种的 workload。其中包含:CloneSet、Advanced StatefulSet、SidecarSet、Advanced DaemonSet。

  • CloneSet:是面向无状态利用部署的工具,也是阿里巴巴中应用规模最大的局部,绝大部分泛电商业务都是通过 CloneSet 来部署公布,包含 UC 神马、饿了么、电商业务等。
  • Advanced StatefulSet:针对一个原生 StatefulSet 兼容的加强版本,是面向有状态利用部署的工具,目前次要是用于中间件在云原生环境的部署。
  • SidecarSet:是在阿里巴巴环境中 sidecar 生命周期治理的工具。阿里巴巴的运维容器,以及阿里外部的 Mesh 容器,都是通过 SidecarSet 定义、部署以及注入到业务 Pod 中的。
  • Advanced DaemonSet:是针对原生 DaemonSet 兼容加强版本。将宿主机级别的守护过程部署到所有节点上,包含各种用于给业务容器配置网络、存储的根底组件。

介绍完根底环境之后,咱们曾经对云原生部署构造有了一个根本的理解。上面,咱们来理解在云原生部署构造之下存在哪些云原生利用平安危机。

3. 云原生利用平安危机

1)workload 级联删除

Workload 级联删除,这一点不只针对于 Kruise 的 CloneSet,对于 Deployment,对于原生的 StatefulSet 都存在相似的问题。指的是当咱们删除一个 Workload 之后,假如应用采纳默认删除,没有应用 orphan 删除这种策略的话,底下的 Pod 都会被删掉,这里存在一种误删危险。也就是说,一旦某个 Deployment 被误删,那么它底下的所有 Pod 都会级联被删掉,导致整个利用不可用。如果有多个 Workload 被删掉,就可能导致很多个业务呈现不可用的状况,这是一个对可用性造成的危险。如下图所示:

2)namespace 级联删除

那么咱们再往上看,如果 Namespace 被删掉,那么整个 Namespace 底下的所有资源,包含 Deployment、CloneSet 这些 Workload,也包含 Pod、Service 等所有资源都会被删除,这是一种很高的误删危险。

3)CRD 级联删除

如果有用 Helm 部署的同学可能会遇到过相似的状况,也就是如果你的 Helm 中蕴含了一些 CRD,这些 CRD 都被定义在 template 中,那么当 Helm uninstall 的时候,基本上这些 CRD 都会被 Helm 包级联删除掉,包含有人手动误删了某个 CRD,那么 CRD 底下对应的 CR 都会被清理。这是一个很高的危险。

如果 CRD 是 CloneSet 这种 Workload 级别的 CRD,那么一旦删除这个 CRD 之后,会导致所有 CRD 底下的 CloneSet 的 CR 对象全副被删掉,从而导致所有的业务 Pod 全副被删掉。也就是说,删除一个 Workload,只是这个 Workload 底下的 Pod 被删掉;删除一个 Namespace 可能只是 Namespace 底下的 Pod 被删掉。但如果像阿里巴巴这种场景下,如果有人把 CloneSet 或者一些很要害的 CRD 删掉的话,其实很可能导致整个集群环境所有 NameSpace 底下的 Pod 都会被级联删掉,或者说都会处于利用不可用的状态,造成云原生环境对于利用可用性的危险。如下图所示:

从上文能够看进去,云原生这种理念架构为咱们带来的益处是面向终态,也就是说咱们定义终态,从而整个 Kubernetes 集群就会向终态聚拢。而一旦呈现一些误操作导致定义了一种谬误的终态,那么 Kubernetes 也会向谬误的终态聚拢,导致呈现谬误的后果,从而影响到整个利用的可用性。因而咱们说,面向终态是一把“双刃剑”。

4)并发 Pod 更新 / 驱赶 / 删除

除了几种误删的状况,还有更多针对可用性的危险。如下图所示,假如右边 CloneSetA 部署了两个 Pod,这两个 Pod 中又被 SidecarSet 注入了对应的 sidecar 容器。在这种状况下,如果通过 CloneSet 做利用公布,假如说咱们设置的 Max Available 是 50%,也就是说,两个 Pod 是一一降级,前一个降级实现,后一个能力开始降级,默认状况下这种公布策略是没有问题的。

然而如果 Pod 有多个 Owner,比方 CloneSet 是其中一个 Owner,CloneSet 对下面的 Pod 开始做原地降级,SidecarSet 对第二个 Pod 做 sidecar 的原地降级,那么同一时刻可能这个利用的两个 Pod 都在被降级。因为在 CloneSet 定义了 Max Unavailable 是 50%,从它的视角来看,只有选取两个 Pod 中的一个开始做降级。CloneSet 自身是无奈感知到其它控制器甚至其他人为的行为去对其它 Pod 做操作,不足全局视角,每一个控制器都认为本人在降级的 Pod 是合乎降级策略,合乎最大不可用测略。但当多个控制器同时开始工作的时候,可能会导致整个利用 100% 不可用。

如上图左边的状况,CloneSetC 底下有 3 个 Pod,如果它开始做降级的时候只降级其中一个 Pod,假如是重建降级,它会把旧版本 Pod 删掉,先建新版本 Pod。在这过程中,假如另外两个 Pod 一个可能被 Kubelet,或者 kube-controller-manager 中的 node lifecycle controller 驱赶,这时候曾经有两个 Pod 不可用,曾经超过 Workload 中定义的最大不可用公布策略。在这个过程中,还可能有一些 Pod 被其余一些控制器其余有人工手动删除。种种可能性导致一个 Workload 下 Pod 的不可用数量,很可能是超过自身 workload 中定义的不可用公布策略的。

也就是说,在 Deployment 中定义了 Max Unavailable 是 25%,那么 Deployment 在公布的时候,从它本身角度来看保障 25% 的 Pod 在被公布。其余 75% 的 Pod 并不保障齐全可用,这 75% 的 Pod 可能被 Kubelet 驱赶、可能被人为手动删除、可能被 SidecarSet 内部热降级等等,种种状况可能会导致 Deployment 超过 50% 不可用,甚至更高,使整个利用受到影响。

云原生利用平安防护实际

针对以上种种危机,咱们能采取怎么样的措施,保障原生环境下利用平安的可用性、安全性。上面介绍一些实际的教训。

1. 防护实际 – 防级联删除

因为级联删除对利用可用性危害十分大,包含了删除 CRD 节点,删除 Namespace 节点,以及删除 Workload 节点。防级联删除定义了针对多种资源,包含 CRD、Namespace、包含原生 Deployment 在内的各种 Workload 等,对这些资源提供了针对的 labels 定义。

上面是针对各种重要节点防级联删除的语名:

apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  labels:
    policy.kruise.io/disable-cascading-deletion: true

---

apiVersion: v1
kind: Namespace
metadata:
  labels:
    policy.kruise.io/disable-cascading-deletion: true

---

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    policy.kruise.io/disable-cascading-deletion: true

---

apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
metadata:
  labels:
    policy.kruise.io/disable-cascading-deletion: true

labels 定义是敞开级联删除,用户的任何 CRD、Namespace、workload 里带有防级联删除标识之后,kruise 就会保障资源防级联删除校验。也就是说,当用户删除一个 CRD 时,如果这个 CRD 里带有防级联删除这个 label,那么 kruise 就会去查看 CRD 底下是否还有存量 CR,如果有存量 CR 那么 kruise 会禁止 CRD 删除。

同理,在 Namespace 删除时,也会校验 Namespace 底下是否还有存量的运行状态的 Pod,如果有,会禁止用户间接删除 Namespace。

对于 workload 逻辑绝对简略,就对于 Deployment、CloneSet、SidecarSet,当用户去删除 workload 时,如果 workload 中用户曾经定义了防级联删除的 label,那么 kruise 会查看 workload 的 replica 是否为 0,如果 replica 大于 0,那么 kruise 是禁止用户间接删除带有防级联删除标识的 workload。也就是说,当一个存量 Deployment,如果 replicas 大于 0 的状况下,如果 Deployment 中存在带有防级联删除标识,kruise 禁止用户间接删除。

如果真的须要删除 Deployment 有两种方法:

  • 第一,先把 replica 调为“0”,这时底下 Pod 开始被删除,这时删除 Deployment 是没问题的。
  • 第二,能够把 Deployment 中防级联删除标识去掉。

以上是对于防级联删除的介绍,大家应该将防级联删除了解成平安防护最根底的一个策略,因为级联删除是 Kubernetes 中十分危险的一个面向终态的能力。

2. 防护实际 – Pod 删除流控 & 熔断

针对 Pod 删除流控 & 熔断的策略,指的是用户调用、或用控制器用 K8s 去做 Pod 驱赶时,一旦呈现误操作或者呈现逻辑异样,很可能导致在整个 K8s 集群范畴内呈现 Pod 大规模删除的状况。针对这种状况做了 Pod 删除留空策略,或者说是一个 CRD。这个 CRD 用户能够定义在一个集群中,不同的工夫窗口内,最多有多少 Pod 容许被删除。

apiVersion: policy.kruise.io/v1alpha1
kind: PodDeletionFlowControl
metadata:
  # ...
spec:
  limitRules:
  - interval: 10m
    limit: 100
  - interval: 1h
    limit: 500
  - interval: 24h
    limit: 5000
  whiteListSelector:
    matchExpressions:
    - key: xxx
      operator: In
      value: foo

如下面这个例子,10 分钟之内最多容许 100 个 Pod 被删除,1 小时之内最多容许 500 个 Pod 被删除,24 小时内最多容许 5000 个 Pod 被删除。当然也能够定义一些白名单,比方有些测试利用,每天频繁地巡检、测试,频繁删除会影响整个流控,能够提供一个白名单,合乎白名单的利用不计算在窗口内。

除了白名单之外,可能 90% 的惯例利用或者外围利用,是受到删除流控爱护的。一旦存在规模性误删除操作,就会被删除流控以及熔断机制爱护。包含在爱护之后或者触发阈值之后,最好提供这种报警机制、监控机制,让集群的管理者能疾速的感知到线上呈现的熔断事件。还包含帮忙管理者去判断熔断事件是一个失常的事件,还是一个异样的事件。

如果在这段时间内,须要存在很多删除申请,能够把对应策略值相应放大。如果真的是一些误删除,拦挡到之后,及时依据申请起源做溯源,及时在搜寻层面做熔断,回绝这些申请。

3. 防护实际 – 利用维度不可用数量爱护

对利用维度不可用数量爱护,对于 K8s 原生,原生的 Kubernetes 提供了 PDB(PodDisruptionBudge) 策略,然而 PDB 只能拦挡 Pod eviction 驱赶操作,也就是 Pod 驱赶操作。

apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
  name: xxx
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: xxx

下面的这个例子,假如其中有 5 个 Pod,这时定义了 minAvailable=2,就保障起码有 2 个 Pod 处于可用。一旦有 3 个 Pod 不可用,还剩下 2 个 Pod 可用,这时候如果 Pod eviction 针对存量 2 个 Pod 做驱赶,这个时候 PDB 会爱护 Pod 可用性,回绝这次驱赶操作。然而相应的如果对存量 2 个 Pod 做删除或者原地降级,或者去做其余导致 Pod 不可用的事件,PDB 是没有方法拦挡,尤其是针对 Pod 删除申请,比 Pod 驱赶更为常见,然而 PDB 是没方法拦挡删除等申请。

对于这些问题,阿里巴巴做了 PodUnavailableBudget 拦挡操作,也就是 PUB。这里的 Unavailable 能做的操作就更多了,基本上所有可能导致 Pod 不可用的操作,都在 PodUnavailableBudget 爱护范畴内,包含了驱赶申请、Pod 删除申请,利用原地降级、Sidecar 原地降级、容器重启等,所有导致利用不可用的操作都会被 PUB 拦挡。

如上面这个例子:

apiVersion: policy.kruise.io/v1alpha1
kind: PodUnavailableBudget
spec:
  #selector:
  #  app: xxx
  targetRef:
    apiVersion: apps.kruise.io
    kind: CloneSet
    name: app-xxx
  maxUnavailable: 25%
  # minAvailable: 15
status:
  deletedPods:
    pod-uid-xxx: "116894821"
  unavailablePods:
    pod-name-xxx: "116893007"
  unavailableAllowed: 2
  currentAvailable: 17
  desiredAvailable: 15
  totalReplicas: 20

定义了一个 PUB,这个 PUB 能够像原生 PDB 一样写一个 selector 范畴,也能够通过 targetRef 间接关联到某一个 Workload,爱护范畴就是在 Workload 底下的所有 Pod,同样也能够定义最大不可用数量,以及最小可用数量。

假如对于 CloneSet 底下总共 20 个 Pod,当定义了 maxUnavailable:25% 时,肯定要保障至多有 15 个 Pod 处于可用状态。也就是说,PUB 会保障这 20 个 Pod 中最多有 5 个处于不可用状态。回到咱们之前在“危机”局部讲到的一个例子,如果这 20 个 Pod 同时在被 Cloneset 公布,以及被 Kubelet 驱赶,或是人工手动删除,一旦 Pod 不可用数量超过 5 个,不论是 Kubelet 对残余 15 个 Pod 做驱赶,还是人为手动删除残余的某些 Pod,这些操作都会被 PUB 所拦挡,这种策略能齐全保障利用在部署过程中的可用性。PUB 能够爱护的范畴比 PDB 大很多,包含在理论应用过程中预期之外的一些删除申请、降级申请,从而保障整个利用在运行时的稳定性和可用性。

4. 防护实际 – PUB/PDB 主动生成

对于真正的 Depoyment 利用开发者、运维人员来说,一般而言,只须要定义本身 workload 中 template,业务方只关怀 Depoyment templatek 中业务的版本、环境变量、端口、提供的服务,但咱们很难去强制每一个业务方在定义利用时,另外写一个 PUB 或者 PDB 爱护策略的 CR。那么,咱们怎么对每一个利用提供主动爱护呢?

在阿里巴巴外部,咱们针对每个 Workload 提供主动生成 PUB/PDB 的能力。比如说,如果用户此时新创建了一个 Deployment,会通过控制器主动为该 Deployment 生成一个匹配的 PUB。这个主动生成的性能即能反对原生 Deployment/StatefulSet,也反对 Kruise 的 CloneSet / Advanced StatefulSet / UnitedDeployment。第二,默认依据 strategy 中 maxUnavailable 策略。第三,容许 annotation 中独自定义爱护策略。如上面的语句所示:

apiVersion: apps
kind: Deployment
metadata:
  name: deploy-foo
  annotations:
    policy.kruise.io/generate-pub: "true"
    policy.kruise.io/generate-pub-maxUnavailable: "20%"
    # policy.kruise.io/generate-pub-minAvailable: "80%"
spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 25%
      maxSurge: 25%
  # ...

---
# auto generate:
apiVersion: policy.kruise.io/v1alpha1
kind: PodUnavailableBudget
spec:
  targetRef:
    apiVersion: apps
    kind: Deployment
    name: deploy-foo
  maxUnavailable: 20%

主动生成的 PUB/PDB 外部填写的 maxUnavailable,既能够让用户在 kruise 中指定定义。比方用户能够间接把 kruise.io/generate-pub:”true”,也能够 kruise.io/generate-pub-maxUnavailable:”20%”,能够让用户指定利用最多容许有多少个不可用。这是用户指定的策略。

如果用户没有指定策略,会依据在公布策略中存在的 maxUnavailable 生成 PUB。就是指在公布的阶段,有多少个不可用数量,做为利用运行时最大不可能数量。这是容许独自定义策略。

OpenKruise 的新畛域

1. OpenKruise 介绍

最初,和大家介绍上述凋谢的能力在 OpenKruise 新畛域如何去凋谢,以及怎么拓展对 OpenKruise 的认知。OpenKruise 是阿里云开源的 Kubernetes 扩大利用负载我的项目,实质上是围绕 Kubernetes 云原生利用去做一系列自动化能力的引擎,同时也是阿里巴巴经济体上云全面应用的部署基座。

OpenKruise 的定位,做的不是一个残缺的平台,更相似于是 Kubernetes 中一个拓展的产品。这个拓展的产品作为一个 add on 的组件,提供了一系列针对在 Kubernetes 中部署利用,以及后续爱护防护利用可用、围绕云原生利用的一些自动化的能力,这些拓展能力或者加强能力,是原生 Kubernetes 所不具备,但也是迫切需要它所领有这些能力,是阿里巴巴外部在云原生逐步演进过程中去积淀的一些通用能力。

目前,Kruise 提供了以下 workload 控制器:

  • CloneSet:提供了更加高效、确定可控的利用治理和部署能力,反对优雅原地降级、指定删除、公布程序可配置、并行 / 灰度公布等丰盛的策略,能够满足更多样化的利用场景。
  • Advanced StatefulSet:基于原生 StatefulSet 之上的加强版本,默认行为与原生完全一致,在此之外提供了原地降级、并行公布(最大不可用)、公布暂停等性能。
  • SidecarSet:对 sidecar 容器做对立治理,在满足 selector 条件的 Pod 中注入指定的 sidecar 容器。
  • UnitedDeployment:通过多个 subset workload 将利用部署到多个可用区。
  • BroadcastJob:配置一个 job 在集群中所有满足条件的 Node 上都跑一个 Pod 工作。
  • Advanced DaemonSet:基于原生 DaemonSet 之上的加强版本,默认行为与原生统一,在此之外提供了灰度分批、按 Nodelabel 抉择、暂停、热降级等公布策略。
  • AdvancedCronJob:一个扩大的 CronJob 控制器,目前 template 模板反对配置应用 Job 或 BroadcastJob。

2. 原生 workload 能力缺点

依据 Deployment 去 CloneSet、AdcancedStatefulSet 是因为原生 workload 能力缺点有很多。大家能够看到,基本上从 Kubernetes 1.10 版本之后,其实其余的性能,包含 pod 外面,它的字段还是在不断丰富,包含更多的 pod 的能力反对、更多的策略等,然而对于 workload 层面,就是 deployment 和 StatefulSet 层面,曾经不偏向于做任何改变。社区在这背地的思考是因为在不同公司、不同业务场景下,利用部署公布层面需要很多。

Kubernetes 原生提供的 Deployment,是面向一些最通用最根底的一些环境,没方法用它去满足所有的业务场景,但实际上社区是十分激励有更高需要,更大更简单场景规模需要的用户,自行通过 CRD 去拓展编写,利用更弱小的 workload,来满足不同的业务的场景需要。

3. OpenKruise 与原生能力比照

橙色:开源中  /  绿色:已开源

那么,对于这场景而言,Kruise 曾经做了比拟齐备的一个无状态以及有状态利用的部署,通过上图表格能看到 Kruise 提供的 workload 和原生 deployment、StatefulSet、DaemonSet 的比照。

4. OpenKruise 2021 布局

如上图所示,OpenKruise 是一个云原生利用自动化引擎,目前提供的 workload 能力在利用部署,但不会仅局限于利用部署这一个畛域的。

1)危险防控

在 2021 年上半年的布局中,咱们会针对下面讲到的云原生利用的危险和防控的策略,会通过 OpenKruise 输入给社区。包含 CRD 删除防护、级联删除防护、全局 Pod 删除流控、Pod 删除 / 驱赶 / 原地降级防护、主动为 workload 生成 PDB/PUB 等。

2)Kruise-daemo

除此之外之前 OpenKruise 只是作为一个核心的控制器部署,下个版本中会提供一个 Kruise-daemon 通过 daemon set 部署到每个节点上,能够帮用户去做一些镜像预热,公布减速,容器重启,单机调度优化的一些策略。

3)ControllerMesh

ControllerMesh 是 OpenKruise 提供进去帮忙用户治理用户集群中其余运行时的一些控制器运行时的能力,通过流量管制等形式解决传统控制器单住模式带来的种种问题。

 最初,在 OpenKruise 我的项目社区建设方面,曾经在 2020 年 11 月 11 号经 CNCF 技术监督委员会全体成员投票,一致同意正式进入 CNCF Sanbox,在整个过程中也失去了 CNCF 踊跃的回应,示意 OpenKruise 我的项目与 CNCF 提倡的理念很符合,激励有更多像 OpenKruise 这样能做一些通用化的,面向更简单的场景,更大规模的一些这种自主的 Workload 能力的我的项目呈现。

当初曾经有很多公司在应用 OpenKruise 的这些能力,比方:

  • 基于原地降级、灰度公布等需要,携程在生产环境应用 CloneSet、AdvancedStatefulSet 来别离治理无状态、有状态利用的服务,单集群 Kruise workload 数量达到万级别。
  • OPPO 公司不仅大规模应用了 OpenKruise,还在上游配合其定制化的 Kubernetes 进一步增强了原地降级的能力,广泛应用在多个业务的后端运行服务中,通过原地更新笼罩了 87% 左右的降级部署需要。
  • 此外,国内的用户还有苏宁、斗鱼 TV、有赞、比心、Boss 直聘、申通、小红书、VIPKID、掌门教育、杭银生产、万翼 科技、多点 Dmall、佐疆科技、享住智慧、艾佳生存、永辉科技核心、跟谁学,国外的用户有 Lyft、Bringg、Arkane Systems 等。
  • Maintainer 5 位成员来自阿里巴巴、腾讯、Lyft
  • 51 位贡献者

    • 国内:阿里云、蚂蚁团体、携程、腾讯、拼多多 …
    • 国外:微软、Lyft、Spectro Cloud、Dsicord…
  • 2000+ GitHub Stars
  • 300+ Forks

如果大家对 OpenKruise 我的项目感兴趣,有任何心愿交换的话题,欢送大家拜访 OpenKruise 官网、GitHub,以及退出钉钉交换群:

“Kubernetes 与云原生利用开源实际大讲堂”

4 场云原生与 Kubernetes 技术前沿话题直播、70 节经典课程、3 本云原生电子书,来“Kubernetes 与云原生利用开源实际大讲堂”,和阿里云容器技术专家一起,将热门的容器开源我的项目和前沿的云原生利用落地实际一网打尽!点击中转“Kubernetes 与云原生利用开源实际大讲堂”!

退出移动版