阿里云原生应用安全防护实践与 OpenKruise 的新领域 (2)

  从上文可以看出来,云原生这种理念架构为我们带来的好处是面向终态,也就是说我们定义终态,从而整个 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/v1beta1kind: CustomResourceDefinitionmetadata: labels: policy.kruise.io/disable-cascading-deletion: true---apiVersion: v1kind: Namespacemetadata: labels: policy.kruise.io/disable-cascading-deletion: true---apiVersion: apps/v1kind: Deploymentmetadata: labels: policy.kruise.io/disable-cascading-deletion: true---apiVersion: apps.kruise.io/v1alpha1kind: CloneSetmetadata: labels: policy.kruise.io/disable-cascading-deletion: truelabels 定义是关闭级联删除,用户的任何 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 中防级联删除标识去掉。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zgzwsw.html