Confluent の複数アベイラビリティゾーンのデプロイ

Confluent for Kubernetes は、Kubernetes における Confluent コンポーネントのデプロイ、管理、運用を支援します。

パブリッククラウドにおける Kubernetes 製品の多くは、Kubernetes クラスターが複数のアベイラビリティゾーン(マルチ AZ)に分散されるリージョナルな構成での実行をサポートしています。

このトピックでは、マルチ AZ デプロイにおける Confluent for Kubernetes の動作と慣例について説明します。

このトピックの例では、現在の名前空間を設定するものとし、明示的には名前空間を指定していないので注意してください。

Confluent for Kubernetes は、複数の AZ に Confluent for Kubernetes をデプロイするだけでなく、ラックが AZ である場合にラック認識機能に対応するよう構成できます。ラック認識機能を使用すれば、Kafka のパーティションレプリカを複数の AZ に配置して、AZ の障害イベントで失われるデータを最小にできます。ラック認識機能を構成する方法については、AZ のチュートリアルの、ラック認識機能の構成に関する説明 を参照してください。

マルチ AZ Kubernetes

マルチ AZ Kubernetes では、Kubernetes ワーカーノードが複数の AZ に分散されます。それぞれのノードには、その存在場所であるリージョンのラベルが付けられます。AZ ラベルを調べるには、次のコマンドを実行します。

kubectl get nodes --show-labels

前述のコマンドからの出力には、failure-domain.beta.kubernetes.io/zone という AZ ラベルが含まれます。以下に例を示します。

failure-domain.beta.kubernetes.io/zone=us-central1-f

ワーカーノードによって使用されるストレージには、どの AZ からでもアクセスできます。

Confluent ポッドのスケジューリング

Confluent コンポーネントのインスタンスポッドは、AZ 全体にラウンドロビン方式でスケジューリングされます。

たとえば、6 つの Kafka ブローカーを 3 つの AZ(各 AZ に 2 つのワーカーノード)に対してスケジューリングした場合、最終的にそれぞれの AZ の Kafka ブローカー数は 2 つとなります。

その AZ のリソースキャパシティまたはワーカーキャパシティが十分ではない場合は、キャパシティがあるゾーン内のいずれかのワーカーにポッドがスケジューリングされます。

たとえば、次のワーカーノードが分散配置されている Kubernetes クラスターがあるとします。

  • ワーカー×4(AZ 1)
  • ワーカー×1(AZ 2)
  • ワーカー×4(AZ 3)

6 つの Kafka ブローカーをスケジューリングした場合、ポッドは次のいずれかとしてスケジューリングされます。

  • ブローカーポッド×2(AZ 1)、ブローカーポッド×1(AZ 2)、ブローカーポッド×3(AZ 3)
  • ブローカーポッド×3(AZ 1)、ブローカーポッド×1(AZ 2)、ブローカーポッド×2(AZ 3)

デプロイ後は、次のようにして、ポッドのスケジューリング先ノードを調べることができます。

  1. ポッドのノード名を取得します。

    kubectl get pods -o wide
    
  2. それぞれのノードについて、その failure-domain.beta.kubernetes.io/zone ラベルに着目し、そのノードが属している AZ を調べます。

    kubectl get nodes --show-labels | grep <node_name>
    

ストレージのスケジューリング

Confluent for Kubernetes では、各コンポーネントのストレージニーズに対して永続ボリュームが使用されます。ほとんどのクラウドプロバイダーでは、永続ボリュームのストレージメカニズムが AZ に対応していますが、AZ の境界を越えて永続ボリュームにアクセスしたり永続ボリュームを移動したりすることはできません。したがって特定の AZ にスケジューリングされたポッドの永続ボリュームは、同じ AZ に存在する必要があります。

CFK では、複数の AZ に分散された Kubernetes クラスター上のストレージクラスが遅延バインドであることが必要です。ご使用のストレージクラスの volumeBindingModeWaitForFirstConsumer に設定されていることを確認してください。この場合、PersistentVolumeClaim を使用するポッドが作成されるまで、PersistentVolume のバインドとプロビジョニングが先延ばしされます。PersistentVolume は、ポッドのスケジューリング制約で指定されたトポロジーに従って選択またはプロビジョニングされます。

次のコマンドを使用してストレージクラスのバインディングモードを調べます。

kubectl describe sc <your_storage_class>

出力を見ると、次のように、VolumeBindingModeWaitForFirstConsumer に設定されているはずです。

Name:                  <your_storage_class>
...
VolumeBindingMode:     WaitForFirstConsumer
...

デプロイ後に、永続ボリュームの割り当て先の AZ を確認することができます。以下に例を示します。

kubectl describe pv pvc-008a81fd-cd28-4b3e-a26f-5fe9384476f9

上記コマンドのサンプル出力を見ると、永続ボリュームが us-central1-a ゾーンにマウントされていることがわかります。

Name:        pvc-008a81fd-cd28-4b3e-a26f-5fe9384476f9
Labels:      failure-domain.beta.kubernetes.io/region=us-central1
             failure-domain.beta.kubernetes.io/zone=us-central1-a

シナリオ: ワーカーの障害

単一の Kubernetes ワーカーノードで障害が発生すると、そのワーカーノードのポッドが消えます。

この場合、Confluent ポッドは、CFK によって、必要なリソースキャパシティを備えた、同じ AZ 内の別の Kubernetes ワーカーにスケジューリングされ、同じ永続ボリュームに接続されます。

必要なリソースキャパシティを備えた利用可能なワーカーノードが存在しない場合、ポッドはスケジューリングされず、保留状態となります。

そのゾーンのリソースキャパシティが利用可能な状態になったとき、ポッドはスケジューリングされます。

注釈

Confluent for Kubernetes では、oneReplicaPerNode の機能を使用して、同じ Kubernetes ワーカーノードに複数の Kafka ブローカーが併置されるのを回避しています。これは ZooKeeper サーバーについても同様です。そのため、Kafka と ZooKeeper を収容できるだけの Kubernetes ワーカーノードを確保する必要があります。

シナリオ: AZ の障害

AZ 全体の障害が発生すると、その AZ にある Kubernetes ワーカーノードがすべて利用できなくなります。ストレージの回復性は AZ の範囲に限定されるため、ストレージも利用できなくなります。

このケースでは、ポッドと永続ボリュームは利用できず、それらを自動的に起動することはできません。これらは保留状態となります。

この問題の解決には 2 つのパスがあります。つまり、AZ が利用可能な状態になるまで待つか、ポッドを別の AZ にスケジューリングします。

AZ が利用可能な状態になるまで待つ

AZ が利用可能な状態になるまで待つ場合、AZ が回復するまで、その AZ 内の特定のポッドは保留状態となります。AZ が復旧すると、それらのポッドも稼動状態となります。

このケースでは、万一 AZ がダウンしても動作するだけの十分なブローカーキャパシティが存在することを確認してください。1 つの AZ に障害が発生したときに利用できるブローカーの数とかみ合うように、レプリケーション係数と ISR(In-Sync Replicas: 同期レプリカ)が設定されている必要があります。

Confluent ポッドを別の AZ にスケジューリングする

このパスでは、Kafka ブローカーポッドが読み取り/書き込みリクエストの受け付けを開始できるのは、そのポッドが新しいストレージで起動し、他のブローカーからパーティションをレプリケートした後となります。

以下のコマンド例では、Kafka クラスター名として kafka を使用しています。

異なる AZ にポッドをスケジューリングするには、次の手順に従います。

  1. リソースのリコンサイルのアップデートを一時的に停止するよう CFK を設定します。

    kubectl annotate kafka kafka platform.confluent.io/block-reconcile=true
    
  2. 永続ボリュームクレーム(pvc)を削除します。

    pvc には "data0-<clustername>-0" という名前が付いています。

    たとえば、障害が発生した AZ 上のポッドが "kafka-0" で、Kafka クラスターの名前が kafka である場合、コマンドは次のようになります。

    kubectl patch pvc data0-kafka-0 \
       -p '{"metadata":{"finalizers":[]}}' \
       --type=merge \
       | kubectl delete pvc data0-kafka-0
    
  3. 障害のある AZ に関連付けられていたポッドを削除します。

    kubectl delete pod kafka-0 --grace-period=0 --force
    
  4. リソースのリコンサイルを再度有効にして、リコンサイルをトリガーします。これにより、利用可能な AZ 上でポッドがスケジューリングされます。

    kubectl annotate kafka kafka platform.confluent.io/block-reconcile-