Kubernetes Descheduler は、クラスター内のPod配置を再評価して不要なPodをエビクト(削除)することで再スケジューリングを促すコンポーネントです。デフォルトのスケジューラ(kube-scheduler)はPod作成時にしかスケジューリングしませんが、Deschedulerは既存のPodを定期的にチェックして適切でない配置のPodを退去させ、再配置を促す役割を担います (Descheduler GA in OpenShift 4.7) (Kubernetes: Kubernetes Descheduler とは #kubernetes - Qiita)。Descheduler自身はエビクトのみを行い、削除されたPodの再スケジューリング自体は通常のスケジューラ(デフォルトまたは指定されたカスタムスケジューラ)が行います (Kubernetes: Kubernetes Descheduler とは #kubernetes - Qiita)。以下では、Deschedulerの目的と仕組み、導入方法、主要なユースケース、および標準スケジューラや他のカスタムスケジューラとの比較について説明します。
Deschedulerとは何か?目的と動作原理
DeschedulerはKubernetesのサブプロジェクト(SIG-Scheduling 管轄)であり、既存のPodの配置を見直してクラスターのバランス改善やポリシー順守を図るためのツールです (Descheduler GA in OpenShift 4.7)。KubernetesのスケジューラはPod生成時に最適なノードを選択しますが、一度Podがノードに割り当てられると、その後ノード状況が変化しても自動で再評価・移動することはありません (Descheduler GA in OpenShift 4.7) (Kubernetes: Kubernetes Descheduler とは #kubernetes - Qiita)。例えば、時間の経過とともに:
- あるノードだけリソース使用率が高く偏ってしまう
- Podスケジューリング後にノードのラベルやタaintsが変更されても、既存のPodには反映されない
- 新しいノードが追加されても、既存のPodは自動ではそのノードに分散されない
といった問題が発生しがちです (Kubernetes: Kubernetes Descheduler とは #kubernetes - Qiita)。これらはクラスターの長期運用で典型的な課題で、結果としてリソースの不均衡やポリシー違反状態が放置される可能性があります。
Deschedulerの目的は、このような変更後の最適でない状態を是正することにあります。Deschedulerは定期的にクラスター内の全Podとノード状態を評価し、あらかじめ定義したポリシー(ストラテジー)に基づいて「現在のノードより他のノードに配置した方が良い」と判断されるPodを抽出します (Descheduler GA in OpenShift 4.7)。該当Podに対してKubernetesのエビクト(Eviction API)を用いて削除を行い(Podを削除することでDeploymentやReplicaSetが自動的に代替Podを再作成します)、その新規Podは通常どおりスケジューラによってより適切なノードにスケジューリングされます (descheduler/charts/descheduler/README.md at master · kubernetes-sigs/descheduler · GitHub) (Kubernetes: Kubernetes Descheduler とは #kubernetes - Qiita)。このように、Deschedulerは**既存Podの「デスケジューリング」**を行うことで結果的にPodの再スケジューリングを発生させ、クラスターの状態を改善します。
動作原理としては、Deschedulerは内部でプラグイン化された複数の「ストラテジー(Strategy)」を用いてポリシー違反や最適ではないPodを判定します (Descheduler GA in OpenShift 4.7)。各ストラテジーは特定のチェック項目を持ち(例: ノードの利用率、PodのAffinity/Anti-Affinity違反、トポロジースプレッド違反など)、条件に合致するPodを見つけた場合にそのPodをエビクト対象とします。実際のエビクトでは、kubectl delete pod
と同様の操作が行われますが、PodDisruptionBudget(PDB) が設定されている場合はそれを考慮して安全に実行されます(PDBを満たさないエビクトはブロックされます)。Descheduler自体はスケジューリングを行わないため、既存のスケジューラと補完的に動作します (Descheduler GA in OpenShift 4.7)。
どのような状況でDeschedulerを使用すべきか?
Deschedulerは、クラスター稼働中の状態変化によりPod配置の見直しが必要な状況で力を発揮します。具体的には以下のようなケースで利用を検討できます。
- ノード間のリソース利用率の偏り: 時間の経過やワークロードの変化で、一部のノードにCPUやメモリ負荷が集中し他が遊休状態になることがあります。Deschedulerのリソース利用率ベースのストラテジーを使えば、過負荷ノード上のPodを他ノードへ移動させて負荷分散が可能です (Kubernetes: Kubernetes Descheduler とは #kubernetes - Qiita)。
-
ノードの追加・削除(スケールアウト/イン): 新しいノードをクラスターに追加した場合、既存のDeployment/ReplicaSet管理下のPodは自動ではそのノードに移動しません(DaemonSetとは異なります)。障害対応でノードを入れ替えた場合も同様です。このような時、Deschedulerを使って既存Podを一旦エビクトすることで、新ノードを含めPodを再分散させることができます (Descheduler for KubernetesでPod(レプリカ)の再スケジュールを促す #AWS - Qiita)。手動で
kubectl delete pod
する手間を省き、自動で均等化できます。 -
ノードの状態変化によるポリシー不整合: Podスケジューリング後にノードに変更が起きた場合(例:ノードに新たなラベル付与やタイント追加、他Podの配置状況変化など)、当初のスケジューリング条件を満たさない状態になることがあります。DeschedulerはPodのAffinity/Anti-AffinityやTaints/Tolerations、Topology Spread Constraintsの違反を検知して該当Podをエビクトできます (Descheduler for KubernetesでPod(レプリカ)の再スケジュールを促す #AWS - Qiita)。例えば、
requiredDuringSchedulingIgnoredDuringExecution
のNodeAffinityを持つPodが、後からノードのラベル変更で条件不一致となった場合にそれを退避させる、といった使い方です。 -
長期稼働Podのリフレッシュ: ペット的に長期間動き続けているPodを定期的に再配置したい場合にもDeschedulerが使えます。
PodLifeTime
ストラテジーを適用すれば、一定期間以上経過したPodを自動エビクトし、新しいPodに置き換えることで、潜在的不具合のリセットやロールリング更新に近い効果を得られます (descheduler/docs/user-guide.md at master · kubernetes-sigs/descheduler · GitHub) (descheduler/docs/user-guide.md at master · kubernetes-sigs/descheduler · GitHub)。 -
その他: CrashLoopや再起動を繰り返しているPodを対象にしたリスケジューリング(
RemovePodsHavingTooManyRestarts
)、Fail状態のPodのクリーンアップ(RemoveFailedPods
)など、細かなシナリオにも対応するストラテジーがあります (Usage of Kubernetes Descheduler - SoByte)。
以上のように、クラスター内の状態変化で初期スケジューリング時の前提が崩れた場合や、より均衡の取れた資源配分を図りたい場合にDeschedulerを使うと効果的です。逆に、クラスターが小規模であったりワークロードの変動が少ない場合、またはPod配置を頻繁に変更したくない場合には必ずしも導入する必要はありません。Deschedulerを適用する際は、アプリケーションの耐障害性にも留意しましょう。Podの再スケジューリングにより一時的に停止が発生し得るため、PodDisruptionBudgetの設定や、一度にエビクトするPod数の上限設定(maxNoOfPodsToEvictPerNode
など)で影響を緩和することが重要です (Descheduler for KubernetesでPod(レプリカ)の再スケジュールを促す #AWS - Qiita) (Usage of Kubernetes Descheduler - SoByte)。
Deschedulerの設定方法
それではDeschedulerの導入と設定方法について説明します。Kubernetes 1.30以降のクラスタであれば、Deschedulerは安定版(v0.3x系)を使用できます。Descheduler自体はデフォルトでKubernetesに組み込まれていないため、追加でデプロイする必要があります。一般的な導入手順として以下の方法があります。
Deschedulerのインストールと実行
① Helm Chartを利用する方法: 公式のHelmチャートが提供されており、簡単にCronJobとしてデプロイできます。まずHelmリポジトリを追加し、インストールコマンドを実行します(kube-system
名前空間にデプロイする例)。
# 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) (descheduler/charts/descheduler/README.md at master · kubernetes-sigs/descheduler · GitHub)。Helmのvaluesでkind
パラメータをCronJob
(デフォルト)またはDeployment
に切り替えることで、CronJobとして定期実行するかデーモン的に常駐させるかを選択可能です(Deployment利用時はdeschedulingInterval
で実行間隔を指定、デフォルト5分間隔 (descheduler/charts/descheduler/README.md at master · kubernetes-sigs/descheduler · GitHub))。多くの場合はCronJobで数分おきに実行する形が扱いやすいでしょう。
② マニフェストを直接適用する方法: kubernetes-sigs/deschedulerリポジトリには、CronJob用のマニフェストやKustomizeが用意されています。それらを利用してデプロイすることも可能です。例えば、kubectl
とkustomize
を使ってCronJobリソースをデプロイするには以下のコマンドを実行します(v0.32.0を使用する例)。
# 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)。複数のストラテジーを有効/無効にしたり、各ストラテジーの閾値や条件を設定可能です。以下に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)。例えば、システム系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)。逆に、HighNodeUtilization
戦略を使えば極端に低負荷なノード上のPodを他に移し、ノードを遊休状態にしないよう集約することも可能です(これにより特定ノードを空にできれば、Cluster Autoscalerと併用してノード縮退もできます)。これらによりクラスター全体のリソース消費を均一化し、リソースの有効活用やスケーラビリティ向上が期待できます。
2. Podの分散配置による可用性向上(レプリカの再スケジューリング)
Deployment/ReplicaSetの複数レプリカが特定ノードに固まってしまった場合の再分散にもDeschedulerが有効です。通常、kube-schedulerもスプレッド(Spread)アルゴリズムでできるだけ均等に配置しようとしますが、ノード追加直後やスケジューラの都合で一時的に偏りが出ることがあります。DeschedulerのRemoveDuplicates
戦略は、同じReplicaSet由来のPodが一つのノードに複数存在する場合にその一部をエビクトし、再スケジューラによって他ノードへ再配置させます (Kubernetes: Kubernetes Descheduler とは #kubernetes - Qiita)。結果として各ノード上のレプリカ数が均等になるため、単一ノード障害時の影響を減らしサービス可用性を高める効果があります (Descheduler for KubernetesでPod(レプリカ)の再スケジュールを促す #AWS - Qiita)。また、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)。特に複雑なAffinityルールを使っている環境やマルチテナント環境では、意図せぬ配置が発生していないか定期的にチェック・修正できる点で有用です。
4. 古いPodのリスケジューリング(Podの世代交代)
長期間再起動されていないPodを定期的に入れ替える用途にもDeschedulerが使われます。例えばPodLifeTime
戦略を有効にしておくと、指定した寿命(稼働時間)を超えたPodを自動的にエビクトできます (descheduler/docs/user-guide.md at master · kubernetes-sigs/descheduler · GitHub) (descheduler/docs/user-guide.md at master · kubernetes-sigs/descheduler · GitHub)。これにより、数日〜数週間以上動き続けているPodを強制的に再作成させてメモリリークの解消やローリングアップデートの疑似実行を行うことが可能です。特に状態を持たず再起動が比較的容易なアプリケーション(ステートレスなWebアプリケーションなど)では、定期的にPodをサイクルさせることでシステムの健全性を保つ一助となるでしょう。ただし、この機能を使う場合もPodDisruptionBudgetを設定するなどして、一度に多数のPodが消えてしまわないよう調整することが重要です。
標準スケジューラや他のカスタムスケジューラとの比較
最後に、DeschedulerをKubernetes標準のスケジューラやカスタムスケジューラと比較してその位置付けを整理します。
-
デフォルトのkube-schedulerとの関係: 上述の通り、kube-schedulerは新規Podの配置担当、Deschedulerは既存Podの再配置担当という棲み分けになります (Descheduler GA in OpenShift 4.7)。標準スケジューラはスコアリングアルゴリズム等により最適なノード選択を行いますが、一度スケジューリングされたPodのその後の管理はしません (Descheduler GA in OpenShift 4.7)。Deschedulerはまさにそのギャップを埋める補完的ツールであり、標準スケジューラでは対処できない「後からの最適化」を担います。したがって、Deschedulerを導入してもkube-scheduler自体を置き換えるものではなく、あくまで追加のコントローラとして動作します (Kubernetes: Kubernetes Descheduler とは #kubernetes - Qiita)。
-
カスタムスケジューラとの使い分け: Kubernetesではデフォルト以外にも独自のスケジューラを動かし、Podごとに
spec.schedulerName
で使い分けることが可能です(例:Batchジョブ専用のスケジューラ等) (Descheduler GA in OpenShift 4.7)。カスタムスケジューラはスケジューリングロジック自体を変更・拡張することで、特定の要件(例:先着順ではなく公平にリソースを配分する、GPUワークロード向けに特化する 等)に対応できます。しかしいずれのスケジューラもPod配置後に能動的に移動させる機能は基本持ちません。仮にカスタムスケジューラを導入しても、クラスター状況の変化に応じた再配置は手動対応が必要です。Deschedulerはその点でユニークな存在であり、既存の(デフォルト/カスタム)スケジューラではカバーしきれない運用中の最適化を自動化します。例えば、大量のジョブをさばくためのスケジューラ(例:Volcanoなど)を使っていても、ジョブ完了後のリソース分散にはDeschedulerを組み合わせる、といった使い方も可能です。
要件によってはスケジューリング段階で解決できる問題(初期配置のポリシー)はカスタムスケジューラやスケジューラ拡張(Plugin)で対処し、運用中に発生する問題はDeschedulerで対処する、といった使い分けが考えられます。 -
オーバーヘッドと注意点: DeschedulerはPodのエビクトという破壊的アクションを伴うため、導入には慎重な調整が必要です。標準スケジューラや多くのカスタムスケジューラは基本的にスケジューリング先の決定のみを行い既存Podを壊すことはしませんが、Deschedulerは設定によっては多数のPodを動かす可能性があります。そのため、頻度や対象を絞り込みつつ、必要に応じてPodDisruptionBudgetや優先度設定で影響度をコントロールしてください (Descheduler for KubernetesでPod(レプリカ)の再スケジュールを促す #AWS - Qiita)。適切に使えばDeschedulerはクラスターを常にベストエフォートな状態に保つ強力なツールですが、乱用するとかえって不安定になる恐れもあります。
まとめ: Kubernetes Deschedulerは、Kubernetes 1.30+の環境においてクラスターの効率化と安定性向上に寄与する便利なコンポーネントです。標準スケジューラでは解決しきれない**「配置後」の最適化**を自動化し、リソースの偏り解消やポリシー遵守、分散配置の維持など様々なユースケースで活用できます。 (descheduler/charts/descheduler/README.md at master · kubernetes-sigs/descheduler · GitHub) (Descheduler GA in OpenShift 4.7)導入はHelmチャートや公式マニフェストを用いることで比較的容易に行え、ポリシーもYAMLで柔軟にカスタマイズ可能です。是非、ご自身のクラスタで試してみて、効果を検証してみてください。適切な設定のDeschedulerにより、クラスター運用の手間を減らしつつ健全なリソース配分を自動で維持できるようになるでしょう。
次の記事では、Karpenterとの組合せたときのメリットなどを説明します。