はじめに
OpenShiftやKubernetesではスケジューラーがどのノードにPodを配置するか決定します。複数ノードに分散配置されることが望ましいですが、単純にデプロイした場合、すべてのPodが1ノードに配置されることもあります。この記事では「トポロジー分散制約」と「Deschedulearを使用したPodのエビクト」を試します。
環境やアプリケーションについては以下の記事を参照ください。
■ OpenShift環境
■ Spring Bootアプリケーション
#1. トポロジー分散制約
ラベル「topology.kubernetes.io/zone」が異なるノードにPodが分散してスケジュールされるように、マニフェストに「topologySpreadConstraints」を追加してデプロイしました。workerノード0~2に1Podずつスケジュールされたことを確認できます。
oc get nodes
NAME STATUS ROLES AGE VERSION
master-0 Ready master 14d v1.21.1+051ac4f
master-1 Ready master 14d v1.21.1+051ac4f
master-2 Ready master 14d v1.21.1+051ac4f
worker-0 Ready worker 14d v1.21.1+051ac4f
worker-1 Ready worker 14d v1.21.1+051ac4f
worker-2 Ready worker 14d v1.21.1+051ac4f
oc label node worker-0 topology.kubernetes.io/zone=tok0
oc label node worker-1 topology.kubernetes.io/zone=tok1
oc label node worker-2 topology.kubernetes.io/zone=tok2
oc apply -f spring-liberty.yaml
oc get pod -o wide
### 標準出力↓
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
spring-liberty-85469f6ffd-7j6gq 1/1 Running 0 24s 10.128.3.165 worker-0 <none> <none>
spring-liberty-85469f6ffd-c6sms 1/1 Running 0 24s 10.129.2.60 worker-1 <none> <none>
spring-liberty-85469f6ffd-fl67k 1/1 Running 0 24s 10.131.0.34 worker-2 <none> <none>
apiVersion: apps/v1
kind: Deployment
metadata:
name: spring-liberty
labels:
app: spring-liberty
spec:
replicas: 3
selector:
matchLabels:
app: spring-liberty
template:
metadata:
labels:
app: spring-liberty
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app: spring-liberty
containers:
- name: spring-liberty
image: image-registry.openshift-image-registry.svc:5000/spring-liberty/spring-liberty
ports:
- containerPort: 9080
readinessProbe:
httpGet:
path: /healthz
port: 9080
また、レプリカ数を3~6に変更したとき、各ノードのPod数は下表のようになりました。
maxSkewで指定したPod数の最大差『1』でスケジュールされています。
レプリカ数 | ノード worker-0 |
ノード worker-1 |
ノード worker-2 |
---|---|---|---|
3 | 1 | 1 | 1 |
4 | 1 | 2 | 1 |
5 | 1 | 2 | 2 |
6 | 2 | 2 | 2 |
oc scale --replicas=<レプリカ数> deploy/spring-liberty
#2. Kube DeschedulerオペレーターによるPodのエビクト
「Kube Descheduler」オペレーターにより、ポリシーに違反するPodが削除(エビクト)されることを確認します。削除後、Podがどのノードに作成されるかはスケジューラーが決定します。
##2.1. ノード停止後の挙動確認
ノード「worker-2」停止後、同ノードのスタータスは『NotReady』になりました。また、worker-2のPod「spring-liberty-85469f6ffd-fl67k」は終了中となり、worker-1にPod「spring-liberty-85469f6ffd-fl67k」が作成されました。マニフェストに記載したレプリカ数『3』を維持しようとしていることが分かります。
oc get nodes
### 標準出力↓
NAME STATUS ROLES AGE VERSION
master-0 Ready master 1d v1.21.1+051ac4f
master-1 Ready master 1d v1.21.1+051ac4f
master-2 Ready master 1d v1.21.1+051ac4f
worker-0 Ready worker 1d v1.21.1+051ac4f
worker-1 Ready worker 1d v1.21.1+051ac4f
worker-2 NotReady worker 1d v1.21.1+051ac4f
oc get pod -o wide
### 標準出力↓
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
spring-liberty-85469f6ffd-4d9d9 1/1 Running 0 116s 10.129.2.64 worker-1 <none> <none>
spring-liberty-85469f6ffd-7j6gq 1/1 Running 0 8m36s 10.128.3.165 worker-0 <none> <none>
spring-liberty-85469f6ffd-c6sms 1/1 Running 0 8m36s 10.129.2.60 worker-1 <none> <none>
spring-liberty-85469f6ffd-fl67k 1/1 Terminating 0 8m36s 10.131.0.34 worker-2 <none> <none>
##2.2. ノード起動後の挙動確認
ノード「worker-2」起動後、同ノードのスタータスは『Ready』になりました。worker-2のPod「spring-liberty-85469f6ffd-fl67k」の終了処理は完了しましたが、Podが再作成されることはありません。
oc get nodes
### 標準出力↓
NAME STATUS ROLES AGE VERSION
master-0 Ready master 1d v1.21.1+051ac4f
master-1 Ready master 1d v1.21.1+051ac4f
master-2 Ready master 1d v1.21.1+051ac4f
worker-0 Ready worker 1d v1.21.1+051ac4f
worker-1 Ready worker 1d v1.21.1+051ac4f
worker-2 Ready worker 1d v1.21.1+051ac4f
oc get pod -o wide
### 標準出力↓
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
spring-liberty-85469f6ffd-4d9d9 1/1 Running 0 7m40s 10.129.2.64 worker-1 <none> <none>
spring-liberty-85469f6ffd-7j6gq 1/1 Running 0 14m 10.128.3.165 worker-0 <none> <none>
spring-liberty-85469f6ffd-c6sms 1/1 Running 0 14m 10.129.2.60 worker-1 <none> <none>
##2.3. KubeDeschedulerマニフェストの適用
「Kube Descheduler」オペレーターをインストールした後、「KubeDescheduler」マニフェストを適用すると、worker-1に2つ起動していたPodのうち1つが終了し、worker-2にPod「spring-liberty-85469f6ffd-pm9jw」が作成されました。結果的に各ノードに1つのPodが存在する状態になっています。
oc apply -f descheduler.yaml
oc get pod -o wide
### 標準出力↓
spring-liberty-85469f6ffd-4d9d9 1/1 Running 0 10m 10.129.2.64 worker-1 <none> <none>
spring-liberty-85469f6ffd-7j6gq 1/1 Running 0 16m 10.128.3.165 worker-0 <none> <none>
spring-liberty-85469f6ffd-pm9jw 1/1 Running 0 2m14s 10.131.0.35 worker-2 <none> <none>
「KubeDescheduler」マニフェストでは、同じノードにPodが重複する場合は削除されるように、TopologyAndDuplicatesプロファイルを有効にしています。
apiVersion: operator.openshift.io/v1
kind: KubeDescheduler
metadata:
name: cluster
namespace: openshift-kube-descheduler-operator
spec:
deschedulingIntervalSeconds: 0
logLevel: Normal
managementState: Managed
operatorLogLevel: Normal
profiles:
- TopologyAndDuplicates
##2.4. OpenShift Kube Deschedulerについて
OpenShiftの「Kube Descheduler」オペレーターは、GitHubに公開されている「Descheduler for Kubernetes」のアップストリーム版です。
The Descheduler is an upstream Kubernetes subproject owned by SIG-Scheduling. 21
「Descheduler for Kubernetes」は、「DeschedulerPolicy」をConfigMapとして作成し、同設定を元にdeschedulerコンテナを実行することでPodの削除を行う仕組みのようです。一方、OpenShiftの「Kube Descheduler」オペレーターでは、「KubeDescheduler」マニフェスト適用時に「DeschedulerPolicy」が作成されていました。
oc describe cm cluster -n openshift-kube-descheduler-operator
### 標準出力↓
Name: cluster
Namespace: openshift-kube-descheduler-operator
Labels: <none>
Annotations: <none>
Data
====
policy.yaml:
----
apiVersion: descheduler/v1alpha1
ignorePvcPods: true
kind: DeschedulerPolicy
strategies:
RemoveDuplicates:
enabled: true
params:
includeSoftConstraints: false
namespaces:
exclude:
- kube-system
- openshift-apiserver
- openshift-apiserver-operator
…
前項の例でworker-1で実行されていたPod「spring-liberty-85469f6ffd-c6sms」を削除したのは、ネームスペース『openshift-kube-descheduler-operator』のPod「cluster-69ccfc675b-6bpm2」です。下記のログが出力されていました。
"Evicted pod" pod="spring-liberty/spring-liberty-85469f6ffd-c6sms" reason="RemoveDuplicatePods"
oc get pod -n openshift-kube-descheduler-operator
### 標準出力↓
NAME READY STATUS RESTARTS AGE
cluster-69ccfc675b-6bpm2 0/1 Completed 3 63s
descheduler-operator-858465f765-kxsgj 1/1 Running 0 10m
oc logs cluster-69ccfc675b-6bpm2 -n openshift-kube-descheduler-operator
### 標準出力↓
I0826 03:18:54.636239 1 dynamic_serving_content.go:111] Loaded a new cert/key pair for "serving-cert::/certs-dir/tls.crt::/certs-dir/tls.key"
I0826 03:18:59.430209 1 dynamic_serving_content.go:130] Starting serving-cert::/certs-dir/tls.crt::/certs-dir/tls.key
I0826 03:18:59.430283 1 tlsconfig.go:200] loaded serving cert ["serving-cert::/certs-dir/tls.crt::/certs-dir/tls.key"]: "metrics.openshift-kube-descheduler-operator.svc" [ser
ving] validServingFor=[metrics.openshift-kube-descheduler-operator.svc,metrics.openshift-kube-descheduler-operator.svc.cluster.local] issuer="openshift-service-serving-signer@16285
84568" (2021-08-26 01:53:35 +0000 UTC to 2023-08-26 01:53:36 +0000 UTC (now=2021-08-26 03:18:59.430262245 +0000 UTC))
I0826 03:18:59.430471 1 named_certificates.go:53] loaded SNI cert [0/"self-signed loopback"]: "apiserver-loopback-client@1629947939" [serving] validServingFor=[apiserver-loop
back-client] issuer="apiserver-loopback-client-ca@1629947936" (2021-08-26 02:18:54 +0000 UTC to 2022-08-26 02:18:54 +0000 UTC (now=2021-08-26 03:18:59.430463658 +0000 UTC))
I0826 03:18:59.430522 1 secure_serving.go:197] Serving securely on [::]:10258
I0826 03:18:59.430612 1 tlsconfig.go:240] Starting DynamicServingCertificateController
I0826 03:18:59.537841 1 node.go:46] "Node lister returned empty list, now fetch directly"
I0826 03:18:59.629163 1 duplicates.go:99] "Processing node" node="master-0"
I0826 03:18:59.727021 1 duplicates.go:99] "Processing node" node="master-1"
I0826 03:18:59.827317 1 duplicates.go:99] "Processing node" node="master-2"
I0826 03:18:59.854129 1 duplicates.go:99] "Processing node" node="worker-0"
I0826 03:18:59.878843 1 duplicates.go:99] "Processing node" node="worker-1"
I0826 03:18:59.913138 1 duplicates.go:99] "Processing node" node="worker-2"
I0826 03:18:59.945896 1 duplicates.go:194] "Adjusting feasible nodes" owner={namespace:spring-liberty kind:ReplicaSet name:spring-liberty-85469f6ffd imagesHash:image-registry
.openshift-image-registry.svc:5000/spring-liberty/spring-liberty} from=6 to=3
I0826 03:18:59.945925 1 duplicates.go:202] "Average occurrence per node" node="worker-1" ownerKey={namespace:spring-liberty kind:ReplicaSet name:spring-liberty-85469f6ffd ima
gesHash:image-registry.openshift-image-registry.svc:5000/spring-liberty/spring-liberty} avg=1
I0826 03:18:59.967505 1 evictions.go:130] "Evicted pod" pod="spring-liberty/spring-liberty-85469f6ffd-c6sms" reason="RemoveDuplicatePods"
I0826 03:18:59.984554 1 topologyspreadconstraint.go:139] "Processing namespaces for topology spread constraints"
I0826 03:19:00.427877 1 descheduler.go:151] "Number of evicted pods" totalEvicted=1