🦔

【Kubernetes】Pod のスケジューリング関連

2024/05/18に公開

Pod をデプロイする Node の指定 Node slector

例えば、SSD をマウントしているノードにのみ Pod をスケジュールしたいケースがある
そういう場合は、Pod のマニフェストファイルの .spec.nodeSelector で特定のラベルの付いたノードを指定してあげればいい
もちろん、ノードには予めラベル"disktype: ssd"を付与しておく必要がある

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx:lastest
  nodeSelector:
    disktype: ssd

Pod のスケジュールを指定する Affinity / Anti-affinity

Affinity と Anti-affinity には、3種類存在する

  • Node affinity
  • Pod affinity
  • Pod anti-affinity

Node affinity

概念的には Node Selector と近い。
異なる点としては、「可能であればスケジューリングする」という選択肢が増えること。
Node Selector では、指定したノードに付与されたタグに対応するノードにしかスケジューリングできない。その点で、ノード単位での障害に弱くなってしまう懸念がある。
Node affinity を使用することで、柔軟にノードへのスケジューリングが可能になり、障害にも比較的強くなるので、必ずこのノードに Pod をスケジューリングする必要があるという明確な要件がない限りは、Node affinity を使用するのがいいかもしれない。

requiredDuringSchedulingIgnoredDuringExecution

Pod のマニフェスト内 .spec.affinity.nodeAffinity 配下に設定する項目
対応するノードが見つからない場合は、Pod のスケジューリングを実行しない
Node Selector と概念は一緒だけど、より柔軟なノードの指定が可能

prefferedDuringSchedulingIgnoredDuringExection

Pod のマニフェスト内 .spec.affinity.nodeAffinity 配下に設定する項目
対応するノードが見つからない場合は、適当なノードにスケジューリングする

Node affinity を使用したマニフェストを見てみる

requiredDuringSchedulingIgnoredDuringExecution も prefferedDuringSchedulingIgnoredDuringExection も matchExpression という設定項目を使用してノードを指定する

以下のマニフェストは、「Node についてるラベルに disktype:ssd を含んでいる場合には、その Node を優先してスケジューリングする。ただし、そのような Node が存在しない場合は他の適当な Node でもいいからスケジューリングする」という意味。

apiVersion: v1
kind: Pod
metadata:
  name: sample
spec:
  affinity:
    nodeAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference:
          matchExpressions:
          - key: disktype
            operator: In
            values:
            - ssd
  containers:
  - name: sample
    image: nginx:latest

.spec.affinity.nodeAffinity.preferredDuringSchedulingIgnoredDuringExecution[].preference.matchExpression[].operator に関しては、"In"以外にも"NotIn"や"Exists"なども選べるので、公式ドキュメントを参照。
preferredDuringSchedulingIgnoredDuringExecution を指定する場合、"weight"の指定が必須
preferredDuringSchedulingIgnoredDuringExecution 内の各条件に設定された weight の合計値が最も高いノードに優先してスケジューリングされるので、複数の条件を preferredDuringSchedulingIgnoredDuringExecution の配列に定義している場合は気を付けること。

Pod Affinity/Pod Anti-anffinity

名称の通り、Pod 間の Affinity という解釈が一番自然
Node Affinity は Node のラベルによってスケジューリングを決定していたが、Pod Affinity はノードにデプロイされている Pod のラベルによってスケジューリングを決定する
例えば、ノード自体の故障を見越して、SPOF を発生させないように同じアプリケーションが載っている Pod は同じノードに載せないといったような使い方がある。
Deployment のマニフェスト内で Pod を冗長化していたとしても同じノードに載せていれば、ノードが壊れたらもうアプリは動かないので、この考慮は非常に重要になってくる。
Node Affinity と同様に requiredDuringSchedulingIgnoredDuringExecution と preferredDuringSchedulingIgnoredDuringExecution を設定することが可能だよ

Pod Anti-affinity を使用したマニフェストを見てみる

このマニフェストは、「Pod についてるラベルに app:nginx が含まれている場合、その Pod 同士を可能な限り同じノードにスケジューリングしない」という意味

apiVersion: v1
kind: Pod
metadata:
  name: sample
  labels:
    app: nginx
spec:
  affinity:
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: app
              operator: In
              values:
              - nginx
          topologyKey: kubernetes.io/hostname
  containers:
  - name: sample
    image: nginx:latest

spec.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[].podAffinityTerm.topologyKey に"kubernetes.io/hostname"を指定すると、同じホスト(名)のノードに配置しないというケースを表現できる。
他にも kubernetes.io 提供のトポロジーキーがあるため、公式ドキュメント参照

topolgySpreadConstraints

k8s クラスターがクロスゾーン構成の場合、ゾーンごとに Pod を分散配置することが可用性の観点から重要。
例えば、2ゾーンで構成されるクラスターで、アプリケーションの Pod が1ゾーンに偏ってデプロイされたとき、そのゾーンで障害が発生した場合にはサービス継続が難しくなる。
こういう時に使用するのが、topolgySpreadConstraints であって、Pod の配置数の偏りを少なくすることが可能。
topolgySpreadConstraints は、Pod のマニフェストにおいて、.spec.topolgySpreadConstraints で定義する。※affinity と同レベル
topolgySpreadConstraints は配列で複数の条件を記載可能
条件に含める設定項目は以下の通り

  • topologyKey: ノード群としてまとめるラベルの設定。この群の単位で配置が考慮される。
  • maxskew: 許容可能な差分数
  • labelSelector: 数をカウントする対象の Pod のラベル
  • whenUnsatisfiable: 条件が満たされない場合の挙動指定

topolgySpreadConstraints を使用したマニフェストを見てみる

以下のマニフェストは、「"app: nginx"というラベルの付いた Pod は、"zone"というラベルの付いたノード単位で差分が1よりも大きくならないように分散して配置する」という意味
例えば、"zone: A"と"zone: B"というラベルがつくノードが存在する場合、「zone A群」と「zone B群」にデプロイされる"app: nginx"というラベルが付いてる Pod 数を比較したとき、差分が1よりも大きくならないということ。
Pod 数の総合計が5個の場合、以下の2パターンの配置が考えられる

  • "zone A" に Pod が2個かつ、"zone B" に Pod が3個
  • "zone A" に Pod が3個かつ、"zone B" に Pod が2個
kind: Pod
apiVersion: v1
metadata:
  name: sample
  labels:
    app: nginx
spec:
  topologySpreadConstraints:
  - maxSkew: 1
    topologyKey: zone
    whenUnsatisfiable: DoNotSchedule
    labelSelector:
      matchLabels:
        app: nginx
  containers:
  - name: sample
    image: nginx:latest

.spec.topologySpreadConstraints[].whenUnsatisfiable が "DoNotSchedule" の場合、条件を満たせなかった場合に Pod を配置しない
条件に合わない場合でもどこか適当に Pod を配置する場合は、"ScheduledAnyway"を指定する。
topologykey は、ラベルの Key のみで、value がどうかは関係ないよ

Taint/Toleration

Taint はノードに設定する項目
Toleration は Pod に設定する項目
それぞれ日本語直訳すると、、、、

  • Taint = 汚れ
  • Toleration = 寛容
    つまり、「ノードに付いている『汚れ』を Pod が許容できるか」という解釈
    Node Affinity と対称的な概念。
    Node affinity は、「どんなノードに Pod をスケジューリングしたいか」だったが、Taint/Toleration は、「どんなノードに Pod をスケジューリングしたくないか

Discussion