Upgrade to Pro — share decks privately, control downloads, hide ads and more …

「詰める」と「散らす」の動力学 - 原理・原則から理解するコンテナ配置戦略 #openshiftjp / OpenShift Run 2019

y_taka_23
December 20, 2019

「詰める」と「散らす」の動力学 - 原理・原則から理解するコンテナ配置戦略 #openshiftjp / OpenShift Run 2019

OpenShift.Run 2019 で使用したスライドです。

Kubernetes において Deployment の作成から Pod の起動に至る流れは隠蔽されており、通常エンドユーザは Pod がどの Node に配置されるのかを気にする必要はありません。しかし、運用がある程度の規模になると、CPU やメモリなどクラスタが持っているリソースを効果的に使い切り、さらに障害時にサービスが停止しないようにするためには、Pod の配置にまで気を配る必要があります。

Pod をどの Node に配置するかの判断をスケジューリングと呼びます。本講演では Kubernetes のスケジューリングの仕組みと、それを運用する上で現実的に生じる課題、さらにその対策までをまとめて包括的に解説しました。

イベント概要:https://openshift.connpass.com/event/151473/
ブログ記事:https://ccvanishing.hateblo.jp/entry/2019/12/21/212423

なお、本講演のストーリーは CloudNative Days Tokyo 2019 での内容が元になっており、そこに 2019 年 7 月から半年間で実装された新機能などの解説を追加して再構成してあります。

CloudNative Days Tokyo 2019:https://speakerdeck.com/ytaka23/cloudnative-days-tokyo-2019

y_taka_23

December 20, 2019
Tweet

More Decks by y_taka_23

Other Decks in Technology

Transcript

  1. #openshiftjp $ kubectl apply -f my-deployment.yaml deployment.apps/myapp created $ kubectl

    get pods -o wide NAME READY STATUS RESTARTS AGE NODE myapp-6dd86d77d-vweg2 1/1 Running 0 52s node-03 myapp-6dd86d77d-wt34h 1/1 Running 0 52s node-01 myapp-6dd86d77d-r4pag 1/1 Running 0 52s node-02
  2. #openshiftjp $ kubectl apply -f my-deployment.yaml deployment.apps/myapp created $ kubectl

    get pods -o wide NAME READY STATUS RESTARTS AGE NODE myapp-6dd86d77d-vweg2 1/1 Running 0 52s node-03 myapp-6dd86d77d-wt34h 1/1 Running 0 52s node-01 myapp-6dd86d77d-r4pag 1/1 Running 0 52s node-02 配置される Node が「よしなに」決まる
  3. #openshiftjp #openshiftjp コンテナを「詰める」力学 • メリット:コストの抑制 ◦ 出来るだけ多くの Pod を Node

    に配置する ◦ リソース(CPU、Memory)を使い切ることを目指す • デメリット:サービスの可用性低下 ◦ Node の障害時に Pod がまとめて巻き込まれる ◦ Pod に比べて Node の起動は遅く、ロードスパイクに弱い
  4. #openshiftjp #openshiftjp コンテナを「散らす」力学 • メリット:サービスの可用性向上 ◦ 出来るだけ Pod を分散して配置する ◦

    ひとつの Node が障害されてもサービス全体は停止しない • デメリット:コストの上昇 ◦ 必然的に準備しておく Node の個数が増える ◦ リソースの断片化により Node の性能を使いきれない
  5. #openshiftjp #openshiftjp コンテナ配置は自分事 • 結局のところ「戦略」が必須 ◦ どちらかに全振りすると運用が廻らずに死ぬ ◦ クラスタにデプロイするアプリの性質にも依存 •

    戦略を考えるには「仕組み」への理解が必須 ◦ ブラックボックスは狙ってコントロールできない ◦ 何ができるか・できないのかを知っておく必要性
  6. #openshiftjp ユーザが kubectl コマンドで Deployment を作成 Contoller Manager が Deployment

    から ReplicaSet を作成 Controller Manager が ReplicaSet から Pod を作成 Scheduler が Pod を配置する Node を選択 Node 上の Kubelet が自分に割り当てられた Pod を起動
  7. #openshiftjp ユーザが kubectl コマンドで Deployment を作成 Contoller Manager が Deployment

    から ReplicaSet を作成 Controller Manager が ReplicaSet から Pod を作成 Scheduler が Pod を配置する Node を選択 Node 上の Kubelet が自分に割り当てられた Pod を起動
  8. #openshiftjp Dequeue Filtering Scoring Node が未定の Pod を一つ選択 Pod の条件に合わない

    Node を除外する 残った Node から ベストを選ぶ Scheduling Cycle
  9. #openshiftjp #openshiftjp スケジューラの基本動作 • Pod と Node の紐付けのみを担当 ◦ 自分自身が

    Pod を作成するわけではない • Pod ひとつずつに対し以下を繰り返す ◦ キューから配置 Node が未定の Pod を取り出す ◦ Pod の条件から Node の候補を絞る ◦ 残った中からさらに最適な Node を選択する
  10. #openshiftjp apiVersion: v1 kind: Pod metadata: name: my-app spec: containers:

    - name: my-app image: username/my-app:latest resources: requests: memory: 2Gi cpu: 200m Mem : 2 GiB CPU : 0.2 core
  11. #openshiftjp apiVersion: v1 kind: Pod metadata: name: my-app spec: containers:

    - name: my-app image: username/my-app:latest resources: requests: memory: 2Gi cpu: 200m Mem : 2 GiB CPU : 0.2 core メモリ 2 GiB と CPU 200 mcore 確保できる Node に配置してくれ
  12. #openshiftjp Mem : 1 GiB CPU : 0.2 core Mem

    : 2 GiB CPU : 0.2 core Mem : 2 GiB CPU : 0.2 core Mem : 4 / 8 GiB CPU : 0.4 / 2 core Mem : 3 GiB CPU : 0.2 core Mem : 4 MiB CPU : 0.2 core Mem : 7 / 8 GiB CPU : 0.4 / 2 core Mem : 1 GiB CPU : 0.2 core Mem : 2 / 8 GiB CPU : 0.4 / 2 core Mem : 2 GiB CPU : 0.2 core
  13. #openshiftjp Mem : 1 GiB CPU : 0.2 core Mem

    : 2 GiB CPU : 0.2 core Mem : 2 GiB CPU : 0.2 core Mem : 4 / 8 GiB CPU : 0.4 / 2 core Mem : 3 GiB CPU : 0.2 core Mem : 4 MiB CPU : 0.2 core Mem : 7 / 8 GiB CPU : 0.4 / 2 core Mem : 1 GiB CPU : 0.2 core Mem : 2 / 8 GiB CPU : 0.4 / 2 core Mem : 2 GiB CPU : 0.2 core Pod の条件に合わない Node を除外する Mem 不足で除外
  14. #openshiftjp Mem : 1 GiB CPU : 0.2 core Mem

    : 2 GiB CPU : 0.2 core Mem : 2 GiB CPU : 0.2 core Mem : 4 / 8 GiB CPU : 0.4 / 2 core Mem : 1 GiB CPU : 0.2 core Mem : 2 / 8 GiB CPU : 0.4 / 2 core Mem : 2 GiB CPU : 0.2 core 残った Node の中から ベストを選ぶ より余裕がある Mem : 3 GiB CPU : 0.2 core Mem : 4 MiB CPU : 0.2 core Mem : 7 / 8 GiB CPU : 0.4 / 2 core
  15. #openshiftjp Mem : 1 GiB CPU : 0.2 core Mem

    : 2 GiB CPU : 0.2 core Mem : 2 GiB CPU : 0.2 core Mem : 4 / 8 GiB CPU : 0.4 / 2 core Mem : 3 GiB CPU : 0.2 core Mem : 4 MiB CPU : 0.2 core Mem : 7 / 8 GiB CPU : 0.4 / 2 core Mem : 1 GiB CPU : 0.2 core Mem : 4 / 8 GiB CPU : 0.6 / 2 core Mem : 2 GiB CPU : 0.2 core
  16. #openshiftjp #openshiftjp スケジューラの設定 • スケジューラ起動時に --config フラグを指定 ◦ 冗長化などの設定も含まれる ◦

    さらに ConfigMap 化しておいた Policy を参照 • Policy は用意された項目を組み合わせる ◦ Node を Filtering する条件 ◦ Scoring の順位付け関数と重み付け
  17. #openshiftjp { "kind": "Policy", "apiVersion": "v1", "predicates": [ {"name": "PodFitsHostPorts"},

    {"name": "PodFitsHostResources"}, ... ], "priorities": [ {"name": "LeastRequestedPriority", "weight": 1}, {"name": "ServiceSpreadingPriority", "weight": 1}, ... ] } policy.cfg
  18. #openshiftjp { "kind": "Policy", "apiVersion": "v1", "predicates": [ {"name": "PodFitsHostPorts"},

    {"name": "PodFitsHostResources"}, ... ], "priorities": [ {"name": "LeastRequestedPriority", "weight": 1}, {"name": "ServiceSpreadingPriority", "weight": 1}, ... ] } policy.cfg 確保済みリソースが少ない Node を優先 = 散らす配置戦略
  19. #openshiftjp { "kind": "Policy", "apiVersion": "v1", "predicates": [ {"name": "PodFitsHostPorts"},

    {"name": "PodFitsHostResources"}, ... ], "priorities": [ {"name": "MostRequestedPriority", "weight": 1}, {"name": "ServiceSpreadingPriority", "weight": 1}, ... ] } policy.cfg 確保済みリソースが多い Node を優先 = 詰め込む配置戦略
  20. #openshiftjp apiVersion: kubescheduler.config.k8s.io/v1alpha1 kind: KubeSchedulerConfiguration schedulerName: my-scheduler leaderElection: leaderElect: false

    algorithmSource: policy: configMap: namespace: kube-system name: my-scheduler-policy スケジューラに名前を付けておく
  21. #openshiftjp apiVersion: v1 kind: Pod metadata: name: my-app spec: schedulerName:

    my-scheduler containers: - name: my-app image: username/my-app:latest resources: requests: memory: 500Mi cpu: 200m どのスケジューラの管理下にするかを指定
  22. #openshiftjp #openshiftjp Section 1 のポイント • スケジューラは Pod を Node

    へ紐付ける ◦ Filtering で Node の候補を絞り、Scoring で順位付け • Policy によるスケジューリングの調整 ◦ あらかじめ定義されている項目の中から指定 • クラスタ内に複数のスケジューラが共存可能 ◦ Kubernetes の「舵輪型」アーキテクチャの恩恵
  23. #openshiftjp #openshiftjp コンテナを「詰める」ための指針 • Pod の必要リソース量を正しく指定 ◦ 余裕がありすぎると無駄、ギリギリすぎると強制終了の危険 ◦ そもそも何をもって「正しいリソース量」とするのか

    • スパイク的な負荷上昇への対応 ◦ 効率的に詰めると定常的にリソースの遊びがなくなる ◦ クラウドであっても Node の起動は Pod に比較して 2 ケタ遅い
  24. #openshiftjp apiVersion: v1 kind: Pod metadata: name: my-app spec: containers:

    - name: my-app image: username/my-app:latest resources: requests: memory: 6Gi cpu: 200m Mem : 6 GiB CPU : 0.2 core 本当は 2 GiB で足りるはずだけど OOM で死なないように多めにしとこう
  25. #openshiftjp Mem : 6 / 8 GiB CPU : 0.2

    / 2 core Mem : 6 GiB CPU : 0.2 core
  26. #openshiftjp Mem : 6 / 8 GiB CPU : 0.2

    / 2 core (Mem : 2 GiB) (CPU : 0.2 core) 無駄
  27. #openshiftjp #openshiftjp Vertical Pod Autoscaler (VPA) • Resource Requests は実使用量と無関係

    ◦ 少なすぎると危険、大きすぎるとお金の無駄 ◦ あらかじめ検証するにしても負荷テストが必要 ◦ 最終的には経験則で設定 • VPA により実測値に基づいた設定が可能に ◦ Pod を削除してから再作成する
  28. #openshiftjp Mem : 500 MiB CPU : 0.2 core Mem

    : 500 MiB CPU : 0.2 core Mem : 500 MiB CPU : 0.2 core Mem : 500 MiB CPU : 0.2 core Mem : 500 MiB CPU : 0.2 core Mem : 500 MiB CPU : 0.2 core Mem : 500 MiB CPU : 0.2 core Mem : 500 MiB CPU : 0.2 core
  29. #openshiftjp Mem : 500 MiB CPU : 0.2 core Mem

    : 500 MiB CPU : 0.2 core Mem : 500 MiB CPU : 0.2 core Mem : 1 GiB CPU : 0.5 core VPA Mem : 1 GiB CPU : 0.5 core Mem : 1 GiB CPU : 0.5 core
  30. #openshiftjp #openshiftjp VPA の構成要素 • Recommender ◦ 時系列データからリソース使用量の上限と下限を算出 • Updater

    ◦ 設定が上限と下限に収まっていない Pod を退去 • Admission Controller ◦ 新しい Pod の作成に割り込んで Request 値を上書き
  31. #openshiftjp Mem : 500 MiB CPU : 0.2 core Recommender

    Updater Mem: 500 MiB CPU : 0.2 core
  32. #openshiftjp Mem : 500 MiB CPU : 0.2 core Recommender

    Updater Mem: 500 MiB CPU : 0.2 core 200 <= Mem <= 400 0.1 <= CPU <= 1
  33. #openshiftjp Mem : 500 MiB CPU : 0.2 core Recommender

    Updater 200 <= Mem <= 400 0.1 <= CPU <= 1
  34. #openshiftjp Mem : 500 MiB CPU : 0.2 core Updater

    Mem : 500 MiB CPU : 0.2 core Recommender
  35. #openshiftjp Mem : 500 MiB CPU : 0.2 core Updater

    200 <= Mem <= 400 0.1 <= CPU <= 1 Recommender Admission Webhook Mem: 400 MiB CPU : 0.2 core
  36. #openshiftjp • 主に Deployment で管理 • 長時間、稼働し続ける • 出来るだけ散らしたい •

    今すぐ起動したい Server 系の Pod • 主に Job で管理 • 一定時間で終了する • 出来るだけ詰め込みたい • 余裕がある時に起動 Batch 系の Pod
  37. #openshiftjp S Mem : 3 GiB CPU : 0.2 core

    S Mem : 4 GiB CPU : 0.2 core B Mem : 1 GiB CPU : 0.2 core Mem : 8 / 8 GiB CPU : 0.6 / 2 core S Mem : 4 GiB CPU : 0.2 core Mem : 8 / 8 GiB CPU : 0.6 / 2 core B Mem : 2 GiB CPU : 0.2 core B Mem : 1 GiiB CPU : 0.2 core Mem : 8 / 8 GiB CPU : 0.6 / 2 core S Mem : 6 GiB CPU : 0.2 core B Mem : 1 GiiB CPU : 0.2 core Mem : 2 GiB CPU : 0.2 core S B Mem : 2 GiB CPU : 0.2 core
  38. #openshiftjp S Mem : 3 GiB CPU : 0.2 core

    S Mem : 4 GiB CPU : 0.2 core B Mem : 1 GiB CPU : 0.2 core Mem : 8 / 8 GiB CPU : 0.6 / 2 core S Mem : 4 GiB CPU : 0.2 core Mem : 8 / 8 GiB CPU : 0.6 / 2 core B Mem : 2 GiB CPU : 0.2 core B Mem : 1 GiiB CPU : 0.2 core Mem : 8 / 8 GiB CPU : 0.6 / 2 core S Mem : 6 GiB CPU : 0.2 core B Mem : 1 GiiB CPU : 0.2 core Mem : 2 GiB CPU : 0.2 core S B Mem : 2 GiB CPU : 0.2 core
  39. #openshiftjp #openshiftjp Priority と Preemption • Priority の指定 ◦ Scheduler

    のキューは優先度付きキューになる • Preemption ◦ Filtering で Node の候補が見つからなかった際に発動 ◦ 低優先度の Pod を強制的に追い出す ◦ できるだけ影響が小さくなる Node を選ぶ
  40. #openshiftjp Dequeue Filtering Node が未定の Pod を一つ選択 Pod の条件に合う Node

    が見つからない Preemption 自分より低優先度の Pod を追い出す
  41. #openshiftjp apiVersion: scheduling.k8s.io/v1 kind: PriorityClass matadata: name: server value: 10000

    description: "The higher priority" --- apiVersion: scheduling.k8s.io/v1 kind: PriorityClass matadata: name: batch value: 100 description: "The lower priority"
  42. #openshiftjp apiVersion: scheduling.k8s.io/v1 kind: PriorityClass matadata: name: server value: 10000

    description: "The higher priority" --- apiVersion: scheduling.k8s.io/v1 kind: PriorityClass matadata: name: batch value: 100 description: "The lower priority" 優先度:高 優先度:低
  43. #openshiftjp #openshiftjp Preemption のアルゴリズム • まず低優先度の Pod をすべて消したと仮定 ◦ 余裕ができなければその時点で可能性なし

    ◦ 可能性がある Node が見つかったら次に進む • そのあとで消した Pod をひとつずつ戻す ◦ 追い出さざるをえない Pod に対してペナルティを計算 ◦ 最終的に傷がもっとも浅く済む Node をターゲットに
  44. #openshiftjp 高 Mem : 3 GiB CPU : 0.2 core

    高 Mem : 4 GiB CPU : 0.2 core 低 Mem : 1 GiB CPU : 0.2 core Mem : 8 / 8 GiB CPU : 0.6 / 2 core 高 Mem : 4 GiB CPU : 0.2 core Mem : 8 / 8 GiB CPU : 0.6 / 2 core 低 Mem : 2 GiB CPU : 0.2 core 低 Mem : 1 GiiB CPU : 0.2 core Mem : 8 / 8 GiB CPU : 0.6 / 2 core 高 Mem : 6 GiB CPU : 0.2 core 低 Mem : 1 GiiB CPU : 0.2 core Mem : 2 GiB CPU : 0.2 core 高 低 Mem : 2 GiB CPU : 0.2 core
  45. #openshiftjp 高 Mem : 3 GiB CPU : 0.2 core

    高 Mem : 4 GiB CPU : 0.2 core Mem : 7 / 8 GiB CPU : 0.4 / 2 core 高 Mem : 4 GiB CPU : 0.2 core Mem : 4 / 8 GiB CPU : 0.2 / 2 core Mem : 6 / 8 GiB CPU : 0.2 / 2 core 高 Mem : 6 GiB CPU : 0.2 core Mem : 2 GiB CPU : 0.2 core 高 まず低優先度 Pod を 全て追い出してみる 追い出しても無理 可能性あり 可能性あり
  46. #openshiftjp 高 Mem : 3 GiB CPU : 0.2 core

    高 Mem : 4 GiB CPU : 0.2 core Mem : 8 / 8 GiB CPU : 0.6 / 2 core 高 Mem : 4 GiB CPU : 0.2 core Mem : 6 / 8 GiB CPU : 0.4 / 2 core Mem : 6 / 8 GiB CPU : 0.2 / 2 core 高 Mem : 6 GiB CPU : 0.2 core Mem : 2 GiB CPU : 0.2 core 高 追い出した Pod を 戻せるところは戻す ひとつも戻せない 犠牲は 2 Pod ひとつは戻せる 犠牲は 1 Pod 低 Mem : 2 GiB CPU : 0.2 core 低 Mem : 1 GiB CPU : 0.2 core
  47. #openshiftjp 高 Mem : 3 GiB CPU : 0.2 core

    高 Mem : 4 GiB CPU : 0.2 core 低 Mem : 1 GiB CPU : 0.2 core Mem : 8 / 8 GiB CPU : 0.6 / 2 core 高 Mem : 4 GiB CPU : 0.2 core Mem : 6 / 8 GiB CPU : 0.4 / 2 core 低 Mem : 2 GiB CPU : 0.2 core 低 Mem : 1 GiiB CPU : 0.2 core Mem : 8 / 8 GiB CPU : 0.6 / 2 core 高 Mem : 6 GiB CPU : 0.2 core 低 Mem : 1 GiiB CPU : 0.2 core Mem : 2 GiB CPU : 0.2 core 高 追い出される
  48. #openshiftjp apiVersion: scheduling.k8s.io/v1 kind: PriorityClass matadata: name: server value: 10000

    preemptingPolicy: Never description: "The higher priority" Preemption を行わない
  49. #openshiftjp #openshiftjp コンテナを「散らす」ための指針 • 複数 Node 障害時の可用性を担保 ◦ 発生しうる広域障害の影響をあらかじめ洗い出し ◦

    障害時に「まとめて死ぬ」範囲をコントロール • 運用中に Pod が偏る状況が生じうる ◦ オートスケールや障害による Node の追加・削除 ◦ そのままにしておくと障害時に全滅の危険
  50. #openshiftjp #openshiftjp Topology Spread Constraint • Label による Topology の指定

    ◦ Node を論理的にグルーピング ◦ 運用中に「まとめて故障する単位」に相当 • Topology Spread Constraint ◦ 各 Topology 間での Pod 個数の差の許容範囲を指定 ◦ 強制(Filtering)か優先(Scoring)かは選択可能
  51. #openshiftjp apiVersion: v1 kind: Pod metadata: name: mypod labels: foo:

    bar spec: containers: (snip) topologySpreadConstraints: - topologyKey: rack maxSkew: 1 labelSelector: matchLabels: foo: bar whenUnsatisfiable: DoNotSchedule
  52. #openshiftjp apiVersion: v1 kind: Pod metadata: name: mypod labels: foo:

    bar spec: containers: (snip) topologySpreadConstraints: - topologyKey: rack maxSkew: 1 labelSelector: matchLabels: foo: bar whenUnsatisfiable: DoNotSchedule Pod をカウントする単位
  53. #openshiftjp apiVersion: v1 kind: Pod metadata: name: mypod labels: foo:

    bar spec: containers: (snip) topologySpreadConstraints: - topologyKey: rack maxSkew: 1 labelSelector: matchLabels: foo: bar whenUnsatisfiable: DoNotSchedule 許容できる個数の差
  54. #openshiftjp apiVersion: v1 kind: Pod metadata: name: mypod labels: foo:

    bar spec: containers: (snip) topologySpreadConstraints: - topologyKey: rack maxSkew: 1 labelSelector: matchLabels: foo: bar whenUnsatisfiable: DoNotSchedule 分散対象 Pod の指定
  55. #openshiftjp apiVersion: v1 kind: Pod metadata: name: mypod labels: foo:

    bar spec: containers: (snip) topologySpreadConstraints: - topologyKey: rack maxSkew: 1 labelSelector: matchLabels: foo: bar whenUnsatisfiable: DoNotSchedule 満たせない場合は配置禁止(Filtering)
  56. #openshiftjp Mem : 2 GiB CPU : 0.2 core Mem

    : 2 / 8 GiB CPU : 0.2 / 2 core Mem : 2 MiB CPU : 0.2 core Mem : 2 / 8 GiB CPU : 0.2 / 2 core Mem : 2 GiB CPU : 0.2 core Mem : 2 / 8 GiB CPU : 0.2 / 2 core
  57. #openshiftjp Mem : 2 GiB CPU : 0.2 core Mem

    : 2 / 8 GiB CPU : 0.2 / 2 core Mem : 2 GiB CPU : 0.2 core Mem : 4 / 8 GiB CPU : 0.4 / 2 core Node 死亡 Mem : 2 GiB CPU : 0.2 core
  58. #openshiftjp Mem : 2 GiB CPU : 0.2 core Mem

    : 2 / 8 GiB CPU : 0.2 / 2 core Mem : 0 / 8 GiB CPU : 0 / 2 core Mem : 2 GiB CPU : 0.2 core Mem : 4 / 8 GiB CPU : 0.4 / 2 core Mem : 2 GiB CPU : 0.2 core 復活しても空のまま
  59. #openshiftjp #openshiftjp Descheduler • 運用に伴って崩れた Pod の配置を回復 • 特定の条件下で Pod

    を退去させる ◦ RemoveDuplicates : Replica が同じ Node に固まっている ◦ LowNodeUtilization : リソース使用率が一定以下 ◦ RemovePodsViolatingPodAntiAffinity : 他 Pod との相性に違反 ◦ RemovePodsViolatingNodeAffinity : Node との相性に違反
  60. #openshiftjp apiVersion: descheduler/v1alpha1 kind: DeschedulerPolicy strategies: LowNodeUtilization: enabled: true params:

    nodeResourceUtilizationThresholds: thresholds: memory: 20 cpu: 20 pods: 20 targetThresholds: memory: 50 cpu: 50 pods: 50
  61. #openshiftjp apiVersion: descheduler/v1alpha1 kind: DeschedulerPolicy strategies: LowNodeUtilization: enabled: true params:

    nodeResourceUtilizationThresholds: thresholds: memory: 20 cpu: 20 pods: 20 targetThresholds: memory: 50 cpu: 50 pods: 50 下限値(単位は %)
  62. #openshiftjp apiVersion: descheduler/v1alpha1 kind: DeschedulerPolicy strategies: LowNodeUtilization: enabled: true params:

    nodeResourceUtilizationThresholds: thresholds: memory: 20 cpu: 20 pods: 20 targetThresholds: memory: 50 cpu: 50 pods: 50 上限値(単位は %)
  63. #openshiftjp Mem : 1 GiB CPU : 0.2 core Mem

    : 1 GiB CPU : 0.2 core Mem : 1 GiB CPU : 0.2 core Mem : 3 / 8 GiB CPU : 0.6 / 2 core Mem : 1 GiB CPU : 0.2 core Mem : 2 GiB CPU : 0.2 core Mem : 3 GiB CPU : 0.1 core Mem : 6 / 8 GiB CPU : 0.5 / 2 core Mem : 0.5 GiB CPU : 0.8 core Mem : 0.5 / 8 GiB CPU : 0.8 / 2 core Mem : 20 % CPU : 20 % Pods : 20 % Thresholds Mem : 50 % CPU : 50 % Pods : 50 % Target Thresholds
  64. #openshiftjp Mem : 1 GiB CPU : 0.2 core Mem

    : 1 GiB CPU : 0.2 core Mem : 1 GiB CPU : 0.2 core Mem : 3 / 8 GiB CPU : 0.6 / 2 core Mem : 1 GiB CPU : 0.2 core Mem : 2 GiB CPU : 0.2 core Mem : 3 GiB CPU : 0.1 core Mem : 6 / 8 GiB CPU : 0.5 / 2 core Mem : 0.5 GiB CPU : 0.8 core Mem : 0.5 / 8 GiB CPU : 0.8 / 2 core Mem : 20 % CPU : 20 % Pods : 20 % Thresholds Mem : 50 % CPU : 50 % Pods : 50 % Target Thresholds Mem 遊びすぎ
  65. #openshiftjp Mem : 1 GiB CPU : 0.2 core Mem

    : 1 GiB CPU : 0.2 core Mem : 1 GiB CPU : 0.2 core Mem : 3 / 8 GiB CPU : 0.6 / 2 core Mem : 1 GiB CPU : 0.2 core Mem : 2 GiB CPU : 0.2 core Mem : 3 GiB CPU : 0.1 core Mem : 6 / 8 GiB CPU : 0.5 / 2 core Mem : 0.5 GiB CPU : 0.8 core Mem : 0.5 / 8 GiB CPU : 0.8 / 2 core Mem : 20 % CPU : 20 % Pods : 20 % Thresholds Mem : 50 % CPU : 50 % Pods : 50 % Target Thresholds Mem 使いすぎ
  66. #openshiftjp Mem : 1 GiB CPU : 0.2 core Mem

    : 1 GiB CPU : 0.2 core Mem : 1 GiB CPU : 0.2 core Mem : 3 / 8 GiB CPU : 0.6 / 2 core Mem : 1 GiB CPU : 0.2 core Mem : 2 GiB CPU : 0.2 core Mem : 3 / 8 GiB CPU : 0.4 / 2 core Mem : 0.5 GiB CPU : 0.8 core Mem : 3.5 / 8 GiB CPU : 0.9 / 2 core Mem : 20 % CPU : 20 % Pods : 20 % Thresholds Mem : 50 % CPU : 50 % Pods : 50 % Target Thresholds Mem : 3 GiB CPU : 0.1 core
  67. #openshiftjp #openshiftjp Section 2 のポイント • シンプルな原理だけでは最適な配置は難しい • 状況に応じて補完する機能やツールを使用 ◦

    Vertical Pod Autoscaler : 実測値に基づいて Requests を決めたい ◦ Preemption : 重要な Pod を優先して起動したい ◦ Topology Spread : 特定範囲内の Node の同時障害に耐えたい ◦ Descheduler : 運用中に生じた Pod の偏りを是正したい
  68. #openshiftjp #openshiftjp Scheduler Extender • JSON Webhook による処理の追加 • 拡張ポイントは

    4 箇所 ◦ Filter : Node の候補をさらに絞る ◦ Prioritized : Node の Scoring 関数を追加 ◦ Preempt : 退去させられる Pod の候補を絞る ◦ Bind : Pod の Node の紐付けの方法を定義
  69. #openshiftjp { "kind": "Policy", "apiVersion": "v1", "predicates": [(snip)], "priorities": [(snip)],

    "extenders": [{ "urlPrefix": "http://my-extender:8080", "filterVerb": "filter", "prioritizeVerb": "prioritize", "preemptVerb": "preempt", "bindVerb": "bind", "enableHttps": false }] } policy.cfg
  70. #openshiftjp { "kind": "Policy", "apiVersion": "v1", "predicates": [(snip)], "priorities": [(snip)],

    "extenders": [{ "urlPrefix": "http://my-extender:8080", "filterVerb": "filter", "prioritizeVerb": "prioritize", "preemptVerb": "preempt", "bindVerb": "bind", "enableHttps": false }] } policy.cfg Webhook サーバのエンドポイント
  71. #openshiftjp #openshiftjp Extender を利用したツール例 • kube-throttler (by PFN) ◦ 割り当て分を超えた

    Pod をリジェクトせず待機 • TopoLVM (by Cybozu) ◦ Node ごとの Persistent Volume のキャパシティを反映 • Stork (by Portworx) ◦ ネットワークストレージの状況を反映
  72. #openshiftjp #openshiftjp Scheduling Framework • Interface を提供、本体と同時にビルド ◦ JSON Webhook

    である Extender よりオーバヘッドが軽い ◦ より細かい拡張ポイントが設けられている ◦ 計算結果を拡張ポイントをまたいで使いまわせる • Scheduler 自体の実装も整理 ◦ Kubernetes v1.17 では既存の実装を移植中
  73. #openshiftjp #openshiftjp 開発中の特殊スケジューラ • kube-batch ◦ All or Nothing の配置

    (Co-Scheduling) に対応 ◦ 実証済み機能は機械学習プラットフォーム kubeflow で採用 • Poseidon ◦ Firmament Scheduler の Kubernetes 向け実装 ◦ Pod の配置をグラフ上の最小費用流問題に帰着
  74. #openshiftjp #openshiftjp Section 3 のポイント • Extender によるロジックの外部化 ◦ 外部の

    Webhook サーバとして稼働 • Framework によるソースコード内のカスタマイズ ◦ Extender と比較してレイテンシが向上 ◦ Kubernetes 本体も Scheduling Framework ベースに移行中 • その他、特殊なスケジューラも開発されている
  75. #openshiftjp #openshiftjp まとめ • スケジューラの責務と仕組み ◦ Filtering + Scoring で

    Pod にあった Node を選択 • 配置戦略を効果的に運用するための追加施策 ◦ 愚直に配置するだけではカバーできない課題を解決 • より複雑なユースケースに対応するユーザ拡張 ◦ Extender、Framework 、特殊スケジューラ