kakakakakku blog

Weekly Tech Blog : Keep on Learning 👍

Pod に「優先度」を設定できる PriorityClass と Non-preempting 機能を試した

Kubernetes の「PriorityClass」を使うと Pod に優先度(プライオリティ)を設定できる.例えば,通常 Pod を起動するために必要なリソースを確保できない場合は Pending になるけど,そういう場合でも優先的に起動できるようになる.逆に「優先度を低くした待機用 Pod」を使ってノードを多めに起動しておく「オーバープロビジョニング」という活用法にも繋がる.今回は「PriorityClass」を試していく.

kubernetes.io

検証環境

今回は Docker Desktop for MacKubernetes 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.yamldeployment-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 は削除せず」スケジューリング待ちの中で優先度を高くする.さっそく試していく.

kubernetes.io

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.yamlpriorityClassNamehigh-priority-nonpreempting に変えて,同じように deployment-row.yamldeployment-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 を宣言できることも確認した.覚えておこう!