1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Pod をAZ(アベイラビリティーゾーン)ごとに分散して配置させたい

Last updated at Posted at 2021-03-09

AWS は堅牢であるものの、AZレベルの障害が発生しているため、複数のAZに分散して可用性を高めておきたいものです。
下記の図のように、各ゾーンごとにノードが配置されている場合、Podについてもそれぞれのゾーン毎に配置したいのですが、単純に replicas の数を増やしても、各ノードのリソースの空き状況に応じて配置されるだけなので、思ったように分散されないこともしばしばです。

fig-1.png

PodAffinity / PodAntiAffinity について

Pod をどのノードに配置するかを指定する方法として、 ノードに付与されたラベルから配置先を指定する nodeSelector と、より柔軟な指定ができる nodeAffinity / nodeAntiAffinity があります。
これらはあくまでもノードに付与されたラベルから配置先を指定しますが、PodAffinity / PodAntiAffinity はノードのラベルではなく、すでに配置されたPodのラベルから配置先を指定することができます。

下記の図のように既に実行中のPodを避けて配置先を指定したい場合は PodAntiAffinity を指定します。

fig-2.png

また、指定できる条件として、必須条件の requiredDuringSchedulingIgnoredDuringExecution と、条件に満たなかった場合でも配置を試みる preferredDuringSchedulingIgnoredDuringExecution があります。

1AZで複数のノードを使用していたり、リソースの使用状況に応じてノード数やPod数を増減させるような、cluster autoscaler や Horizontal Pod Autoscaler (HPA) を使っている場合、必須条件である requiredDuringSchedulingIgnoredDuringExecution で指定していると本来必要なPodが実行できないことになるため、preferredDuringSchedulingIgnoredDuringExecution を指定することになると思います。

動作確認

検証環境として以下のような2AZに1ノードずつ配置したEKSを構築しました。

fig-3.png

以下のようなテスト用 Deployment を replicas: 1 で実行します。

test.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: podinfo
spec:
  selector:
    matchLabels:
      app: podinfo
  replicas: 1
  template:
    metadata:
      labels:
        app: podinfo
    spec:
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - podinfo
              topologyKey: "failure-domain.beta.kubernetes.io/zone"
      containers:
      - name: podinfo
        image: stefanprodan/podinfo		
$ kubectl apply -f test.yaml

下記のように ap-northeast-1 にある nod-1 に配置されました。

fig-4.png

次にレプリカ数を 2 に増やしてみます。

$ kubectl scale deployment.v1.apps/podinfo --replicas=2

想定通り、既に配置しているap-northeast-1aを避けてap-northeast-1c にある node-2 に配置されました。

fig-5.png

さらにレプリカ数を増やしてみます。

$ kubectl scale deployment.v1.app/podinfo --replicas=3

preferredDuringSchedulingIgnoredDuringExecution で設定しているので、既に同じAZで実行中のPodがあるものの、新しくPodが node-2 で実行されました。

fig-6.png

この状態で ap-northeast-1dnode-3という新しいノードを追加してみます。

fig-7.png

新しいノードが追加されても、kubernetesは自動でPodのリバランスは行われないため、node-2 で Podが2つ動いている状態は解消されません。

Descheduler for Kubernetes でリバランスを行う

先記のように、PodAntiAffinity を使って Pod の配置先を指定したとしても、条件によって偏って配置されてしまったPodはリバランスされないため、手動でPodを停止させるなどしないと解消されません。

descheduler を使うと CronJob として実行し、偏って配置されたPodを停止して正しいノード先に再配置されるようになります。

descheduler では PodAntiAffinity に違反したPodを停止する以外にも以下のようなポリシーを設定することもできます。

  • 同じノードに重複してPodが配置されている場合に重複したPodを停止させて別ノードに配置されるようにする。
  • 使用率が低いノードがある場合、他のノードのPodを停止して、このノードに配置されるようにする。

それ以外は Policy and Strategies を参照してください。
ただし、 descheduler は、あくまでもPodを停止する事しかしないため、Podの再配置については Kuberenetes が決定するため、思った通りの挙動にならないこともあります。

では、Helm でインストールできるので検証用EKSにインストールしてみます。

$ helm upgrade --install --namespace kube-system descheduler descheduler/descheduler

デフォルトでは */2 * * * * なので、毎2分ごとに実行されます。
しばらく待つと descheduler が実行されて下記のようにPodが正しく再配置されました。

fig-8.png

まとめ

PodAntiAffinity と descheduler を使うことで、AZ(アベイラビリティーゾーン)ごとにPodを分散して配置することができるようになりました。
descheduler を使うと、意図しないタイミングでPodが停止することになるので、Pod disruption budgets や コンテナーの Lifecycle Hook の PreStop の設定を行なっておく必要もあるかと思います。

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?