Confluent for Kubernetes を使用したワークロードのスケジューリング

概要

Confluent コンポーネントから最適なパフォーマンスを引き出すためにできることとして、Kubernetes ノードにおけるコンポーネントポッドのスケジューリング方法を制御することが挙げられます。たとえば、リソース使用率の高い他のアプリケーションと同じノードにはスケジューリングされないようポッドを構成することができます。また、専用ノードにスケジューリングされるようにポッドを構成したり、最適なハードウェアを備えたノードにスケジューリングされるようにポッドを構成したりすることも可能です。

ストレージやネットワークなど同じリソースをコンポーネントが奪い合って両方のポッドでパフォーマンスが低下する事態を防ぐためには、他のクリティカルなワークロードとのノードの共有を避けるようにコンポーネントポッドをスケジューリングします。

Kubernetes ノードへの Confluent コンポーネントポッドのスケジューリングに関して、Confluent for Kubernetes は次の機能をサポートします。

Taint と Toleration

Taint と Toleration は、Kubernetes 内の特定のノードにポッドがスケジューリングされないよう一体となって作用します。

Taint はノードに適用され、Toleration はポッドに適用されます。Taint に対する Toleration が宣言されていないポッドを、そのノードにスケジューリングすることはできません。

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

Taint と Toleration は、ノードにポッドがスケジューリングされないようにする働きはありますが、意図した実行先ノードにポッドがスケジューリングされることを保証する機能ではありません。

意図した適切なノードにポッドをスケジューリングするには、別の Kubernetes 機能、つまり アフィニティとアンチアフィニティ を使用してください。Confluent for Kubernetes では、次のタイプの Kubernetes アフィニティ機能がサポートされます。

  • ノードアフィニティ
  • ポッドアフィニティとポッドアンチアフィニティ

ノードアフィニティ

ノードアフィニティ機能を使用すると、ワークロード(ポッド)を特定のノードにスケジューリングすることで、たとえば、ストレージや CPU、ネットワークなど各種リソースを最適化することができます。

Confluent for Kubernetes では、ノードアフィニティルールを作成することで、Confluent ポッドのスケジューリング先となる Kubernetes ノードの候補を指定できます。たとえば、1 つまたは複数の Confluent ポッドの実行に使用する特別なハードウェアがある場合は、ノードアフィニティを使用して、該当するポッドをその特別なハードウェアノードに固定できます。

ポッドアフィニティとポッドアンチアフィニティ

ポッドアフィニティ機能を使用すると、ポッドのスケジューリング先ノードとして、他のポッドと同じノードを指定できます。

ポッドアンチアフィニティ機能を使用すると、さまざまなノード、アベイラビリティゾーン、または使用するその他の潜在的トポロジードメインで、一連のポッドが相互に重複することのないようにスケジュールを指定できます。たとえば、ポッドアンチアフィニティを使用することで、Kafka ブローカーが、リソース使用率の高い他のワークロードやクリティカルな他のワークロードとノードを共有することを確実に防ぐことができます。

アフィニティルールとアンチアフィニティルールは、名前空間レベルで適用されます。

ポッドトポロジーの分散制約

ポッドトポロジーの分散制約を使用すると、複数のノード、ゾーン、リージョン、または他のユーザー定義のトポロジードメインにわたって、ポッドの分散を制御して、可用性を高め、クラスターリソースを効率的に使用することができます。

最初に、ノードにラベルを付けて、リージョン、ゾーン、ノードなどのトポロジー情報を提供する必要があります。次に、Confluent コンポーネントの CR で分散制約を定義します。たとえば、グループ化するポッド、ポッドが分散されるトポロジードメイン、および許容される偏りを指定します。

ポッドトポロジーの制約は、同じ名前空間内のポッドにのみ適用されます。

1 ノードあたり 1 レプリカ

Kubernetes ノード 1 つにつき、実行されるレプリカが 1 つに限定されるように、CFK を構成できます。

このスケジューリング方式では、Confluent Platform コンポーネントと、同じノード上で実行される他のアプリケーションとが、システムリソースを奪い合うのを確実に防ぐことができます。

このルールは、同じクラスターから作成されたレプリカにのみ、名前空間レベルで適用されます。

1 ノードあたり 1 レプリカの設定は、Kafka と ZooKeeper では有効に、他の Confluent Platform コンポーネントでは無効にすることをお勧めします。

Confluent コンポーネントの Taint と Toleration の構成

Taint の構成

ノードに Taint を設定するには、「Taint と Toleration」の説明に従って、kubectl taint nodes コマンドを使用します。

Toleration の構成

Toleration を使用してポッドが構成されているとき、ポッドは、マッチング演算子 <operator> を使用して 3 つの構成要素(<key,value,effect>)と一致する Taint を "容認" します。

ノードの Taint を容認しているポッドは、ノードにスケジューリングすることができます。

Confluent コンポーネントの CR の tolerations プロパティを次のように構成し、リソースを作成するか、アップデートします。

spec:
  podTemplate:
    tolerations:
    - effect:                --- [1]
      key:                   --- [2]
      operator:              --- [3]
      value:                 --- [4]
      tolerationSeconds:     --- [5]
  • [1] 容認しないポッドにどのように対応するかを示します。使用できる値は、NoSchedulePreferNoScheduleNoExecute です。

    空の値を設定すると、この Toleration は、すべての Taint 作用と一致します。

  • [2] Toleration が適用される Taint キーです。

    key が空の場合は、operatorExists に設定する必要があります。この組み合わせは、すべての値とすべてのキーに一致することを意味します。

  • [3] キーと値を比較する一致演算子。使用できる operator は、ExistsEqual で、Equal がデフォルトです。

    Exists は、値のワイルドカードに相当するため、ポッドは、key のすべての Taint を許容できます。

  • [4] Toleration が一致する Taint 値。operatorExists の場合は、この値が空である必要があります。

  • [5] Toleration が Taint を許容する期間。effectNoExecute に設定されている場合にのみ適用されます。そうでない場合は、このフィールドが無視されます。

    デフォルトでは設定されていません。つまり、Taint が永続的に許容されます(排除されません)。

    ゼロおよび負の値は 0 として扱われます(すぐに排除されます)。

たとえば、ノードの Taint が次のように設定されたとします。

kubectl taint nodes node1 myKey=myValue:NoSchedule

次の CR スニペットは、上で作成した Taint と一致するため、ポッドは、このノードにスケジューリングすることができます。

spec:
  podTemplate:
    tolerations:
    - key: "myKey"
      operator: "Equal"
      value: "myValue"
      effect: "NoSchedule"

各フィールドの詳細については、「Taint と Toleration」を参照してください。

Confluent コンポーネントのノードアフィニティの構成

このセクションでは、Confluent コンポーネントポッドに使用するノードアフィニティのスケジューリングルールを構成する方法について説明します。

Confluent コンポーネントポッドをどのノードで実行できるかは、ノードアフィニティを使用して、ノードのラベル(matchExpressions)またはノードのフィールド(matchFields)に基づいて指定します。それぞれの一致条件は <key, operator, value> という 3 つの要素から成ります。

サポートされるノードアフィニティルールは次の 2 種類です。

  • requiredDuringSchedulingIgnoredDuringExecution

    ポッドがノードにスケジューリングされるためには、そのポッドがこれらのルールを満たしている必要があります。

  • preferredDuringSchedulingIgnoredDuringExecution

    指定したアフィニティ式を満たしたポッドは、スケジューラーによって優先的にノードにスケジューリングされますが、1 つまたは複数の式と一致しないノードが選択される場合もあります。

    重みの合計が最大となるノードが最も優先されます。

    優先スケジューリングの term が空である場合、暗黙的な重みが 0 であるすべてのオブジェクトと一致します。

    優先スケジューリングの term が null である場合は、いずれのオブジェクトとも一致しません。

requiredDuringSchedulingIgnoredDuringExecution を使用したノードアフィニティの構成

ポッドは、いずれかの nodeSelectorTerms が一致した場合、ノードにスケジューリングできます。

nodeSelectorTerms 項目は、すべての matchExpressions が一致した場合に一致と見なされます。

ノードラベルと一致するノードアフィニティルールを作成するには、Confluent コンポーネントの CR の nodeAffinity プロパティを次のように構成して、リソースを作成するか、アップデートします。matchExpressions または matchFields を設定してください。

spec:
  podTemplate:
    affinity:
      nodeAffinity:
        requiredDuringSchedulingIgnoredDuringExecution:
          nodeSelectorTerms:     --- [1]
            - matchExpressions:  --- [2]
                - key:           --- [3]
                  operator:      --- [4]
                  values:        --- [5]
              matchFields:       --- [6]
                - key:           --- [7]
                  operator:      --- [8]
                  values:        --- [9]
  • [1](必須)ノードセレクター条件のリスト。

  • [2] ノードのラベル別の、ノードセレクター要件のリスト。

    ノードセレクター要件は、valueskey、および keyvalues を関連付ける operator を含むセレクターです。

  • [3](必須)セレクターが適用されるラベルキー。

  • [4](必須)``key`` が values とどのような関係であるかを表します。有効な operator は、InNotInExistsDoesNotExistGt、および Lt です。

  • [5] 文字列値の配列。

    operatorIn または NotIn である場合は、values 配列を空にすることはできません。

    operatorExists または DoesNotExist である場合は、values 配列を空にする必要があります。

    operatorGt または Lt の場合は、values 配列の要素を 1 つにする必要があります。この要素は整数と解釈されます。

  • [6] ノードのフィールド別の、ノードセレクター要件のリスト。

    ノードセレクター要件は、valueskey、および keyvalues を関連付ける operator を含むセレクターです。

  • [7](必須)セレクターが適用されるフィールドキー。

  • [8](必須)``values`` が key とどのような関係であるかを表します。有効な operator は、InNotInExistsDoesNotExistGt、および Lt です。

  • [9] 文字列値の配列。

    operatorIn または NotIn である場合は、values 配列を空にすることはできません。

    operatorExists または DoesNotExist である場合は、values 配列を空にする必要があります。

    operatorGt または Lt の場合は、values 配列の要素を 1 つにする必要があります。この要素は整数と解釈されます。

サンプル CR スニペット

spec:
  podTemplate:
    affinity:
      nodeAffinity:
        requiredDuringSchedulingIgnoredDuringExecution:
          nodeSelectorTerms:
          - matchExpressions:
            - key: "node-role.kubernetes.io/kafka-connect"
              operator: In
              values: ["true"]

preferredDuringSchedulingIgnoredDuringExecution を使用したノードアフィニティの構成

ノードセレクター式またはノードセレクターフィールドと一致するノードアフィニティルールを作成するには、Confluent コンポーネントの CR を次のように構成して、リソースを作成するか、アップデートします。matchExpressions または matchFields を設定してください。

spec:
  podTemplate:
    affinity:
      nodeAffinity:
        preferredDuringSchedulingIgnoredDuringExecution:
        - preference:            --- [1]
            matchExpressions:    --- [2]
              key:               --- [3]
              operator:          --- [4]
              values:            --- [5]
            matchFields:         --- [6]
            - key:               --- [7]
              operator:          --- [8]
              values:            --- [9]
          weight:                --- [10]
  • [1](必須)対応する重みと関連付けられたノードセレクター条件。

  • [2] ノードのラベル別の、ノードセレクター要件のリスト。

  • [3](必須)セレクターが適用されるラベルキー。

  • [4](必須)``key`` が values とどのような関係であるかを表します。有効な operator は、InNotInExistsDoesNotExistGt、および Lt です。

  • [5] 文字列値の配列。

    operatorIn または NotIn である場合は、values 配列を空にすることはできません。

    operatorExists または DoesNotExist である場合は、values 配列を空にする必要があります。

    operatorGt または Lt の場合は、values 配列の要素を 1 つにする必要があります。この要素は整数と解釈されます。

  • [6] ノードセレクター要件のリスト。

  • [7](必須)セレクターが適用されるラベルキー。

  • [8](必須)``key`` が values とどのような関係であるかを表します。有効な operator は、InNotInExistsDoesNotExistGt、および Lt です。

  • [9] 文字列値の配列。

    operatorIn または NotIn である場合は、values 配列を空にすることはできません。

    operatorExists または DoesNotExist である場合は、values 配列を空にする必要があります。

    operatorGt または Lt の場合は、values 配列の要素を 1 つにする必要があります。この要素は整数と解釈されます。

  • [10](必須)``1`` ~ 100 の範囲内で対応する nodeSelectorTerm との一致に関連付けられた重み。

Confluent コンポーネントのポッドアフィニティとポッドアンチアフィニティの構成

このセクションでは、ポッドアフィニティとポッドアンチアフィニティのスケジューリングルールを構成する方法、たとえば既にノード上で実行されている他のポッドと同じノードまたはゾーンにポッドを併置するか、併置を避けるかの構成方法について説明します。

ポッドを併置するノード、またはポッドのスケジューリングを避けるノードを指定するには、topologyKey を使用します。選択したポッドの実行先となるノードのラベルが、topologyKey と一致する必要があります。

一般に topologyKey は、アフィニティルールが適用される粒度を指定する目的で使用されます。

たとえば、同じノード上で他のアプリケーションと一緒に Kafka を実行することが望ましくない場合、topologyKeykubernetes.io/hostname に設定して、同じホスト名を持つノードへの Kafka ポッドのスケジューリングを避けるように指定します。

別の例として、アンチアフィニティルールの topologyKeytopology.kubernetes.io/zone に設定した場合で、なおかつ us-central1-a ゾーンのノードで Kafka ポッドが実行されているとします。この場合スケジューラーは、異なるゾーン、つまりノードラベルの topology.kubernetes.io/zone の値が us-central1-a ではないゾーンからノードを検索します。

ポッドのアフィニティルールとアンチアフィニティルールは、次の 2 種類がサポートされます。

  • requiredDuringSchedulingIgnoredDuringExecution

    ポッドがノードにスケジューリングされるためには、そのポッドがこれらのルールを満たしている必要があります。

  • preferredDuringSchedulingIgnoredDuringExecution

    指定したアフィニティ式を満たしたポッドは、スケジューラーによって優先的にノードにスケジューリングされますが、1 つまたは複数の式と一致しないノードが選択される場合もあります。

    重みの合計が最大となるノードが最も優先されます。

ポッドは名前空間に属しているため、ポッドのアフィニティとアンチアフィニティは名前空間内で適用されます。

preferredDuringSchedulingIgnoredDuringExecution を使用したポッドアフィニティの構成

Confluent コンポーネントの CR の affinity プロパティを次のように構成し、リソースを作成するか、アップデートします。

spec:
  podTemplate:
    affinity:
      podAffinity:
        preferredDuringSchedulingIgnoredDuringExecution:
          - podAffinityTerm:     --- [1]
              namespaces:        --- [2]
              labelSelector:     --- [3]
              topologyKey:       --- [4]
          weight:                --- [5]
  • [1](必須)対応する重みと関連付けられたポッドアフィニティ条件。

  • [2] labelSelector が適用される(照合する)名前空間。Null または空のリストである場合は、このポッドの名前空間を意味します。

  • [3] 一致するポッドを見つけるために使用されるクエリ。詳細については、「ポッドラベルセレクター」を参照してください。

  • [4](必須)クラスターノードのラベル。

    このポッドは、指定した名前空間の labelSelector に一致するポッドと同じ場所(アフィニティの場合)に、または、異なる場所(アンチフィニティの場合)にある必要があります。同じ場所にあるということは、ラベルの値(topologyKey を含む)が、選択したポッドのいずれかが実行されているノードのラベルの値と一致するノードで実行されているということです。

    空の topologyKey は使用できません。

  • [5](必須)``1`` ~ 100 の範囲内で対応する podAffinityTerm との一致に関連付けられた重み。

requiredDuringSchedulingIgnoredDuringExecution を使用したポッドアフィニティとポッドアンチアフィニティの構成

Confluent コンポーネントの CR の affinity プロパティを次のように構成し、リソースを作成するか、アップデートします。

spec:
  podTemplate:
    affinity:
      podAffinity:
        requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:      --- [1]
          namespaces:           --- [2]
          topologyKey:          --- [3]
  • [1] 一致するポッドを見つけるために使用されるクエリ。詳細については、「ポッドラベルセレクター」を参照してください。

  • [2] labelSelector が適用される(照合する)名前空間。Null または空のリストである場合は、このポッドの名前空間を意味します。

  • [3](必須)クラスターノードのラベル。

    このポッドは、指定した名前空間の labelSelector に一致するポッドと同じ場所(アフィニティの場合)または異なる場所(アンチフィニティの場合)にある必要があります。

    空の topologyKey は使用できません。

ポッドラベルセレクター

labelSeletor をポッドアフィニティ、ポッドアンチアフィニティ、およびポッドトポロジーの分散制約で使用して、制約が適用される条件に一致するポッドを見つけます。

labelSelector:
  matchExpressions:    --- [1]
  - key:               --- [2]
    operator:          --- [3]
    values:            --- [4]
  matchLabels:         --- [5]
  • [1] ラベルセレクター要件のリスト。各要件は AND で連結されています。

    セレクターには、値、キー、および、キーと値を関連付ける演算子が含まれます。

  • [2](必須) セレクターが適用されるラベルキー。

  • [3](必須)一連の値とキーがどのような関係であるかを表します。有効な operator は、InNotInExists`、``DoesNotExist です。

  • [4] 文字列値の配列。

    operator が In または NotIn である場合は、values 配列を空にすることはできません。

    operator が Exists または DoesNotExist である場合は、values 配列を空にする必要があります。

  • [5] {key,value} ペアのマップ。各要件は AND で連結されています。

labelSelector で使用できる次のラベルが CFK によって追加されます。

ラベルのキー ラベルの値
app <cluster name>
clusterId operator
confluent-platform "true"
platform.confluent.io/type <CR type>
type <cluster name>

同じホストで 2 つの Connect アプリがスケジュール設定されないようにするサンプル CR スニペット

spec:
  podTemplate:
    affinity:
      podAntiAffinity:
        requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - connect
            topologyKey: "kubernetes.io/hostname"

ポッドトポロジーの分散制約の構成

TopologySpreadConstraints は、複数のトポロジードメインにわたって Confluent ポッドのスケジュールを指定する方法を説明するものです。

すべての topologySpreadConstraints は AND で連結されています。

ポッドトポロジーの分散制約を適用する Confluent コンポーネント CR で以下を指定します。

spec:
  podTemplate:
    topologySpreadConstraints:
      - labelSelector:           --- [1]
        maxSkew:                 --- [2]
        topologyKey:             --- [3]
        whenUnsatisfiable:       --- [4]
  • [1] 一致するポッドを見つけるために使用されます。このラベルセレクターに一致するポッドがカウントされて、対応するトポロジードメイン内のポッド数が特定されます。詳細については、「ポッドラベルセレクター」を参照してください。
  • [2](必須) ポッドが不均等に分散されている程度を表します。デフォルト値は、最も均等な分散を表す 1 です。0 は使用できません。
  • [3](必須)ノードラベルのキー。このキーを含み、値が同じである各ノードは、同じトポロジーにあると見なされます。
  • [4](必須)分散制約を満たさない場合のポッドの取り扱いを示します。使用できる値は、DoNotSchedule (デフォルト)と ScheduleAnyway です。

以下の例では、すべてのワーカーノードにわたって、バランスよく均等に Kafka ポッドを分散するように指定しています。

spec:
  topologySpreadConstraints:
    - maxSkew: 1
      topologyKey: kubernetes.io/hostname
      whenUnsatisfiable: ScheduleAnyway
      labelSelector:
        matchLabels:
          type: kafka-pods

1 ノードあたり 1 レプリカの構成

OneReplicaPerNode は、ポッドアンチアフィニティ機能を通じて、1 ノードにつき 1 つのポッドを実行するように強制するプロパティです。ポッドのワークロードには専用ノードが割り当てられます。

OneReplicaPerNode は、デフォルトで無効になっています。

このプロパティを有効にする(OneReplicaPerNode: true)と、ポッドアンチアフィニティが無効になります。

既存のクラスターでこのプロパティを変更すると、クラスターがローリングされます。

Confluent の CR の oneReplicaPerNode プロパティを次のように構成し、リソースを作成またはアップデートします。

spec:
  oneReplicaPerNode:    # Set it to true or false.