云架构


在 OKE 集群中实现高可用性

使用Oracle Container Engine for Kubernetes (OKE) 时,高可用性对于确保系统正常运行至关重要,即使发生故障也是如此。在 Kubernetes 集群中,工作节点可以在多可用性域 Oracle Cloud Infrastructure (OCI) 区域中跨多个可用性域运行,或者在具有单个可用性域和多个故障域的 OCI 区域中跨多个故障域运行。为了服务于高负载并实现高可用性,将部署的副本分布到不同的可用性域非常重要。

本博客的主要目标是解释不同的 Kubernetes 机制,您可以使用这些机制在 OKE 集群中跨节点分发部署的 pod 以实现高可用性。博客中讨论的概念,例如使用节点标签、反亲和性、 TopologySpreadConstraints来分发 Pod,普遍适用于许多 Kubernetes 场景。此博客在以下示例情况下很有用:

  • 区域部署:如果您的部署跨越多个区域,则将副本分布在每个区域内的不同可用性域中以实现高可用性非常重要。
  • 有状态应用程序:在 Kubernetes 上运行有状态应用程序时,确保副本分布在不同的可用性域中,以避免单点故障。
  • 持续集成和部署 (CI/CD) 管道:在 Kubernetes 集群中部署新版本的应用程序时,确保新版本的应用程序分布在不同的可用性域中,以确保高可用性并降低故障风险。

关键词

  • 可用性域:可用性域是区域内数据中心的逻辑分组。在典型的云提供商的基础架构中,可用性域是一个物理上独立的位置,具有冗余电源、冷却和网络资源。它们是一个区域内在地理位置上不同的位置。

当您创建具有多个可用性域的集群时,节点分布在可用性域中。因此,如果一个可用性域出现故障,节点在其余可用性域中仍然可用。这样,您的集群仍在运行并提供服务

  • 节点标签:在 OKE 中,工作节点可以是在集群中运行 Pod 的虚拟机或物理机。标签是可以添加到 Kubernetes 对象(例如节点)的键值对,以指定对用户有意义且相关的标识属性。您可以使用节点标签来标识节点的不同特征,例如它所属的可用性域、它的机器类型或它运行的操作系统。 Kubernetes 会自动为所有节点分配一组标准标签,这些标签可以包含有关节点所属可用性域的信息。

使用节点标签识别可用性域

当您想要跨不同的可用性域分配工作负载并确保服务的高可用性时,了解可用性域和节点标签会很有帮助。在检查 OKE 集群中节点上的标签时,请参考以下代码块:

oci@oci-mac % kubectl describe node 10.0.10.127
Name:               10.0.10.127
Roles:              node
Labels:             beta.kubernetes.io/arch=amd64
                    beta.kubernetes.io/instance-type=VM.Standard.E3.Flex
                    beta.kubernetes.io/os=linux
                    displayName=oke-cxeqigstkia-ndhpxqaqgsa-srp6z4k7mva-0
                    failure-domain.beta.kubernetes.io/region=phx
                    failure-domain.beta.kubernetes.io/zone=PHX-AD-1
                    hostname=oke-cxeqigstkia-ndhpxqaqgsa-srp6z4k7mva-0
                    internal_addr=10.0.10.127
                    kubernetes.io/arch=amd64
                    kubernetes.io/hostname=10.0.10.127
                    kubernetes.io/os=linux
                    last-migration-failure=get_kubesvc_failure
                    name=dis_oke_drcc2.0_cluster
                    node-role.kubernetes.io/node=
                    node.info.ds_proxymux_client=true
                    node.info/kubeletVersion=v1.24
                    node.kubernetes.io/instance-type=VM.Standard.E3.Flex
                    oci.oraclecloud.com/fault-domain=FAULT-DOMAIN-1
                    oke.oraclecloud.com/node.info.private_subnet=false
                    oke.oraclecloud.com/node.info.private_worker=true
                    oke.oraclecloud.com/tenant_agent.version=1.47.5-ed7c19ae8e-916
                    topology.kubernetes.io/region=phx
                    topology.kubernetes.io/zone=PHX-AD-1

我们可以使用多个标签来唯一标识一个可用性域,包括以下示例:

  • topology.kubernetes.io/zone=PHX-AD-1
  • failure-domain.beta.kubernetes.io/zone=PHX-AD-1

对于我们的用例,我们可以使用 topology.kubernetes.io/zone 标签。

域分发 Pod 的机制

亲和与反亲和

亲和特征有两种类型。节点亲和力功能类似于nodeSelector字段,但更具表现力并允许我们指定软规则。与nodeSelector一样,这个简单的方法将 pod 限制到具有一组标签的特定节点。

Interpod亲和性和反亲和性允许我们根据已经在该节点上运行的 pod 标签而不是节点标签来限制我们可以在哪些节点上调度我们的 pod。这些规则采用“如果 X 已经在运行一个或多个满足规则 Y 的 Pod,则此 Pod 应该(或者,在反亲和性的情况下,不应该)在 X 中运行”的形式,其中 X 是云提供商的可用性域,Y 是 Kubernetes 试图满足的规则。

对于我们的用例,我们专注于后一种功能。我们可以通过以下方式设置 pod 反亲和规则:

  • 强制性的硬性规则:除非满足规则,否则调度程序无法调度 pod。该规则由 requiredDuringSchedulingIgnoredDuringExecution关键字。
  • 软规则,更像是一个建议:调度器试图找到一个符合规则的节点。如果找不到匹配的节点,则 Pod 会被调度到任何可用的节点上。此规则由preferredDuringSchedulingIgnoredDuringExecution关键字标识。

硬关联规则

我们可以根据以下代码块定义一个硬关联规则,以将 Pod 分布在不同可用性域的节点上:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: adtest-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 4
  template:
    metadata:
      labels:
        app: nginx
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - nginx
            topologyKey: topology.kubernetes.io/zone
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80
        resources:
          requests:
            memory: "500Mi"

在此配置中, topologyKey是要使用的节点标签的键。匹配labelSelector的 Pod在传播以满足约束时被计数并识别为一个组。指定标签选择器,否则无法匹配到任何 pod。

如果我们尝试使用此配置调度一个 pod 的四个副本,其中三个被调度到属于不同可用性域的节点上,而第四个仍处于挂起状态。除非满足约束,否则requiredDuringSchedulingIgnoredDuringExecution强制执行的硬性规则不会安排副本,并且只有三个可用性域是开放的,并且每个可用性域已经安排了来自此部署的 pod。

A graphic depicting a multi-availability domain setup with a pod in pending state.

这种方法在处理最多可以有三个副本的部署时效果最好,我们希望将这些副本分布在三个可用性域中。

软亲和规则

要跨可用性域安排三个以上的 pod,我们遵循以下软规则:

spec:
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - nginx
              topologyKey: topology.kubernetes.io/zone
            weight: 100

preferredDuringSchedulingIgnoredDuringExecution关联类型的每个实例,权重可以具有 1-100 之间的值。当调度程序找到满足 pod 的所有其他调度要求的节点时,调度程序会遍历该节点满足的每个首选规则,并将该表达式的权重值添加到总和中。

我们可以使用此配置安排三个以上的 pod。 Pod 分布在可用性域中。如果它不能满足约束,则 pod 会被调度到任何可用的节点上,这可能会导致 pod 在节点之间的分布不均。

A graphic depicting a multi-availability domain setup with a pod scheduled.

拓扑传播约束

如果我们的集群跨越多个可用性域或区域,我们可以将节点标签与pod 拓扑分布约束结合使用,以控制 pod 如何在故障域、区域、可用性域甚至特定节点之间分布在我们的集群中。这些提示使调度程序能够放置 pod 以获得更好的可用性,从而降低相关故障影响我们整个工作负载的风险。我们指定将哪些 pod 组合在一起,它们分布在哪些拓扑域中,以及可接受的偏差。由于约束,在传播时,只有同一命名空间内的 pod 才会匹配并组合在一起。

我们可以指定多个拓扑扩展约束,但要确保它们不会相互冲突。

spec:
      topologySpreadConstraints:
      - maxSkew: 1 
        topologyKey: topology.kubernetes.io/zone 
        whenUnsatisfiable: DoNotSchedule 
        labelSelector: 
          matchLabels:
            app: nginx

术语maxSkew描述了 pod 分布不均匀的程度。使用大于 0 的数字指定此字段。它的语义根据 whenUnsatisfiable 的值而不同。whenUnsatisfiable指示如果 pod 不满足传播约束时如何处理它。

DoNotSchedule的状态是默认的。设置后, maxSkew定义了目标拓扑中匹配的 pod 数量与全局最小值之间的最大允许差异(合格域中匹配 pod 的最小数量,如果合格域的数量小于MinDomains则为零)。例如,如果我们有三个可用性域,分别有两个、两个和一个匹配的 pod,则 MaxSkew设置为 1,全局最小值为 1。

ScheduleAnyway指示调度程序为有助于减少偏差的拓扑提供更高的优先级。

A graphic depicting a multi-availability domain setup with a pod scheduled.

结论

在 OKE 集群中实现高可用性对于确保系统正常运行时间和服务高负载至关重要。通过了解可用性域、节点标签、反亲和性和TopologySpreadConstraints的概念,您可以将部署的 pod 分布到 OKE 集群内的不同可用性域或故障域。此功能对于多区域部署、有状态应用程序和 CI/CD 管道特别有用。有了这些知识,您可以最大限度地降低单点故障的风险并提高 OKE 集群的整体可靠性。

ad