※ 本記事は、Shravan Sriram, Kalaiyarasan Pによる”Achieving high availability in an OKE cluster“を翻訳したものです。

2023年2月15日


Oracle Container Engine for Kubernetes(OKE)を使用する場合、障害が発生した場合でもシステムの稼働時間を確保するには高可用性が不可欠です。Kubernetesクラスタでは、ワーカー・ノードは、マルチ可用性ドメインのOracle Cloud Infrastructure(OCI)リージョンにある複数の可用性ドメイン、または単一の可用性ドメインと複数のフォルト・ドメインを持つOCIリージョン内の複数のフォルト・ドメインにわたって実行できます。高負荷を処理し、高可用性を実現するには、デプロイメントのレプリカを異なる可用性ドメインに分散することが重要です。

このブログの主な目的は、高可用性を実現するために、OKEクラスタ内のノード間でデプロイメントのポッドを分散するために使用できる様々なKubernetesメカニズムを説明することです。ノード・ラベル、アンチアフィニティ、TopologySpreadConstraintsを使用したポッド配布など、ブログで説明する概念は、一般的に多くのKubernetesシナリオに適用されます。このブログは次のような状況で役立ちます。:

  • マルチリージョン・デプロイメント: 複数のリージョンにまたがるデプロイメントがある場合は、高可用性を実現するために、各リージョン内の異なる可用性ドメインにレプリカを分散することが重要です。

  • ステートフル・アプリケーション: Kubernetesでステートフル・アプリケーションを実行する場合は、単一障害点を回避するために、レプリカが様々なアベイラビリティ・ドメインに分散されていることを確認します。

  • 継続的な統合およびデプロイメント(CI/CD)パイプライン: Kubernetesクラスタにアプリケーションの新しいバージョンをデプロイする場合は、アプリケーションの新しいバージョンが様々な可用性ドメインに分散されていることを確認して、高可用性を保証し、障害のリスクを軽減します。

主な用語

  • 可用性ドメイン: 可用性ドメインは、リージョン内のデータ・センターの論理グループです。一般的なクラウド・プロバイダのインフラでは、可用性ドメインは、冗長電力、冷却およびネットワーキング・リソースを備えた、物理的に離れた場所です。リージョン内の地理的に離れたロケーションです。

    複数の可用性ドメインを持つクラスタを作成すると、ノードは可用性ドメイン全体に分散されます。そのため、1つの可用性ドメインが停止しても、残りの可用性ドメインでノードは引き続き使用できます。このようにして、クラスタはまだ実行中であり、サービスを提供しています。

  • ノード・ラベル: OKEでは、ワーカー・ノードは、クラスタ内でポッドを実行する仮想または物理マシンにできます。ラベルは、ノードなどの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ラベルを使用できます。

可用性ドメイン間でポッドを分散するためのメカニズム

アフィニティとアンチアフィニティ

アフィニティー機能には2つのタイプがあります。ノード・アフィニティはnodeSelectorフィールドのように機能しますが、表現性が高く、ソフト・ルールを指定できます。nodeSelectorと同様に、この単純なメソッドは、一連のラベルを使用してポッドを特定のノードに制約します。

ポッド間アフィニティおよびアンチアフィニティにより、ノード・ラベルではなく、そのノードですでに実行されているポッドのラベルに基づいてポッドをスケジュールできるノードを制限できます。これらのルールは、「XがルールYを満たす1つ以上のポッドをすでに実行している場合、このポッドはXで実行する必要があります(アンチアフィニティの場合は実行しないでください)」という形式をとります。ここで、Xはクラウド・プロバイダの可用性ドメインで、YはKubernetesが満たそうとするルールです。

ユース・ケースでは、後者の機能に重点を置いています。ポッド・アンチアフィニティ・ルールは、次の方法で設定できます:

  • 必須のハード・ルール: ルールが満たされないかぎり、スケジューラはポッドをスケジュールできません。このルールは、requiredDuringSchedulingIgnoredDuringExecutionキーワードで識別されます。

  • ソフト・ルール(提案など): スケジューラはルールを満たすノードを検索しようとします。一致するノードが見つからない場合、ポッドは使用可能な任意のノードでスケジュールされます。このルールは、preferredDuringSchedulingIgnoredDuringExecutionキーワードで識別されます。

ハード・アフィニティ・ルール

次のコード・ブロックに従ってハード・アフィニティ・ルールを定義して、異なる可用性ドメイン内のノード間でポッドを分散できます:

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に一致するポッドがカウントされ、グループとして認識されます。ラベル・セレクタを指定するか、ポッドを照合できません。

この構成でポッドの4つのレプリカをスケジュールしようとすると、3つのレプリカが別の可用性ドメインに属するノードでスケジュールされ、4番目のレプリカは保留状態のままになります。requiredDuringSchedulingIgnoredDuringExecutionで規定されているハード・ルールは、制約が満たされないかぎりレプリカをスケジュールせず、3つの可用性ドメインのみがオープンされ、各可用性ドメインにはすでにこのデプロイメントからのポッドがスケジュールされています。

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

このアプローチは、3つの可用性ドメインに分散するレプリカを最大3つ持つことができるデプロイメントを操作する場合に最適です。

ソフト・アフィニティ・ルール

可用性ドメイン間で3つ以上のポッドをスケジュールするには、次のソフト・ルールを使用します:

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

重みには、preferredDuringSchedulingIgnoredDuringExecutionアフィニティ・タイプのインスタンスごとに1から100までの値を指定できます。スケジューラがポッドの他のすべてのスケジューリング要件を満たすノードを検出すると、スケジューラはノードが満たすすべての優先ルールを繰り返し処理し、その式の重みの値を合計に追加します。

この構成では、3つ以上のポッドをスケジュールできます。可用性ドメイン全体にポッドが分散しています。制約を満たせない場合、ポッドは使用可能な任意のノードでスケジュールされるため、ノード間でポッドが偏っている可能性があります。

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

TopologySpreadConstraints

クラスタが複数のアベイラビリティ・ドメインまたはリージョンにまたがる場合、ノード・ラベルをポッド・トポロジ分散制約と組み合せて使用し、フォルト・ドメイン、リージョン、アベイラビリティ・ドメイン、さらには特定のノード間でクラスタ全体にポッドを分散する方法を制御できます。これらのヒントを使用すると、スケジューラでポッドを配置して可用性を高め、相関する障害がワークロード全体に影響するリスクを減らすことができます。どのポッドをグループ化するか、どのトポロジ・ドメインに分散するか、許容可能な偏りを指定します。制約のために分散すると、同じネームスペース内のポッドのみが一致し、グループ化されます。

複数のトポロジ分散制約を指定できますが、互いに競合しないようにできます。

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

maxSkewという用語は、ポッドを均等に分散できる程度を示します。0より大きい数値でこのフィールドを指定します。そのセマンティクスは、whenUnsatisfiable.whenUnsatisfiableの値に応じて異なり、ポッドが分散制約を満たさない場合の処理方法を指定します。

DoNotScheduleの状態がデフォルトです。設定すると、maxSkewによって、ターゲット・トポロジの一致するポッドの数とグローバル最小値(適格なドメインの一致するポッドの最小数、または適格なドメインの数がMinDomains未満の場合はゼロ)との許容される最大差異が定義されます。たとえば、2つ、2つおよび1つの一致するポッドを持つ3つの可用性ドメインがある場合、MaxSkewは1に設定され、グローバル最小は1になります。

ScheduleAnywayは、偏りの低減に役立つトポロジに対して、スケジューラにより高い優先度を与えます。

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

まとめ

システムの稼働時間を確保し、高負荷を処理するには、OKEクラスタで高可用性を実現することが重要です。可用性ドメイン、ノード・ラベル、アンチアフィニティおよびTopologySpreadConstraintsの概念を理解することで、OKEクラスタ内の異なる可用性ドメインまたはフォルト・ドメインにデプロイメントのポッドを分散できます。この機能は、マルチリージョン・デプロイメント、ステートフル・アプリケーションおよびCI/CDパイプラインに特に役立ちます。この知識により、単一障害点のリスクを最小限に抑え、OKEクラスタの全体的な信頼性を向上させることができます。