Kubernetes の「PriorityClass」を使うと Pod に優先度(プライオリティ)を設定できる.例えば,通常 Pod を起動するために必要なリソースを確保できない場合は Pending
になるけど,そういう場合でも優先的に起動できるようになる.逆に「優先度を低くした待機用 Pod」を使ってノードを多めに起動しておく「オーバープロビジョニング」という活用法にも繋がる.今回は「PriorityClass」を試していく.
検証環境
今回は Docker Desktop for Mac で Kubernetes 1.19.3 を使う.検証をシンプルにするために「1 ノード」そして「メモリ 2 GB」にした.
$ kubectl describe nodes | egrep 'Capacity:|Allocatable:|memory:' Capacity: memory: 2035604Ki Allocatable: memory: 1933204Ki
「PriorityClass」設定なし
まず,以下のようなマニフェスト deployment-row.yaml
を作る.「メモリ 500 MB」を要求する Pod を3個起動する Deployment とした.
apiVersion: apps/v1 kind: Deployment metadata: name: sandbox-priority-class-row-nginx spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.19-alpine resources: requests: memory: "500Mi" ports: - containerPort: 80
マニフェストを適用すると,期待通りに Pod を起動できた.
$ kubectl apply -f deployment-row.yaml deployment.apps/sandbox-priority-class-row-nginx created $ kubectl get pods NAME READY STATUS RESTARTS AGE sandbox-priority-class-row-nginx-99fd6b465-9vhsv 1/1 Running 0 10s sandbox-priority-class-row-nginx-99fd6b465-hg9ch 1/1 Running 0 10s sandbox-priority-class-row-nginx-99fd6b465-zhv7b 1/1 Running 0 10s
ほぼ同じマニフェスト deployment-high.yaml
をもう1個作る.今回は replicas: 1
にした.
apiVersion: apps/v1 kind: Deployment metadata: name: sandbox-priority-class-high-nginx spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.19-alpine resources: requests: memory: "500Mi" ports: - containerPort: 80
同じくマニフェストを適用すると,メモリを確保することができず Pending
になった.「PriorityClass」設定なしだと,期待通りの挙動になる.2種類の Deployment を削除しておく.
$ kubectl apply -f deployment-high.yaml deployment.apps/sandbox-priority-class-high-nginx created $ kubectl get pods NAME READY STATUS RESTARTS AGE sandbox-priority-class-high-nginx-99fd6b465-5rcpm 0/1 Pending 0 10s sandbox-priority-class-row-nginx-99fd6b465-9vhsv 1/1 Running 0 2m sandbox-priority-class-row-nginx-99fd6b465-hg9ch 1/1 Running 0 2m sandbox-priority-class-row-nginx-99fd6b465-zhv7b 1/1 Running 0 2m $ kubectl delete -f deployment-high.yaml deployment.apps "sandbox-priority-class-high-nginx" deleted $ kubectl delete -f deployment-row.yaml deployment.apps "sandbox-priority-class-row-nginx" deleted
「PriorityClass」設定あり
次に「PriorityClass」を作る.まずは「優先度:高」として使う high-priority.yaml
を作る.値は 1000000
にした.値は「10億以下の整数値」を指定できて,大きいほど優先度が高くなる.今回はドキュメントにも載っている数値をそのまま使った.
apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: high-priority value: 1000000 globalDefault: false
もう1個「優先度 : 低」として使う row-priority.yaml
を作る.値は -1
にした.
apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: row-priority value: -1 globalDefault: false
マニフェストを適用しておく.
$ kubectl apply -f high-priority.yaml priorityclass.scheduling.k8s.io/high-priority created $ kubectl apply -f row-priority.yaml priorityclass.scheduling.k8s.io/row-priority created
次に Deployment に priorityClassName
の指定を追加する.deployment-row.yaml
は「優先度 : 低」の Pod にする.
apiVersion: apps/v1 kind: Deployment metadata: name: sandbox-priority-class-row-nginx spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.19-alpine resources: requests: memory: "500Mi" ports: - containerPort: 80 priorityClassName: row-priority
deployment-high.yaml
は「優先度:高」の Pod にする.検証をする準備は整った.
apiVersion: apps/v1 kind: Deployment metadata: name: sandbox-priority-class-high-nginx spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.19-alpine resources: requests: memory: "500Mi" ports: - containerPort: 80 priorityClassName: high-priority
さっそくマニフェストを適用する.順番はさっきと同じく deployment-row.yaml
➔ deployment-high.yaml
にする.ポイントは deployment-high.yaml
を適用したときに既に起動していた sandbox-priority-class-row-nginx-65dbdbc8f4-bcxk5
が自動的に止まり,代わりに「優先度:高」の sandbox-priority-class-high-nginx-868895ff4d-tz7cr
が起動した.期待通りに動かせた!
$ kubectl apply -f deployment-row.yaml deployment.apps/sandbox-priority-class-row-nginx created $ kubectl get pods NAME READY STATUS RESTARTS AGE sandbox-priority-class-row-nginx-65dbdbc8f4-5gzkb 1/1 Running 0 30s sandbox-priority-class-row-nginx-65dbdbc8f4-bcxk5 1/1 Running 0 30s sandbox-priority-class-row-nginx-65dbdbc8f4-jnxj9 1/1 Running 0 30s $ kubectl apply -f deployment-high.yaml deployment.apps/sandbox-priority-class-high-nginx created $ kubectl get pods NAME READY STATUS RESTARTS AGE sandbox-priority-class-high-nginx-868895ff4d-tz7cr 1/1 Running 0 20s sandbox-priority-class-row-nginx-65dbdbc8f4-5gzkb 1/1 Running 0 2m sandbox-priority-class-row-nginx-65dbdbc8f4-87q8r 0/1 Pending 0 20s sandbox-priority-class-row-nginx-65dbdbc8f4-jnxj9 1/1 Running 0 2m
また2種類の Deployment を削除しておく.
$ kubectl delete -f deployment-high.yaml deployment.apps "sandbox-priority-class-high-nginx" deleted $ kubectl delete -f deployment-row.yaml deployment.apps "sandbox-priority-class-row-nginx" deleted
Non-preempting 機能 : プリエンプトしない(削除しない)
Feature Gates を確認すると NonPreemptingPriority
という機能が Kubernetes 1.19 に Beta としてデフォルトで使えるようになっている.「プリエンプト」とは「Pod を削除すること」を意味していて,簡単に言えば「PriorityClass」を使っても「実行中の Pod は削除せず」スケジューリング待ちの中で優先度を高くする.さっそく試していく.
high-priority.yaml
をベースに新しく high-priority-nonpreempting.yaml
を作る.1箇所 preemptionPolicy: Never
を追加した.これで「プリエンプトしない」ことを宣言できる.
apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: high-priority-nonpreempting value: 1000000 preemptionPolicy: Never globalDefault: false
次に deployment-high.yaml
の priorityClassName
を high-priority-nonpreempting
に変えて,同じように deployment-row.yaml
➔ deployment-high.yaml
の順番でマニフェストを適用する.
apiVersion: apps/v1 kind: Deployment metadata: name: sandbox-priority-class-high-nginx spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.19-alpine resources: requests: memory: "500Mi" ports: - containerPort: 80 priorityClassName: high-priority
結果としては「PriorityClass」設定なしと同じになる.他にもスケジューリング待ちの Pod があれば,効果が出てくる.
$ kubectl apply -f deployment-row.yaml deployment.apps/sandbox-priority-class-row-nginx created $ kubectl get pods NAME READY STATUS RESTARTS AGE sandbox-priority-class-row-nginx-65dbdbc8f4-8vh5d 1/1 Running 0 10s sandbox-priority-class-row-nginx-65dbdbc8f4-dbgxr 1/1 Running 0 10s sandbox-priority-class-row-nginx-65dbdbc8f4-srd7c 1/1 Running 0 10s $ kubectl apply -f deployment-high.yaml deployment.apps/sandbox-priority-class-high-nginx created $ kubectl get pods NAME READY STATUS RESTARTS AGE sandbox-priority-class-high-nginx-5dbccfd9f-s8trp 0/1 Pending 0 10s sandbox-priority-class-row-nginx-65dbdbc8f4-8vh5d 1/1 Running 0 40s sandbox-priority-class-row-nginx-65dbdbc8f4-dbgxr 1/1 Running 0 40s sandbox-priority-class-row-nginx-65dbdbc8f4-srd7c 1/1 Running 0 40s
ドキュメントを読むと「Non-preempting 機能」のユースケースとして「データサイエンス」の例が載っていた.処理中の計算は無駄にせず継続しながら,その後は優先度を適用していく.良さそう!
An example use case is for data science workloads. A user may submit a job that they want to be prioritized above other workloads, but do not wish to discard existing work by preempting running pods.
まとめ
Kubernetes の「PriorityClass」を使って Pod に優先度(プライオリティ)を設定できることを確認した.また preemptionPolicy
を指定して「プリエンプトしない」PriorityClass を宣言できることも確認した.覚えておこう!