StatefulSet の Pod を各ノードに順番に並べる方法

StatefulSet の Pod を各ノードに順番に並べたいユースケースに直面しました.

具体的にやりたいことは以下のようなことです.

  • Pod 0 → ノード1番目
  • Pod 1 → ノード2番目
  • Pod 2 → ノード3番目

今回は上記のようなスケジューリングを Kubernetes の Affinity 定義を使って実現してみます.

Node Affinity と Pod Anti Affinity を用いたスケジューリング

以下のような YAML で実現できます.

apiVersion: apps/v1
kind: StatefulSet
metadata:  
  labels:
    app: example-app
  name: example-app
  namespace: kawanuma
spec:
  replicas: 3
  selector:
    matchLabels:
      app: example-app
  template:
    metadata:      
      labels:
        app: example-app
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                  - key: "app"
                    operator: In
                    values:
                    - example-app
              topologyKey: "kubernetes.io/hostname"
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            preference:
              matchExpressions:
              - key: kubernetes.io/hostname
                operator: In
                values:
                - worker1.example.com
          - weight: 50
            preference:
              matchExpressions:
              - key: kubernetes.io/hostname
                operator: In
                values:
                - worker2.example.com
          - weight: 1
            preference:
              matchExpressions:
              - key: kubernetes.io/hostname
                operator: In
                values:
                - worker3.example.com
      containers:
      - image: fabxc/instrumented_app
        imagePullPolicy: Always
        name: example-app
        ports:
        - containerPort: 8080
          name: web
          protocol: TCP
        resources: {}
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File                
      securityContext: {}
      terminationGracePeriodSeconds: 30

 

解説していきます.

 

まずは Pod Anti Affinity です.
こちらを指定することで『StatefulSet の各 Pod を同じノードに重複して配置しない』ということが実現できます. 簡単な言葉に言い換えると、『各ノードにばらけて配置する』ということになります.

今回は kubernetes.io/hostname をトポロジー(グルーピング)のキーとして、app=example-app が同一の Pod が重複して配置されないように指定しました.

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

 

次に Node Affinity です.
こちらを指定することで『ノードに優先度を付けて配置する』ということが実現できます.

今回は kubernetes.io/hostname をキーに、worker0, worker1, worker2 の順番で優先度を高くしてあります(なお、スケジューリングはこの値のみで決まるわけではないので、出来るだけ weight の値に差がでるように値を設定しています).

nodeAffinity:
  preferredDuringSchedulingIgnoredDuringExecution:
  - weight: 100
    preference:
      matchExpressions:
      - key: kubernetes.io/hostname
        operator: In
        values:
        - worker1.example.com
  - weight: 50
    preference:
      matchExpressions:
      - key: kubernetes.io/hostname
        operator: In
        values:
        - worker2.example.com
  - weight: 1
    preference:
      matchExpressions:
      - key: kubernetes.io/hostname
        operator: In
        values:
        - worker3.example.com

 

以上です.

 

参考