Kubernetes Deschedulerの概要と使い方 (Kubernetes 1.30+対応)

Kubernetes **Descheduler** は、クラスター内のPod配置を再評価して不要なPodをエビクト（削除）することで再スケジューリングを促すコンポーネントです。デフォルトのスケジューラ(kube-scheduler)はPod作成時にしかスケジューリングしませんが、Deschedulerは**既存のPodを定期的にチェックして適切でない配置のPodを退去させ、再配置を促す**役割を担います ([Descheduler GA in OpenShift 4.7](https://www.redhat.com/en/blog/descheduler-ga-in-openshift-4.7#:~:text=The%20Descheduler%20is%20an%20upstream,criteria%20and%20algorithms%20it%20provides)) ([Kubernetes: Kubernetes Descheduler とは #kubernetes - Qiita](https://qiita.com/tkusumi/items/7c5b2b958a7e4beaf5ee#:~:text=Kubernetes%20Descheduler%20%E3%81%AF%E3%82%B9%E3%82%B1%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E6%B8%88%E3%81%BF%E3%81%AE%20Pod%20%E5%89%8A%E9%99%A4,scheduler%20%29%20%E3%81%8C%E8%A1%8C%E3%81%84%E3%81%BE%E3%81%99%E3%80%82))。Descheduler自身はエビクトのみを行い、**削除されたPodの再スケジューリング自体は通常のスケジューラ**（デフォルトまたは指定されたカスタムスケジューラ）が行います ([Kubernetes: Kubernetes Descheduler とは #kubernetes - Qiita](https://qiita.com/tkusumi/items/7c5b2b958a7e4beaf5ee#:~:text=Kubernetes%20Descheduler%20%E3%81%AF%E3%82%B9%E3%82%B1%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E6%B8%88%E3%81%BF%E3%81%AE%20Pod%20%E5%89%8A%E9%99%A4,scheduler%20%29%20%E3%81%8C%E8%A1%8C%E3%81%84%E3%81%BE%E3%81%99%E3%80%82))。以下では、Deschedulerの目的と仕組み、導入方法、主要なユースケース、および標準スケジューラや他のカスタムスケジューラとの比較について説明します。

## Deschedulerとは何か？目的と動作原理

**Descheduler**はKubernetesのサブプロジェクト（SIG-Scheduling 管轄）であり、**既存のPodの配置を見直してクラスターのバランス改善やポリシー順守を図るためのツール**です ([Descheduler GA in OpenShift 4.7](https://www.redhat.com/en/blog/descheduler-ga-in-openshift-4.7#:~:text=The%20Descheduler%20is%20an%20upstream,criteria%20and%20algorithms%20it%20provides))。KubernetesのスケジューラはPod生成時に最適なノードを選択しますが、一度Podがノードに割り当てられると、その後ノード状況が変化しても自動で再評価・移動することはありません ([Descheduler GA in OpenShift 4.7](https://www.redhat.com/en/blog/descheduler-ga-in-openshift-4.7#:~:text=criteria%20and%20algorithms%20it%20provides)) ([Kubernetes: Kubernetes Descheduler とは #kubernetes - Qiita](https://qiita.com/tkusumi/items/7c5b2b958a7e4beaf5ee#:~:text=Kubernetes%20%E3%81%AE%E3%82%B9%E3%82%B1%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%A9%E3%81%AF%20Pod%20%E3%81%AE%E4%BD%9C%E6%88%90%E6%99%82%E3%81%AB%E3%81%97%E3%81%8B%E3%82%B9%E3%82%B1%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AA%E3%83%B3%E3%82%B0%E3%82%92%E8%A1%8C%E3%82%8F%E3%81%AA%E3%81%84%E3%81%9F%E3%82%81%E3%80%81%E9%95%B7%E6%9C%9F%E7%9A%84%E3%81%AB%E8%A6%8B%E3%82%8B%E3%81%A8%E4%B8%8B%E8%A8%98%E3%81%AE%E3%82%88%E3%81%86%E3%81%AA%E8%AA%B2%E9%A1%8C%E3%81%8C%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99%E3%80%82))。例えば、時間の経過とともに:

- あるノードだけ**リソース使用率が高く偏って**しまう  
- Podスケジューリング後に**ノードのラベルやタaints**が変更されても、既存のPodには反映されない  
- **新しいノードが追加**されても、既存のPodは自動ではそのノードに分散されない  

といった問題が発生しがちです ([Kubernetes: Kubernetes Descheduler とは #kubernetes - Qiita](https://qiita.com/tkusumi/items/7c5b2b958a7e4beaf5ee#:~:text=Kubernetes%20%E3%81%AE%E3%82%B9%E3%82%B1%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%A9%E3%81%AF%20Pod%20%E3%81%AE%E4%BD%9C%E6%88%90%E6%99%82%E3%81%AB%E3%81%97%E3%81%8B%E3%82%B9%E3%82%B1%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AA%E3%83%B3%E3%82%B0%E3%82%92%E8%A1%8C%E3%82%8F%E3%81%AA%E3%81%84%E3%81%9F%E3%82%81%E3%80%81%E9%95%B7%E6%9C%9F%E7%9A%84%E3%81%AB%E8%A6%8B%E3%82%8B%E3%81%A8%E4%B8%8B%E8%A8%98%E3%81%AE%E3%82%88%E3%81%86%E3%81%AA%E8%AA%B2%E9%A1%8C%E3%81%8C%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99%E3%80%82))。これらはクラスターの長期運用で典型的な課題で、結果としてリソースの不均衡やポリシー違反状態が放置される可能性があります。

**Deschedulerの目的**は、このような**変更後の最適でない状態を是正すること**にあります。Deschedulerは定期的にクラスター内の全Podとノード状態を評価し、あらかじめ定義したポリシー（ストラテジー）に基づいて「現在のノードより他のノードに配置した方が良い」と判断されるPodを抽出します ([Descheduler GA in OpenShift 4.7](https://www.redhat.com/en/blog/descheduler-ga-in-openshift-4.7#:~:text=However%2C%20one%20limitation%20of%20the,the%20cluster%20against%20their%20nodes))。該当Podに対してKubernetesのエビクト(Eviction API)を用いて**削除**を行い（Podを削除することでDeploymentやReplicaSetが自動的に代替Podを再作成します）、その新規Podは通常どおりスケジューラによってより適切なノードにスケジューリングされます ([descheduler/charts/descheduler/README.md at master · kubernetes-sigs/descheduler · GitHub](https://github.com/kubernetes-sigs/descheduler/blob/master/charts/descheduler/README.md#:~:text=Descheduler%20for%20Kubernetes)) ([Kubernetes: Kubernetes Descheduler とは #kubernetes - Qiita](https://qiita.com/tkusumi/items/7c5b2b958a7e4beaf5ee#:~:text=Kubernetes%20Descheduler%20%E3%81%AF%E3%82%B9%E3%82%B1%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E6%B8%88%E3%81%BF%E3%81%AE%20Pod%20%E5%89%8A%E9%99%A4,scheduler%20%29%20%E3%81%8C%E8%A1%8C%E3%81%84%E3%81%BE%E3%81%99%E3%80%82))。このように、Deschedulerは**既存Podの「デスケジューリング」**を行うことで結果的にPodの再スケジューリングを発生させ、クラスターの状態を改善します。

**動作原理**としては、Deschedulerは内部でプラグイン化された複数の「**ストラテジー(Strategy)**」を用いてポリシー違反や最適ではないPodを判定します ([Descheduler GA in OpenShift 4.7](https://www.redhat.com/en/blog/descheduler-ga-in-openshift-4.7#:~:text=The%20Descheduler%20provides%20a%20number,available%20in%20the%20OperatorHub%20marketplace))。各ストラテジーは特定のチェック項目を持ち（例: ノードの利用率、PodのAffinity/Anti-Affinity違反、トポロジースプレッド違反など）、条件に合致するPodを見つけた場合にそのPodをエビクト対象とします。実際のエビクトでは、`kubectl delete pod`と同様の操作が行われますが、**PodDisruptionBudget(PDB)** が設定されている場合はそれを考慮して安全に実行されます（PDBを満たさないエビクトはブロックされます）。Descheduler自体はスケジューリングを行わないため、**既存のスケジューラと補完的**に動作します ([Descheduler GA in OpenShift 4.7](https://www.redhat.com/en/blog/descheduler-ga-in-openshift-4.7#:~:text=The%20Descheduler%20is%20an%20upstream,criteria%20and%20algorithms%20it%20provides))。

## どのような状況でDeschedulerを使用すべきか？

Deschedulerは、**クラスター稼働中の状態変化によりPod配置の見直しが必要な状況**で力を発揮します。具体的には以下のようなケースで利用を検討できます。

- **ノード間のリソース利用率の偏り**: 時間の経過やワークロードの変化で、一部のノードにCPUやメモリ負荷が集中し他が遊休状態になることがあります。Deschedulerのリソース利用率ベースのストラテジーを使えば、**過負荷ノード上のPodを他ノードへ移動させて負荷分散**が可能です ([Kubernetes: Kubernetes Descheduler とは #kubernetes - Qiita](https://qiita.com/tkusumi/items/7c5b2b958a7e4beaf5ee#:~:text=Kubernetes%20%E3%81%AE%E3%82%B9%E3%82%B1%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%A9%E3%81%AF%20Pod%20%E3%81%AE%E4%BD%9C%E6%88%90%E6%99%82%E3%81%AB%E3%81%97%E3%81%8B%E3%82%B9%E3%82%B1%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AA%E3%83%B3%E3%82%B0%E3%82%92%E8%A1%8C%E3%82%8F%E3%81%AA%E3%81%84%E3%81%9F%E3%82%81%E3%80%81%E9%95%B7%E6%9C%9F%E7%9A%84%E3%81%AB%E8%A6%8B%E3%82%8B%E3%81%A8%E4%B8%8B%E8%A8%98%E3%81%AE%E3%82%88%E3%81%86%E3%81%AA%E8%AA%B2%E9%A1%8C%E3%81%8C%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99%E3%80%82))。
- **ノードの追加・削除（スケールアウト/イン）**: 新しいノードをクラスターに追加した場合、既存のDeployment/ReplicaSet管理下のPodは自動ではそのノードに移動しません（DaemonSetとは異なります）。障害対応でノードを入れ替えた場合も同様です。このような時、**Deschedulerを使って既存Podを一旦エビクトすることで、新ノードを含めPodを再分散**させることができます ([Descheduler for KubernetesでPod(レプリカ)の再スケジュールを促す #AWS - Qiita](https://qiita.com/Takagi_/items/2c702557b3438ae9b46f#:~:text=))。手動で`kubectl delete pod`する手間を省き、自動で均等化できます。
- **ノードの状態変化によるポリシー不整合**: Podスケジューリング後にノードに変更が起きた場合（例：ノードに新たなラベル付与やタイント追加、他Podの配置状況変化など）、当初のスケジューリング条件を満たさない状態になることがあります。Deschedulerは**PodのAffinity/Anti-AffinityやTaints/Tolerations、Topology Spread Constraints**の違反を検知して該当Podをエビクトできます ([Descheduler for KubernetesでPod(レプリカ)の再スケジュールを促す #AWS - Qiita](https://qiita.com/Takagi_/items/2c702557b3438ae9b46f#:~:text=%E3%81%A8%E3%81%82%E3%82%8BPod%E5%90%8C%E5%A3%AB%E3%82%92%E5%90%8C%E3%81%98WorkerNode%E4%B8%8A%E3%81%A7%E8%B5%B7%E5%8B%95%E3%81%95%E3%81%9B%E3%81%9F%E3%81%84%E6%99%82%E3%81%AB%E4%BD%BF%E3%81%86PodAffinity%E3%82%84%E3%80%81Pod%E3%81%8C%E8%B5%B7%E5%8B%95%E3%81%99%E3%82%8BNode%E3%82%92%E5%9B%BA%E5%AE%9A%E3%81%97%E3%81%9F%E3%81%84%E6%99%82%E3%81%AB%E4%BD%BF%E3%81%86NodeAffinity%20%E3%81%AE%E3%83%AB%E3%83%BC%E3%83%AB%E9%81%95%E5%8F%8D%E3%82%92%E6%A4%9C%E7%9F%A5%E3%83%BB%E3%82%B9%E3%82%B1%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E8%A7%A3%E9%99%A4%E3%82%92%E8%A1%8C%E3%81%86%E3%81%93%E3%81%A8%E3%82%82%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99%E3%80%82))。例えば、`requiredDuringSchedulingIgnoredDuringExecution`のNodeAffinityを持つPodが、後からノードのラベル変更で条件不一致となった場合にそれを退避させる、といった使い方です。
- **長期稼働Podのリフレッシュ**: ペット的に長期間動き続けているPodを定期的に再配置したい場合にもDeschedulerが使えます。`PodLifeTime`ストラテジーを適用すれば、**一定期間以上経過したPodを自動エビクト**し、新しいPodに置き換えることで、潜在的不具合のリセットやロールリング更新に近い効果を得られます ([descheduler/docs/user-guide.md at master · kubernetes-sigs/descheduler · GitHub](https://github.com/kubernetes-sigs/descheduler/blob/master/docs/user-guide.md#:~:text=The%20,application%20to%20ensure%20application%20availability)) ([descheduler/docs/user-guide.md at master · kubernetes-sigs/descheduler · GitHub](https://github.com/kubernetes-sigs/descheduler/blob/master/docs/user-guide.md#:~:text=,args%3A%20maxPodLifeTimeSeconds%3A%20604800))。
- **その他**: CrashLoopや再起動を繰り返しているPodを対象にしたリスケジューリング（`RemovePodsHavingTooManyRestarts`）、Fail状態のPodのクリーンアップ（`RemoveFailedPods`）など、細かなシナリオにも対応するストラテジーがあります ([Usage of Kubernetes Descheduler - SoByte](https://www.sobyte.net/post/2023-04/k8s-descheduler/#:~:text=,RemovePodsHavingTooManyRestarts))。

以上のように、**クラスター内の状態変化で初期スケジューリング時の前提が崩れた場合**や、**より均衡の取れた資源配分を図りたい場合**にDeschedulerを使うと効果的です。逆に、クラスターが小規模であったりワークロードの変動が少ない場合、またはPod配置を頻繁に変更したくない場合には必ずしも導入する必要はありません。Deschedulerを適用する際は、**アプリケーションの耐障害性**にも留意しましょう。Podの再スケジューリングにより一時的に停止が発生し得るため、**PodDisruptionBudgetの設定**や、一度にエビクトするPod数の上限設定（`maxNoOfPodsToEvictPerNode` など）で影響を緩和することが重要です ([Descheduler for KubernetesでPod(レプリカ)の再スケジュールを促す #AWS - Qiita](https://qiita.com/Takagi_/items/2c702557b3438ae9b46f#:~:text=%E6%B0%97%E3%82%92%E4%BB%98%E3%81%91%E3%81%9F%E3%81%84%E3%83%9D%E3%82%A4%E3%83%B3%E3%83%88)) ([Usage of Kubernetes Descheduler - SoByte](https://www.sobyte.net/post/2023-04/k8s-descheduler/#:~:text=,be%20evicted%20by%20a%20node))。

## Deschedulerの設定方法

それではDeschedulerの導入と設定方法について説明します。Kubernetes 1.30以降のクラスタであれば、Deschedulerは安定版(v0.3x系)を使用できます。Descheduler自体はデフォルトでKubernetesに組み込まれていないため、**追加でデプロイ**する必要があります。一般的な導入手順として以下の方法があります。

### Deschedulerのインストールと実行

**① Helm Chartを利用する方法**: 公式のHelmチャートが提供されており、簡単にCronJobとしてデプロイできます。まずHelmリポジトリを追加し、インストールコマンドを実行します（`kube-system`名前空間にデプロイする例）。

```bash
# Helmリポジトリの追加
helm repo add descheduler https://kubernetes-sigs.github.io/descheduler/

# Deschedulerをインストール（リリース名: my-descheduler）
helm install my-descheduler --namespace kube-system descheduler/descheduler
```

上記により、デフォルト設定でDeschedulerがCronJobとしてデプロイされます ([descheduler/charts/descheduler/README.md at master · kubernetes-sigs/descheduler · GitHub](https://github.com/kubernetes-sigs/descheduler/blob/master/charts/descheduler/README.md#:~:text=helm%20repo%20add%20descheduler%20https%3A%2F%2Fkubernetes,system%20descheduler%2Fdescheduler)) ([descheduler/charts/descheduler/README.md at master · kubernetes-sigs/descheduler · GitHub](https://github.com/kubernetes-sigs/descheduler/blob/master/charts/descheduler/README.md#:~:text=To%20install%20the%20chart%20with,release))。Helmのvaluesで`kind`パラメータを`CronJob`（デフォルト）または`Deployment`に切り替えることで、CronJobとして定期実行するかデーモン的に常駐させるかを選択可能です（Deployment利用時は`deschedulingInterval`で実行間隔を指定、デフォルト5分間隔 ([descheduler/charts/descheduler/README.md at master · kubernetes-sigs/descheduler · GitHub](https://github.com/kubernetes-sigs/descheduler/blob/master/charts/descheduler/README.md#:~:text=,high%20availability%20when%20running%20replicated))）。多くの場合は**CronJobで数分おきに実行**する形が扱いやすいでしょう。

**② マニフェストを直接適用する方法**: kubernetes-sigs/deschedulerリポジトリには、CronJob用のマニフェストやKustomizeが用意されています。それらを利用してデプロイすることも可能です。例えば、`kubectl`と`kustomize`を使ってCronJobリソースをデプロイするには以下のコマンドを実行します（v0.32.0を使用する例）。

```bash
# CronJobマニフェストを適用（GitHubリポジトリからKustomize経由で取得）
kustomize build "github.com/kubernetes-sigs/descheduler/kubernetes/cronjob?ref=v0.32.0" | kubectl apply -f -
```

上記では公式リポジトリ内のCronJob定義をビルドし、現在のクラスタに適用しています。デフォルトでは`kube-system`名前空間にCronJobが作成され、5分毎程度でDeschedulerのPod(Job)が起動する設定になっています（必要に応じてCronJobのスケジュールを編集可能です）。

どの方法でも、デプロイ後に**Descheduler用のConfigMap（ポリシー定義）**がクラスタ内に作成されます。Helmの場合デフォルトのポリシー、手動適用の場合は標準プロファイルが使われますが、運用シナリオに合わせて**ポリシーを調整する必要があります**。

### Deschedulerポリシーの設定（YAML例）

Deschedulerの動作を制御するポリシーは、`DeschedulerPolicy`というAPIリソース（CustomResourceではなく、ConfigMap内に記述する設定ファイル）で定義します ([descheduler/docs/user-guide.md at master · kubernetes-sigs/descheduler · GitHub](https://github.com/kubernetes-sigs/descheduler/blob/master/docs/user-guide.md#:~:text=,args%3A%20maxPodLifeTimeSeconds%3A%20604800))。複数のストラテジーを有効/無効にしたり、各ストラテジーの閾値や条件を設定可能です。以下に**YAML設定例**を示します。

```yaml
apiVersion: "descheduler/v1alpha2"
kind: "DeschedulerPolicy"
profiles:
  - name: "example-policy"
    pluginConfig:
      # 低利用ノードからPodを集約する HighNodeUtilization の設定例
      - name: "HighNodeUtilization"
        args:
          thresholds:
            cpu: 20    # 各ノードのCPU使用率が20%未満なら対象
            memory: 20 # メモリ使用率20%未満なら対象
      # 高負荷ノードからPodを退避する LowNodeUtilization の設定例
      - name: "LowNodeUtilization"
        args:
          thresholds:
            cpu: 80    # 各ノードCPU使用率が80%超なら退避候補
            memory: 80 # メモリ使用率80%超なら退避候補
          targetThresholds:
            cpu: 50    # 退避後の目標CPU使用率50%以下
            memory: 50 # 退避後の目標メモリ使用率50%以下
      # デフォルトエビクタ設定（システムPodやローカルストレージPodも含める例）
      - name: "DefaultEvictor"
        args:
          evictSystemCriticalPods: true   # kube-system等のクリティカルPodも対象に含める
          evictLocalStoragePods: true     # ローカルストレージを使うPodも対象に含める
          ignorePvcPods: false            # PVCを持つPodを無視しない（対象に含める）
    plugins:
      balance:
        enabled:
          - "LowNodeUtilization"
          - "HighNodeUtilization"
      deschedule:
        enabled:
          - "RemovePodsViolatingNodeAffinity"
          - "RemovePodsViolatingInterPodAntiAffinity"
          - "RemoveDuplicates"
```

上記のポリシー例では、以下のような設定を行っています。

- **LowNodeUtilization / HighNodeUtilization**: ノードのリソース使用率に基づく再配置戦略です。例では、「CPU/メモリ使用率が80%を超えるノード上のPod」を対象にエビクトし、逆に「20%未満のノード」は集約候補として利用する設定になっています（実際の閾値は状況に応じて調整してください）。この組み合わせにより、過負荷ノードからPodを退避しつつ、極端にアイドルなノードへ集約してリソース効率を上げることが可能です。
- **RemovePodsViolatingNodeAffinity など**: ノードアフィニティやPod間のアンチアフィニティ違反、Pod重複配置などを検出してPodをエビクトする戦略です。上記では例として**NodeAffinity**違反、**InterPodAntiAffinity**違反、および**同一ReplicaSetのPodが一つのノードに固まっている場合（RemoveDuplicates）**を有効化しています。
- **DefaultEvictorのパラメータ**: デフォルトではDeschedulerは安全のため**kube-systemなど重要なNamespaceのPodや、ローカルストレージを使うPod、PVCを持つPod**をエビクト対象から除外します。必要に応じて上記のようにフラグを`true`にすることでそれらも含めることができます ([Descheduler for KubernetesでPod(レプリカ)の再スケジュールを促す #AWS - Qiita](https://qiita.com/Takagi_/items/2c702557b3438ae9b46f#:~:text=%60evictSystemCriticalPods%3A%20true%60%20kube,PersistentVolume%E3%82%92%E3%83%9E%E3%82%A6%E3%83%B3%E3%83%88%E3%81%99%E3%82%8BPod%E3%82%82%E3%82%B9%E3%82%B1%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E8%A7%A3%E9%99%A4%E3%81%95%E3%81%9B%E3%82%8B%E3%80%82))。例えば、システム系Podも含めて再スケジューリングしたい場合や、ローカルストレージ上のキャッシュPodを移動させたい場合などに指定します。ただし重要度の高いPodの移動はサービスに影響する可能性もあるため注意してください。

この`DeschedulerPolicy`のYAMLをConfigMapに格納し、DeschedulerのPodに読み込ませることで設定が反映されます。Helmチャート経由の場合は、カスタムのpolicy YAMLを用意して`--set-file policy=<ファイルパス>`等で適用できますし、手動適用の場合は上記ConfigMap (`descheduler-policy-configmap`) を編集することで反映可能です。設定変更後、次回Descheduler実行時から新しいポリシーが有効になります。

## Deschedulerの主要ユースケース

上記の設定例も踏まえ、Deschedulerで実現できる代表的なユースケースをいくつか紹介します。

### 1. リソース使用率の最適化（ノード間の負荷分散）

クラスター内の**CPUやメモリ利用率の偏りを是正**する用途です。例えば、一部のノードだけが常に高負荷で他が閑散としている場合、Deschedulerの`LowNodeUtilization`戦略を使うことで**過負荷ノード上のPodをエビクト**し、比較的余力のあるノードへ再スケジューリングさせることができます ([descheduler/docs/user-guide.md at master · kubernetes-sigs/descheduler · GitHub](https://github.com/kubernetes-sigs/descheduler/blob/master/docs/user-guide.md#:~:text=Using%20,with%20memory%20utilization%20below%2020))。逆に、`HighNodeUtilization`戦略を使えば**極端に低負荷なノード上のPodを他に移し**、ノードを遊休状態にしないよう集約することも可能です（これにより特定ノードを空にできれば、Cluster Autoscalerと併用してノード縮退もできます）。これらによりクラスター全体の**リソース消費を均一化**し、リソースの有効活用やスケーラビリティ向上が期待できます。

### 2. Podの分散配置による可用性向上（レプリカの再スケジューリング）

Deployment/ReplicaSetの**複数レプリカが特定ノードに固まってしまった場合**の再分散にもDeschedulerが有効です。通常、kube-schedulerもスプレッド(Spread)アルゴリズムでできるだけ均等に配置しようとしますが、ノード追加直後やスケジューラの都合で一時的に偏りが出ることがあります。Deschedulerの`RemoveDuplicates`戦略は、**同じReplicaSet由来のPodが一つのノードに複数存在する場合にその一部をエビクト**し、再スケジューラによって他ノードへ再配置させます ([Kubernetes: Kubernetes Descheduler とは #kubernetes - Qiita](https://qiita.com/tkusumi/items/7c5b2b958a7e4beaf5ee#:~:text=RemoveDuplicates))。結果として**各ノード上のレプリカ数が均等**になるため、単一ノード障害時の影響を減らしサービス可用性を高める効果があります ([Descheduler for KubernetesでPod(レプリカ)の再スケジュールを促す #AWS - Qiita](https://qiita.com/Takagi_/items/2c702557b3438ae9b46f#:~:text=))。また、`RemovePodsViolatingTopologySpreadConstraint`を使えば、ゾーンやラック間で定義した**トポロジースプレッドのルール**に違反して偏ってしまったPodを是正できます。例えば、当初1つのアベイラビリティゾーンしか無かったためにゾーン偏在しているPodも、後から別ゾーンにノード追加後にDeschedulerを実行すれば、規定のゾーンバランスに沿って再配置される、といったことが可能です。

### 3. スケジューリングポリシーの順守（Affinity/Anti-Affinityの維持）

Podの**Affinity/Anti-Affinity**やノードの**Taints/Tolerations**など、**スケジューリング時の割り当て制約を運用中に維持する**ユースケースです。スケジューリング時には条件を満たしていたものの、クラスター変更により**後からそれらの条件を満たさなくなったPod**が発生する場合があります。Deschedulerでは以下のような戦略で対応できます。

- `RemovePodsViolatingNodeAffinity`：ノードのラベル条件（NodeAffinity）を満たさなくなったPodをエビクトします。例: Podが要求するラベルをノードが失った場合など。
- `RemovePodsViolatingInterPodAntiAffinity`：互いに同居しないことを望むPod（PodAntiAffinityの対象）が同一ノード上に存在する場合に片方をエビクトします。例: 本来異なるゾーンに置くべきPodが集中してしまった場合など。
- `RemovePodsViolatingNodeTaints`：許容されていないTaintを持つノードに存在するPodをエビクトします。通常、NoExecute以外のTaintは既存Podには影響しませんが、ポリシー上望ましくない場合に強制退去させることができます。

これらの機能により、**クラスター運用中もポリシー準拠の状態を保つ**ことができます ([Descheduler for KubernetesでPod(レプリカ)の再スケジュールを促す #AWS - Qiita](https://qiita.com/Takagi_/items/2c702557b3438ae9b46f#:~:text=%E3%81%A8%E3%81%82%E3%82%8BPod%E5%90%8C%E5%A3%AB%E3%82%92%E5%90%8C%E3%81%98WorkerNode%E4%B8%8A%E3%81%A7%E8%B5%B7%E5%8B%95%E3%81%95%E3%81%9B%E3%81%9F%E3%81%84%E6%99%82%E3%81%AB%E4%BD%BF%E3%81%86PodAffinity%E3%82%84%E3%80%81Pod%E3%81%8C%E8%B5%B7%E5%8B%95%E3%81%99%E3%82%8BNode%E3%82%92%E5%9B%BA%E5%AE%9A%E3%81%97%E3%81%9F%E3%81%84%E6%99%82%E3%81%AB%E4%BD%BF%E3%81%86NodeAffinity%20%E3%81%AE%E3%83%AB%E3%83%BC%E3%83%AB%E9%81%95%E5%8F%8D%E3%82%92%E6%A4%9C%E7%9F%A5%E3%83%BB%E3%82%B9%E3%82%B1%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E8%A7%A3%E9%99%A4%E3%82%92%E8%A1%8C%E3%81%86%E3%81%93%E3%81%A8%E3%82%82%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99%E3%80%82))。特に複雑なAffinityルールを使っている環境やマルチテナント環境では、意図せぬ配置が発生していないか定期的にチェック・修正できる点で有用です。

### 4. 古いPodのリスケジューリング（Podの世代交代）

長期間再起動されていないPodを**定期的に入れ替える**用途にもDeschedulerが使われます。例えば`PodLifeTime`戦略を有効にしておくと、**指定した寿命(稼働時間)を超えたPodを自動的にエビクト**できます ([descheduler/docs/user-guide.md at master · kubernetes-sigs/descheduler · GitHub](https://github.com/kubernetes-sigs/descheduler/blob/master/docs/user-guide.md#:~:text=The%20,application%20to%20ensure%20application%20availability)) ([descheduler/docs/user-guide.md at master · kubernetes-sigs/descheduler · GitHub](https://github.com/kubernetes-sigs/descheduler/blob/master/docs/user-guide.md#:~:text=,%22PodLifeTime))。これにより、数日〜数週間以上動き続けているPodを強制的に再作成させて**メモリリークの解消**や**ローリングアップデートの疑似実行**を行うことが可能です。特に状態を持たず再起動が比較的容易なアプリケーション（ステートレスなWebアプリケーションなど）では、定期的にPodをサイクルさせることでシステムの健全性を保つ一助となるでしょう。ただし、この機能を使う場合もPodDisruptionBudgetを設定するなどして、一度に多数のPodが消えてしまわないよう調整することが重要です。

## 標準スケジューラや他のカスタムスケジューラとの比較

最後に、Deschedulerを**Kubernetes標準のスケジューラやカスタムスケジューラと比較**してその位置付けを整理します。

- **デフォルトのkube-schedulerとの関係**: 上述の通り、kube-schedulerは**新規Podの配置担当**、Deschedulerは**既存Podの再配置担当**という棲み分けになります ([Descheduler GA in OpenShift 4.7](https://www.redhat.com/en/blog/descheduler-ga-in-openshift-4.7#:~:text=The%20Descheduler%20is%20an%20upstream,criteria%20and%20algorithms%20it%20provides))。標準スケジューラはスコアリングアルゴリズム等により最適なノード選択を行いますが、一度スケジューリングされたPodのその後の管理はしません ([Descheduler GA in OpenShift 4.7](https://www.redhat.com/en/blog/descheduler-ga-in-openshift-4.7#:~:text=criteria%20and%20algorithms%20it%20provides))。Deschedulerはまさにそのギャップを埋める**補完的ツール**であり、標準スケジューラでは対処できない「後からの最適化」を担います。したがって、Deschedulerを導入しても**kube-scheduler自体を置き換えるものではなく**、あくまで追加のコントローラとして動作します ([Kubernetes: Kubernetes Descheduler とは #kubernetes - Qiita](https://qiita.com/tkusumi/items/7c5b2b958a7e4beaf5ee#:~:text=Kubernetes%20Descheduler%20%E3%81%AF%E3%82%B9%E3%82%B1%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E6%B8%88%E3%81%BF%E3%81%AE%20Pod%20%E5%89%8A%E9%99%A4,scheduler%20%29%20%E3%81%8C%E8%A1%8C%E3%81%84%E3%81%BE%E3%81%99%E3%80%82))。
- **カスタムスケジューラとの使い分け**: Kubernetesではデフォルト以外にも独自のスケジューラを動かし、Podごとに`spec.schedulerName`で使い分けることが可能です（例：Batchジョブ専用のスケジューラ等） ([Descheduler GA in OpenShift 4.7](https://www.redhat.com/en/blog/descheduler-ga-in-openshift-4.7#:~:text=The%20Descheduler%20is%20an%20upstream,criteria%20and%20algorithms%20it%20provides))。カスタムスケジューラは**スケジューリングロジック自体を変更・拡張**することで、特定の要件（例：先着順ではなく公平にリソースを配分する、GPUワークロード向けに特化する 等）に対応できます。しかし**いずれのスケジューラもPod配置後に能動的に移動させる機能は基本持ちません**。仮にカスタムスケジューラを導入しても、クラスター状況の変化に応じた再配置は手動対応が必要です。Deschedulerはその点でユニークな存在であり、**既存の（デフォルト/カスタム）スケジューラではカバーしきれない運用中の最適化を自動化**します。例えば、大量のジョブをさばくためのスケジューラ（例：Volcanoなど）を使っていても、ジョブ完了後のリソース分散にはDeschedulerを組み合わせる、といった使い方も可能です。  
  要件によってはスケジューリング段階で解決できる問題（初期配置のポリシー）はカスタムスケジューラやスケジューラ拡張(Plugin)で対処し、**運用中に発生する問題はDeschedulerで対処**する、といった使い分けが考えられます。

- **オーバーヘッドと注意点**: DeschedulerはPodのエビクトという**破壊的アクション**を伴うため、導入には慎重な調整が必要です。標準スケジューラや多くのカスタムスケジューラは基本的に**スケジューリング先の決定のみ**を行い既存Podを壊すことはしませんが、Deschedulerは設定によっては多数のPodを動かす可能性があります。そのため、頻度や対象を絞り込みつつ、必要に応じて**PodDisruptionBudgetや優先度設定**で影響度をコントロールしてください ([Descheduler for KubernetesでPod(レプリカ)の再スケジュールを促す #AWS - Qiita](https://qiita.com/Takagi_/items/2c702557b3438ae9b46f#:~:text=%E6%B0%97%E3%82%92%E4%BB%98%E3%81%91%E3%81%9F%E3%81%84%E3%83%9D%E3%82%A4%E3%83%B3%E3%83%88))。適切に使えばDeschedulerはクラスターを常にベストエフォートな状態に保つ強力なツールですが、乱用するとかえって不安定になる恐れもあります。

---

**まとめ**: Kubernetes Deschedulerは、Kubernetes 1.30+の環境においてクラスターの効率化と安定性向上に寄与する便利なコンポーネントです。標準スケジューラでは解決しきれない**「配置後」の最適化**を自動化し、リソースの偏り解消やポリシー遵守、分散配置の維持など様々なユースケースで活用できます。 ([descheduler/charts/descheduler/README.md at master · kubernetes-sigs/descheduler · GitHub](https://github.com/kubernetes-sigs/descheduler/blob/master/charts/descheduler/README.md#:~:text=Descheduler%20for%20Kubernetes)) ([Descheduler GA in OpenShift 4.7](https://www.redhat.com/en/blog/descheduler-ga-in-openshift-4.7#:~:text=However%2C%20one%20limitation%20of%20the,the%20cluster%20against%20their%20nodes))導入はHelmチャートや公式マニフェストを用いることで比較的容易に行え、ポリシーもYAMLで柔軟にカスタマイズ可能です。是非、ご自身のクラスタで試してみて、効果を検証してみてください。適切な設定のDeschedulerにより、クラスター運用の手間を減らしつつ健全なリソース配分を自動で維持できるようになるでしょう。

次の記事では、Karpenterとの組合せたときのメリットなどを説明します。

https://qiita.com/reoring/items/0c861e33b4a1061ee0d7