descheduler@ハードウェアリソース管理系¶
はじめに¶
本サイトにつきまして、以下をご認識のほど宜しくお願いいたします。
01. descheduler¶
アーキテクチャ¶
deschedulerは、ポリシーに応じて不適切なNodeからPodを退避させる。
その後、kube-schedulerがより適切なNodeにPodを再スケジューリングさせる。
$ kubectl get events -n foo
# deschedulerがPodを退避させる
35m Normal LowNodeUtilization pod/foo-5c844554c5-6nk2r pod evicted from ip-*-*-*-*.ap-northeast-1.compute.internal node by sigs.k8s.io/descheduler
35m Normal Killing pod/foo-5c844554c5-6nk2r Stopping container foo
# kube-schedulerがPodを再スケジューリングさせる
35m Normal Scheduled pod/foo-5c844554c5-vgdjl Successfully assigned foo-5c844554c5-vgdjl to ip-*-*-*-*.ap-northeast-1.compute.internal
35m Normal Pulled pod/foo-5c844554c5-vgdjl Container image "public.ecr.aws/docker/library/foo:*.*.*" already present on machine
35m Normal Created pod/foo-5c844554c5-vgdjl Created container foo
35m Normal Started pod/foo-5c844554c5-vgdjl Started container foo
35m Normal SuccessfulCreate replicaset/foo-5c844554c5 Created pod: foo-5c844554c5-vgdjl
kube-schedulerだけでは足りない理由¶
Nodeのハードウェアリソースの消費量が動的に高まった場合に、kube-schedulerは不適切なNodeからPodを退避し、別のNodeにこれを再スケジューリングさせられない。
他にNodeが障害が起こり、他のNodeにPodが退避した場合に、その後Nodeが復旧したとしても、Podが元のNodeに戻ることはない。
kubectl rollout restart
コマンドを実行しても良いが、deschedulerを使用すればこれを自動化できる。
deschedulerをCronJobとして定期的に起動させ、Podを自動的に退避させる。
このことからもわかるように、障害復旧後すぐにdeschedulerが起動するわけではなく、CronJobの実行を待つ必要がある。
01-02¶
マニフェストの種類¶
deschedulerは、Job (descheduler) 、ConfigMapなどのマニフェストから構成されている。
Job¶
ここでは、CronJob配下で定義したとする。
Deschedulerの実行頻度が高すぎると可用性が低下するため、システムの特徴に合わせて実行頻度を設定する。
例えば、深夜帯に利用者が少なくなるのであれば、毎日深夜に1
回だけ実行する。
apiVersion: batch/v1
kind: CronJob
metadata:
labels:
app.kubernetes.io/name: descheduler
name: descheduler
namespace: descheduler
spec:
# 毎日 00:00 (JST) にdeschedulerを実行する
# AWS EKSはUTCでタイムゾーンを設定しているため、9時間分ずらす必要がある
schedule: "0 15 * * *"
# その他の例
# 12:00 と 24:00 (JST) にdeschedulerを実行する
# schedule: "0 3,15 * * *"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 1
failedJobsHistoryLimit: 1
jobTemplate:
spec:
template:
metadata:
annotations:
# ConfigMapの変更に応じて、Jobを更新する。
checksum/configmap: *****
labels:
app.kubernetes.io/name: descheduler
name: descheduler
spec:
containers:
- name: descheduler
image: registry.k8s.io/descheduler/descheduler:latest
command:
- /bin/descheduler
args:
- '--policy-config-file'
- /policy-dir/policy.yaml
- '--v'
- '3'
volumeMounts:
- mountPath: /policy-dir
name: policy-volume
# ポリシーの設定ファイルを読み込む
volumes:
- configMap:
name: descheduler
name: policy-volume
ConfigMap¶
DeschedulerPolicyのマニフェストを設定する。
apiVersion: v1
kind: ConfigMap
metadata:
labels:
app.kubernetes.io/name: descheduler
name: descheduler
namespace: descheduler
data:
policy.yaml: |
apiVersion: "descheduler/v1alpha1"
kind: "DeschedulerPolicy"
evictLocalStoragePods: "true"
strategies:
HighNodeUtilization:
enabled: "true"
LowNodeUtilization:
enabled: "true"
params:
nodeResourceUtilizationThresholds:
targetThresholds:
cpu: 50
memory: 50
pods: 50
thresholds:
cpu: 20
memory: 20
pods: 20
PodLifeTime:
enabled: "true"
RemoveDuplicates:
enabled: "true"
RemoveFailedPods:
enabled: "true"
RemovePodsHavingTooManyRestarts:
enabled: "true"
RemovePodsViolatingInterPodAntiAffinity:
enabled: "true"
RemovePodsViolatingNodeAffinity:
enabled: "true"
params:
nodeAffinityType:
- requiredDuringSchedulingIgnoredDuringExecution
RemovePodsViolatingNodeTaints:
enabled: "true"
RemovePodsViolatingTopologySpreadConstraint:
enabled: "true"
02. DeschedulerPolicy¶
DeschedulerPolicyとは¶
退避の対象とするPodの選定ルールを設定する。
DeschedulerPolicy¶
▼ LowNodeUtilization¶
Nodeのハードウェアリソース使用量 (例:CPU、メモリなど) やPod数が指定したターゲット閾値 (targetThresholds) を超過した場合に、このNode上のPodを退避させる。
さらに、kube-schedulerを使用して、使用量が閾値 (thresholds) を超過していないNodeにPodをスケジューリングさせる。
注意点として、ターゲット閾値と閾値が近いと、Node間でPodが退避 (descheduler) と再スケジューリング (kube-scheduler) を繰り返す状態になってしまう。
Nodeのハードウェアリソース使用量とPod数がターゲット閾値と閾値の間にある場合、つまりターゲット閾値を超過するNodeが存在せず、閾値よりも低いNodeが存在しない場合、deschedulerは何もしない。
apiVersion: descheduler/v1alpha1
kind: DeschedulerPolicy
strategies:
LowNodeUtilization:
enabled: "true"
params:
nodeResourceUtilizationThresholds:
# ターゲット閾値 (この値を超過したNodeからPodを退避させる)
targetThresholds:
cpu: 70
memory: 70
pods: 70
# 閾値 (kube-schedulerを使用して、この値を超過していないNodeにPodを再スケジューリングさせる)
thresholds:
cpu: 20
memory: 20
pods: 20
▼ RemoveDuplicates¶
Workload (例:Deployment、DaemonSet、StatefulSet、Jobなど) の配下にあるPodが同じNode上でスケーリングされている場合に、このPodをNodeから退避させる。
該当するNodeがない場合、退避させない。
apiVersion: descheduler/v1alpha1
kind: DeschedulerPolicy
strategies:
RemoveDuplicates:
enabled: "true"
▼ RemoveFailed¶
Failed
ステータスなPodはそのままでは削除されない。
そのため、Failed
ステータスなPodがある場合は、このPodをNodeから削除する。
apiVersion: descheduler/v1alpha1
kind: DeschedulerPolicy
strategies:
RemoveFailedPods:
enabled: "true"
params:
failedPods:
minPodLifetimeSeconds: 3600
# Failedステータスになった理由でフィルタリングする
reasons:
- NodeAffinity
includingInitContainers: "true"
▼ RemovePodsHavingTooManyRestarts¶
再起動を繰り返しているPodがある場合に、このPodをNodeから退避させる。
再起動の回数の閾値を設定できる。
apiVersion: descheduler/v1alpha1
kind: DeschedulerPolicy
strategies:
RemovePodsHavingTooManyRestarts:
enabled: "true"
params:
podsHavingTooManyRestarts:
podRestartThreshold: 100
includingInitContainers: "true"
▼ RemovePodsViolatingNodeAffinity¶
.spec.nodeAffinity
キーの設定に違反しているPodがある場合に、このPodをNodeから退避させる。
apiVersion: descheduler/v1alpha1
kind: DeschedulerPolicy
strategies:
RemovePodsViolatingNodeAffinity:
enabled: "true"
▼ RemovePodsViolatingInterPodAntiAffinity¶
.spec.affinity.podAffinity
キーの設定に違反しているPodがある場合に、このPodをNodeから退避させる。
apiVersion: descheduler/v1alpha1
kind: DeschedulerPolicy
strategies:
RemovePodsViolatingInterPodAntiAffinity:
enabled: "true"
▼ RemovePodsViolatingNodeTaints¶
taintsの設定に違反しているPodがある場合に、このPodをNodeから退避させる。
▼ RemovePodsViolatingTopologySpreadConstraint¶
TopologySpreadConstraintsの設定に違反しているPodがある場合に、このPodをNodeから退避させる。
apiVersion: descheduler/v1alpha1
kind: DeschedulerPolicy
strategies:
RemovePodsViolatingTopologySpreadConstraint:
enabled: "true"
params:
podsHavingTooManyRestarts:
podRestartThreshold: 100
includingInitContainers: "true"
グローバルオプション¶
▼ nodeFit¶
Podを退避させる前に、他のNodeがPodを再スケジューリングできる条件 (nodeSelector、tolerations、nodeAffinityなど) であるかを検証する。