Slide 1

Slide 1 text

- Workload Availability for OpenShift - ノード障害時にStatefulSetも 自動回復したい! そんなときは medik8s.io Manabu Ori Red Hat 1 OpenShift.Run 2024 2024-03-28

Slide 2

Slide 2 text

2 ▸ worker-2で動いていたPodにEvictionが発動 ▸ k8sの自動復旧の仕組みにより、他のノードで自動的に ...起動してない子がいる?! ▸ worker-2で動いていたPodは Terminating のまま こういう状況見たことありませんか? ▸ worker-2でノード障害が発生!すると...

Slide 3

Slide 3 text

3 こういう状況見たことありませんか? ▸ ...といった状況を自動で復旧させる方法をご紹介します 勝手に復旧!

Slide 4

Slide 4 text

4 ▸ デフォルト設定では、ノード障害発生からおよそ 5分40秒でPodのEvictionが始まる ノード障害時の動き ノード障害発生 Taint付与 Eviction発動 ● node.kubernetes.io/not-ready ● node.kubernetes.io/unreachable tolerationSecondsのデフォルトは 300秒 node-monitor-grace-period (40秒) default-not-ready-toleration-seconds default-unreachable-toleration-seconds (300秒)

Slide 5

Slide 5 text

5 ▸ ノード障害時にPodが自動回復しないパターン: at-most-one semantics ・ StatefulSet ・ RWOなPVを持つPod ▸ KubeVirt/OpenShift Virtualizationでノード障害時にVMが別ノードで自動回復しない Kubernetesのありがちな悩み ▸ 本資料では、これを自動でなんとかするための仕組みをご紹介します ・ キーワード: ・ Workload Availability for OpenShift ・ Node Health Check Operator, Self Node Remediation Operator, ... ・ Medik8s https://www.medik8s.io/ ・ そういえば、最近(k8s v1.28で)Non Graceful Node Shutdownの機能がGAしましたね...

Slide 6

Slide 6 text

6 ▸ Failure Detectionの仕組みでノード障害を検知 ・ Machine Health Check (OpenShift標準機能、IPI前提) ・ Node Health Check Operator (UPIでも使用可) ・ SIG ClusterのExternal Remediation APIを利用 ▸ 検知の結果を元に、Remediationの仕組みを使って自動復旧 ・ Self Node Remediation (IPMI/Redfish必要なし) ・ Fence Agents (IPMI/Redfish前提) ・ Machine Deletion (APIでノード削除) 概要 Failure Detection Remediation Machine Health Check Node Health Check Operator Self Node Remediation Operator Fence Agents Remediation Operator Machine Deletion Remediation Operator OpenShift標準機能 追加Operator Legend: 障害検知 自動復旧

Slide 7

Slide 7 text

7 概要 Node Health Check Operator NodeHealthCheck SelfNode Remediation Self Node Remediation Operator SelfNode Remediation Config SelfNode Remediation Template Soft Watchdogに よる回復処理 FenceAgent Remediation Fence Agent Remediation Operator SelfNode Remediation Template FenceAgent Remediation Template IPMIによる フェンシング ノード障害を検知し、 Remediationが必要と判断する と、Templateから XXRemediation CRを生成 NHC Operatorがノード障害を検 知し、Remediationが必要と判断 すると、Templateから XXRemediation CRを生成 Self Node Remediation Fence Agent Remediation

Slide 8

Slide 8 text

8 ▸ 処理の概要: ・ 各ノードのNodeConditionsを見て、NodeHealthCheckで定義した判断基準/しきい値にひっ かかるかを確認 ・ 障害発生と判断でき、かつRemediation処理を実施するべき状況であれば、 Remediation Request カスタムリソースを作成 ・ このCRを見てRemediation処理が走る ▸ ノードのラベルに応じて異なる対応が可能 ・ NodeHealthCheckでnodeSelectorを指定 ▸ もしクラスターのバージョンアップ中であれば、それが完了するまで remediation処理をスキップする ・ https://github.com/medik8s/node-healthcheck-operator/blob/2edb6fd6d1b0294f19 d62c2e91815e44b96b74f4/controllers/nodehealthcheck_controller.go#L249-L255 ・ 今のところOpenShiftのみ Node Healthcheck Operator

Slide 9

Slide 9 text

9 ▸ NodeHealthCheck CRの例 Node Healthcheck Operator apiVersion: remediation.medik8s.io/v1alpha1 kind: NodeHealthCheck metadata: name: nodehealthcheck-sample spec: minHealthy: 51% pauseRequests: - remediationTemplate: apiVersion: self-node-remediation.medik8s.io/v1alpha1 name: self-node-remediation-resource-deletion-template namespace: openshift-workload-availability kind: SelfNodeRemediationTemplate escalatingRemediations: - remediationTemplate: apiVersion: self-node-remediation.medik8s.io/v1alpha1 name: self-node-remediation-resource-deletion-template namespace: openshift-workload-availability kind: SelfNodeRemediationTemplate order: 1 timeout: 300s selector: matchExpressions: - key: node-role.kubernetes.io/worker operator: Exists unhealthyConditions: - type: Ready status: "False" duration: 300s - type: Ready status: Unknown duration: 300s 最低限残す必要がある Healthyノード数 一時的にRemediationを止めたいときに使用 メインのRemediation処理のテンプレート Remediation処理を多重化したいときはここにリ ストする 適用するノードの指定 ノード障害と判断する条件

Slide 10

Slide 10 text

10 ▸ MachineHealthCheck/NodeHealthCheckで障害を検知した際、自動復旧を行う仕 組 みのひとつ ・ MHC/NHCコントローラがSelfNodeRemediation CRを作成 ・ SelfNodeRemediation CRを見てSNR OperatorがRemediation処理を実行 ▸ IPMI/Redfishやノード操作のAPIを必要としない ・ Software Watchdogを使用 Self Node Remediation Operator apiVersion: self-node-remediation.medik8s.io/v1alpha1 kind: SelfNodeRemediation metadata: name: selfnoderemediation-sample namespace: openshift-operators spec: remediationStrategy: status: lastError: apiVersion: self-node-remediation.medik8s.io/v1alpha1 kind: SelfNodeRemediationConfig metadata: name: self-node-remediation-config namespace: openshift-operators spec: safeTimeToAssumeNodeRebootedSeconds: 180 watchdogFilePath: /dev/watchdog isSoftwareRebootEnabled: true apiServerTimeout: 15s apiCheckInterval: 5s maxApiErrorThreshold: 3 peerApiServerTimeout: 5s peerDialTimeout: 5s peerRequestTimeout: 5s peerUpdateInterval: 15m (次ページ参照)

Slide 11

Slide 11 text

11 ▸ ResourceDeletion ・ ノード上のPodおよびPVCを削除する ▸ OutOfServiceTaint ・ KEP-2268: Non graceful node shutdownの機能を使用 ・ PVを持つPodが動いているノードに障害が発生した場合でも、 PVのデ タッチおよびPodの削除ができるようになる ・ ノードがNotReady状態かつ「node.kubernetes.io/out-of-service」 Taintが付与されている場合に、kube-controller-managerがPVのデ タッチ/Pod削除処理を行う ▸ Automatic ・ OutofServiceTaintが利用できる場合は使用し、そうでなければ ResourceDeletionを使用する (デフォルト設定) Remediation Strategy

Slide 12

Slide 12 text

12 ▸ fence agentを使って電源オン/オフを行う ・ よく使われるのはfence_ipmilan Fence Agent Remediation Operator apiVersion: fence-agents-remediation.medik8s.io/v1alpha1 kind: FenceAgentsRemediationTemplate metadata: name: fence-agents-remediation-template-fence-ipmilan namespace: openshift-workload-availability spec: template: spec: agent: fence_ipmilan nodeparameters: --ipport: master-0-0: '6230' master-0-1: '6231' master-0-2: '6232' worker-0-0: '6233' worker-0-1: '6234' worker-0-2: '6235' sharedparameters: '--action': reboot '--ip': 192.168.123.1 '--lanplus': '' '--password': password '--username': admin retryCount: '5' retryInterval: '5' timeout: '60'

Slide 13

Slide 13 text

13 ▸ 03:56:00 worker-2電源断 実際の動き (1) controllers.NodeHealthCheck Node is going to match unhealthy condition {"node": "worker-2", "condition type": "Ready", "condition status": "Unknown", "duration left": "4m59.920799888s"} controllers.NodeHealthCheck.resource manager Creating a remediation CR {"CR name": "worker-2", "CR kind": "SelfNodeRemediation", "namespace": "openshift-workload-availability"} ▸ 03:56:35 [node-healthcheck-controller-manager] Unhealhtyノードの検出 ▸ 04:01:35 [node-healthcheck-controller-manager] SelfNodeRemediation作成 node-monitor-grace-period default-not-ready-toleration-seconds default-unreachable-toleration-seconds

Slide 14

Slide 14 text

14 ▸ 04:04:37 [node-healthcheck-controller-manager] SelfNodeRemediation更新 (phase: Reboot-Completed) ▸ 04:04:38 [self-node-remediation-controller] out-of-service taint add 実際の動き(2) kube-controller-manager-master-2 kube-controller-manager I0328 04:04:47.598293 1 reconciler.go:277] "attacherDetacher.DetachVolume started: node has out-of-service taint, force detaching" node="worker-2" volumeName="kubernetes.io/csi/openshift-storage.rbd.csi.ceph.com^0001-0011-openshift-storage-0000000000000002-67bda59f-cf8f-4ad3-9ad9-df681d058b9c" kube-controller-manager-master-2 kube-controller-manager I0328 04:04:47.634199 1 reconciler.go:277] "attacherDetacher.DetachVolume started: node has out-of-service taint, force detaching" node="worker-2" volumeName="kubernetes.io/csi/openshift-storage.rbd.csi.ceph.com^0001-0011-openshift-storage-0000000000000002-25426b29-4dfa-48bf-8099-e7827b7cdca1" controllers.SelfNodeRemediation out-of-service taint added {"selfnoderemediation": "openshift-workload-availability/worker-2", "new taints": [{"key":"node.kubernetes.io/unreachable","effect":"NoSchedule","timeAdded":"2024-03-28T03:56:35Z"},{"key":"node.kubernetes.io/unreachable","effect":"NoExecute","time Added":"2024-03-28T03:56:40Z"},{"key":"medik8s.io/remediation","value":"self-node-remediation","effect":"NoExecute","timeAdded":"2024-03-28T04:01:36Z"},{"key":"node. kubernetes.io/unschedulable","effect":"NoSchedule","timeAdded":"2024-03-28T04:01:36Z"},{"key":"node.kubernetes.io/out-of-service","value":"nodeshutdown","effect":"No Execute","timeAdded":"2024-03-28T04:04:38Z"}]} ▸ 04:04:47 [kube-controller-manager] force detaching ▸ 04:01:37 [node-healthcheck-controller-manager] SelfNodeRemediation更新 (phase: Pre-Reboot-Completed) safeTimeToAssumeNodeRebootedSeconds

Slide 15

Slide 15 text

15 ▸ 04:04:48 [node-healthcheck-controller-manager] SelfNodeRemediation更新 (phase: Fencing-Completed) ▸ 04:04:48 [self-node-remediation-controller] out-of-service taint remove 実際の動き (3) controllers.SelfNodeRemediation out-of-service taint removed {"selfnoderemediation": "openshift-workload-availability/worker-2", "new taints": [{"key":"node.kubernetes.io/unreachable","effect":"NoSchedule","timeAdded":"2024-03-28T03:56:35Z"},{"key":"node.kubernetes.io/unreachable","effect":"NoEx ecute","timeAdded":"2024-03-28T03:56:40Z"},{"key":"medik8s.io/remediation","value":"self-node-remediation","effect":"NoExecute","timeAdded":"2024-03-28T0 4:01:36Z"},{"key":"node.kubernetes.io/unschedulable","effect":"NoSchedule","timeAdded":"2024-03-28T04:01:36Z"}]}

Slide 16

Slide 16 text

16 ▸ Workload Availability for Red Hat OpenShift ・ https://access.redhat.com/documentation/en-us/workload_availability_for_red_hat_openshift ▸ Node Health Check Operator ・ https://www.redhat.com/en/blog/node-health-check-operator ▸ Medik8s ・ https://www.medik8s.io/ ▸ Ø Kubernetes Failover Improvement: Non-Graceful Node Shutdown - Yuiko Mori, NEC Solution Innovators ・ https://www.youtube.com/watch?v=28dbE24j_zc&list=PLbzoR-pLrL6q7ytV2im0AoNcJcADAeBtm ・ https://jpn.nec.com/oss/community/blog/kubernetes-failover-improvement-non-graceful-node-sh utdown.html ・ https://qiita.com/y-mo/items/ecb9207175543392ffbe 参考文献

Slide 17

Slide 17 text

17 ▸ KEP-2268: Non graceful node shutdown ・ https://github.com/kubernetes/enhancements/tree/master/keps/sig -storage/2268-non-graceful-shutdown ・ https://github.com/kubernetes/kubernetes/pull/108486 ▸ External Remediation API ・ https://github.com/kubernetes-sigs/cluster-api/pull/3190 参考文献

Slide 18

Slide 18 text

linkedin.com/company/red-hat youtube.com/user/RedHatVideos facebook.com/redhatinc twitter.com/RedHat 18 Red Hat is the world’s leading provider of enterprise open source software solutions. Award-winning support, training, and consulting services make Red Hat a trusted adviser to the Fortune 500. Thank you

Slide 19

Slide 19 text

19 ▸ Provinzial - Workshop OpenShift Virtualization ・ https://docs.google.com/presentation/d/1k2MmPXpgrJgwq3ndZlvX O3qF6VnN4ROGIh5lxpTJh68/edit?usp=sharing ▸ OpenShift Virtualization Technical Sales Overview ・ https://docs.google.com/presentation/d/146vui1TfdaJLtx6G17wnTno mJLspoYNoJBJwvgDPR6E/edit?usp=sharing ・ ▸ ▸ 参考文献 (internal)

Slide 20

Slide 20 text

20 ▸ Kubernetes 1.24: Introducing Non-Graceful Node Shutdown Alpha ▸ Kubernetes 1.26: Non-Graceful Node Shutdown Moves to Beta ▸ Kubernetes 1.28: Non-Graceful Node Shutdown Moves to GA Graceful shutdownとNon graceful shutdown

Slide 21

Slide 21 text

21 ▸ 03:56:00 worker-2電源断 ▸ 03:56:35 [node-healthcheck-controller-manager] Unhealhtyノードの検出 ▸ 04:01:35 SelfNodeRemediation作成 ▸ 04:01:37 SelfNodeRemediation更新 (phase: Pre-Reboot-Completed) ▸ 04:04:37 SelfNodeRemediation更新 (phase: Reboot-Completed) ▸ 04:04:38 [self-node-remediation-controller] out-of-service taint add ▸ 04:04:47 [kube-controller-manager] force detaching ▸ 04:04:48 SelfNodeRemediation更新 (phase: Fencing-Completed) ▸ 04:04:48 [self-node-remediation-controller] out-of-service taint remove ノード電源断 kube-controller-manager-master-2 kube-controller-manager I0328 04:04:47.598293 1 reconciler.go:277] "attacherDetacher.DetachVolume started: node has out-of-servic taint, force detaching" node="worker-2" volumeName="kubernetes.io/csi/openshift-storage.rbd.csi.ceph.com^0001-0011-openshif storage-0000000000000002-67bda59f-cf8f-4ad3-9ad9-df681d058b9c" kube-controller-manager-master-2 kube-controller-manager I0328 04:04:47.634199 1 reconciler.go:277] "attacherDetacher.DetachVolume started: node has out-of-servic taint, force detaching" node="worker-2" volumeName="kubernetes.io/csi/openshift-storage.rbd.csi.ceph.com^0001-0011-openshif storage-0000000000000002-25426b29-4dfa-48bf-8099-e7827b7cdca1" controllers.SelfNodeRemediation out-of-service taint added {"selfnoderemediation": "openshift-workload-availability/worker-2", "new taints": [{"key":"node.kubernetes.io/unreachable","effect":"NoSchedule","timeAdded":"2024-03-2 8T03:56:35Z"},{"key":"node.kubernetes.io/unreachable","effect":"NoExecute","timeAdded ":"2024-03-28T03:56:40Z"},{"key":"medik8s.io/remediation","value":"self-node-remediat ion","effect":"NoExecute","timeAdded":"2024-03-28T04:01:36Z"},{"key":"node.kubernetes .io/unschedulable","effect":"NoSchedule","timeAdded":"2024-03-28T04:01:36Z"},{"key":" node.kubernetes.io/out-of-service","value":"nodeshutdown","effect":"NoExecute","timeA dded":"2024-03-28T04:04:38Z"}]} controllers.SelfNodeRemediation out-of-service taint removed {"selfnoderemediation": "openshift-workload-availability/worker-2", "new taints": [{"key":"node.kubernetes.io/unreachable","effect":"NoSchedule","timeAdded":"2024-03-2 8T03:56:35Z"},{"key":"node.kubernetes.io/unreachable","effect":"NoExecute","timeAdded ":"2024-03-28T03:56:40Z"},{"key":"medik8s.io/remediation","value":"self-node-remediat ion","effect":"NoExecute","timeAdded":"2024-03-28T04:01:36Z"},{"key":"node.kubernetes .io/unschedulable","effect":"NoSchedule","timeAdded":"2024-03-28T04:01:36Z"}]} func (r *SelfNodeRemediationReconciler) useOutOfServiceTaint(node *v1.Node, snr *v1alpha1.SelfNodeRemediation) (time.Duration, error) { if err := r.addOutOfServiceTaint(node); err != nil { return 0, err } // We can not control to delete node resources by the "out-of-service" tai // So timer is used to avoid to keep waiting to complete if !r.isResourceDeletionCompleted(node) { isExpired, timeLeft := r.isResourceDeletionExpired(snr) if !isExpired { return timeLeft, nil } // if the timer is expired, exponential backoff is triggered return 0, errors.New("Not ready to delete out-of-service taint") } if err := r.removeOutOfServiceTaint(node); err != nil { return 0, err } return 0, nil } controllers.NodeHealthCheck Node is going to match unhealthy condition {"node": "worker-2", "condition type": "Ready", "condition status": "Unknown", "duration left": "4m59.920799888s"} controllers.NodeHealthCheck.resource manager Creating a remediation CR {"CR name": "worker-2", "CR kind": "SelfNodeRemediation", "namespace": "openshift-workload-availability"}

Slide 22

Slide 22 text

22 ▸ Unknown: control planeがkubeletからのハートビートを40秒以上受け取らなかっ た場合 ▸ False: 初期化処理の中で何かが失敗した場合 (ネットワークプラグインがうまく動か ない等) xxx

Slide 23

Slide 23 text

23

Slide 24

Slide 24 text

24 ▸ SelfNodeRemediationConfig spec: apiCheckInterval: 15s apiServerTimeout: 5s hostPort: 30001 isSoftwareRebootEnabled: true maxApiErrorThreshold: 3 peerApiServerTimeout: 5s peerDialTimeout: 5s peerRequestTimeout: 5s peerUpdateInterval: 15m safeTimeToAssumeNodeRebootedSeconds: 180 watchdogFilePath: /dev/watchdog

Slide 25

Slide 25 text

25 ▸ spec.template.spec.remediationStrategy ・ Automatic ・ ResourceDeletion ・ OutOfServiceTaint SelfNodeRemediationTemplate

Slide 26

Slide 26 text

26 SelfNodeRemediationTemplate ▸ Deployment with PV ▸ StatefulSet apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pvc-vol-a spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi storageClassName: ocs-storagecluster-ceph-rbd volumeMode: Filesystem --- apiVersion: apps/v1 kind: Deployment metadata: labels: app: deployment-with-pv-a name: deployment-with-pv-a spec: replicas: 1 selector: matchLabels: deployment: deployment-with-pv-a template: metadata: labels: deployment: deployment-with-pv-a spec: affinity: nodeAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 1 preference: matchExpressions: - key: kubernetes.io/hostname operator: In values: - worker-0 containers: - image: registry.access.redhat.com/ubi8/httpd-24 imagePullPolicy: IfNotPresent name: httpd volumeMounts: - name: vol-a mountPath: /var/www/html nodeSelector: type: medik8s-test volumes: - name: vol-a persistentVolumeClaim: claimName: pvc-vol-a apiVersion: v1 kind: Service metadata: name: sts labels: app: sts spec: ports: - port: 80 name: web clusterIP: None selector: app: sts --- apiVersion: apps/v1 kind: StatefulSet metadata: name: sts spec: selector: matchLabels: app: sts serviceName: "sts" replicas: 3 minReadySeconds: 10 template: metadata: labels: app: sts spec: nodeSelector: type: medik8s-test terminationGracePeriodSeconds: 10 containers: - name: httpd image: registry.access.redhat.com/ubi8/httpd-24 ports: - containerPort: 8080 name: web volumeMounts: - name: sts mountPath: /var/www/html volumeClaimTemplates: - metadata: name: sts spec: accessModes: [ "ReadWriteOnce" ] storageClassName: "ocs-storagecluster-ceph-rbd" resources: requests: storage: 1Gi

Slide 27

Slide 27 text

27 ▸ NodeHealthCheck spec: minHealthy: 51% 1 pauseRequests: 2 - remediationTemplate: 3 apiVersion: self-node-remediation.medik8s.io/v1alpha1 name: self-node-remediation-resource-deletion-template namespace: openshift-workload-availability kind: SelfNodeRemediationTemplate escalatingRemediations: 4 - remediationTemplate: apiVersion: self-node-remediation.medik8s.io/v1alpha1 name: self-node-remediation-resource-deletion-template namespace: openshift-workload-availability kind: SelfNodeRemediationTemplate order: 1 timeout: 300s selector: 5 matchExpressions: - key: node-role.kubernetes.io/worker operator: Exists unhealthyConditions: 6 - type: Ready status: "False" duration: 300s 7 - type: Ready status: Unknown duration: 300s

Slide 28

Slide 28 text

Kernel Module Management Operator 28 ▸ aaa aaa

Slide 29

Slide 29 text

Kernel Module Management Operator 29 ▸ Node Health Check (NHC) Operator ・ https://www.redhat.com/en/blog/node-health-check-operator ▸ ノード障害時、データ破損の可能性があるため failoverできない場合がある ▸ NHC ・ ノードの状態を監視 ・ いくつかの指標で死活状態を判断 ・ テンプレートからあらかじめ設定しておいた方法で復旧を試みる ・ aaa

Slide 30

Slide 30 text

Kernel Module Management Operator 30 ▸ NHCが出る前、Poison Pill OperatorはMachine Health Check Controllerに制御 されていた。つまり、Machine APIが前提だった ・ driven by Machine Health Check Controller ・ requires Machine API (≒ IPI) ▸ つまりその当時は、Machine APIがないとノードレベルの高可用性を確保する方法 がなかった ▸ Poison Pill OperatorとMachine Health Check Controllerの経験をもとに、ソリュー ションを一般化してupstreamに提案 ・ External Remediation API ・ NHC as the detection and delegating mechanism ・ Medik8s: umbrella project aaa

Slide 31

Slide 31 text

Kernel Module Management Operator 31 ▸ CR: MachineHealthCheck ▸ Limitations: ・ Machine Set管理のみ (IPIのみ) ・ ノードが削除されると、直ちにremediationが発動する ・ nodeStartupTimeoutだけ待ってもノードがクラスターに参加しない場合、 remediationが発動する ・ MachineリソースがFailedになるとremediationが発動する Machine Health Check

Slide 32

Slide 32 text

Kernel Module Management Operator 32 ▸ aaa aaa https://docs.google.com/presentation/d/1k2MmPXpgrJgwq3ndZlvXO3qF6VnN4ROGIh5lxpTJh68/edit#slide=id.g2933be5451 d_3_101

Slide 33

Slide 33 text

Kernel Module Management Operator 33 ▸ aaa aaa https://drive.google.com/file/d/1DIm3kR9g_y87KxGtXVS1BUEogz7wMvHN/view?usp=sharing

Slide 34

Slide 34 text

Kernel Module Management Operator 34 ▸ Failure Detection System ・ Machine Health Check ・ Node Health Check ▸ Self Node Remediation Operator ・ 管理インターフェース(IPMI, Node Provisioning API等)を必要としない ▸ Fence Agents Remediation (FAR) Operator ・ IPMI等を使ったいわゆるFencingによるRemediationを行う ▸ Machine Deletion Remediation (MDR) Operator ・ Machine APIによってunhealthyなノードを再構築する aaa

Slide 35

Slide 35 text

Kernel Module Management Operator 35 ▸ MachineHealthCheck/NodeHealthCheck CR(のコントローラ)が SelfNodeRemediation CRを作成する ・ Self Node Remediation Operatorが仕事を始める ▸ Watchdogデバイス or software reboot Self Node Remediation apiVersion: self-node-remediation.medik8s.io/v1alpha1 kind: SelfNodeRemediation metadata: name: selfnoderemediation-sample namespace: openshift-operators spec: remediationStrategy: status: lastError:

Slide 36

Slide 36 text

Kernel Module Management Operator 36 ▸ MachineHealthCheck/NodeHealthCheck CR(のコントローラ)が SelfNodeRemediation CRを作成する ・ Self Node Remediation Operatorが仕事を始める ▸ Watchdogデバイス or software reboot Self Node Remediation Config apiVersion: self-node-remediation.medik8s.io/v1alpha1 kind: SelfNodeRemediationConfig metadata: name: self-node-remediation-config namespace: openshift-operators spec: safeTimeToAssumeNodeRebootedSeconds: 180 watchdogFilePath: /dev/watchdog isSoftwareRebootEnabled: true apiServerTimeout: 15s apiCheckInterval: 5s maxApiErrorThreshold: 3 peerApiServerTimeout: 5s peerDialTimeout: 5s peerRequestTimeout: 5s peerUpdateInterval: 15m

Slide 37

Slide 37 text

Kernel Module Management Operator 37 ▸ aaa Control plane fencing

Slide 38

Slide 38 text

Kernel Module Management Operator 38 OpenShift 上で out-of-tree なカーネルモジュールのロード、ライフサイクル管理を行う Operator 以下のユースケースで利用する ▸ out-of-tree なデバイスドライバを利用したい ▸ カーネルモジュールが in-tree 化されるまでの移行期間に検証したい KMM Operator は以下のツールを提供する ▸ Kernel Module Management Operator (KMM) ▸ Driver Toolkit Container (DTK) Optional subheading Kernel Module Management Operator

Slide 39

Slide 39 text

Kernel Module Management Operator 39 [1] https://docs.openshift.com/container-platform/4.14/hardware_enablement/psap-driver-toolkit.html OpenShift 上ではカーネルモジュールを含むドライバーコンテナを起動することで out-of-tree な カーネルモジュールのロードを行う。 DTK はドライバーコンテナに含めるカーネルモジュールをビルドするためのベースイメージ。 KMMO は内部的に DTK を使用してカーネルモジュールのビルドとドライバーコンテナのデプロイ を行う[1] ▸ DTK 上でビルドしたカーネルモジュールを含むドライバーコンテナを Node 上で起動し、カー ネルモジュールをロードする ▸ カーネルモジュールのビルドまたはインストールに必要なカーネルパッケージ、ドライバーコ ンテナーで必要とされるいくつかのツールが含まれる ▸ OpenShift の RHCOS のカーネルバージョンと一致する DTK を使用してカーネルモジュー ルをビルドする Driver Toolkit Container (DTK) ARG DTK FROM ${DTK} as builder ARG KVER WORKDIR /build/ RUN git clone https://github.com/openshift-psap/simple-kmod .git WORKDIR /build/simple-kmod RUN make all install KVER=${KVER} FROM registry.redhat.io/ubi8/ubi-minimal ARG KVER # Required for installing `modprobe` RUN microdnf install kmod COPY --from=builder /lib/modules/${KVER}/simple-kmod.ko /lib/modules/${KVER}/ COPY --from=builder /lib/modules/${KVER}/simple-procfs-kmod.ko /lib/modules/${KVER}/ RUN depmod ${KVER} DTK によりカーネルモジュールをビルド、ドライバーコンテ ナを作成する Dockerfile の例

Slide 40

Slide 40 text

Kernel Module Management Operator 40 [1] https://docs.openshift.com/container-platform/4.14/hardware_enablement/kmm-kernel-module-management.html#kmm-creating-module-cr_kernel-module-management-o perator Dockerfile を定義した ConfigMap を参照する Module CR を作成することで、以下のフローによりドライバーコンテ ナ (KMM の用語では Module Loader) イメージをビルド、対象 Node で実行してカーネルモジュールをロードする[1] ▸ .spec.selector の条件に一致する Node のリストアップ ▸ 各 Node のカーネルバージョンを確認 ▸ 対象のカーネルバージョンごとに以下を実施 ・ .spec.moduleLoader.container.kernelMappings の定義にもとづき Module Loader イメージ を決定、コンテナイメージが存在しない場合 build や sign の定義にもとづきイメージビルドや署名を行 う ・ Module Loader イメージの Pod を起動 ・ .spec.devicePlugin が定義されている場合はデバイスプラグイン DaemonSet を作成 KMM によるカーネルモジュールのライフサイクル管理 apiVersion: kmm.sigs.x-k8s.io/v1beta1 kind: Module metadata: name: kmm-ci-a namespace: labsv2 spec: moduleLoader: serviceAccountName: labsv2sa container: modprobe: moduleName: kmm-ci-a kernelMappings: - regexp: '^.*' containerImage: myrepo.xyz/kmm-labs:kmm-kmod-${KERNEL_FULL_VERSION }-v1.0 build: dockerfileConfigMap: name: build-module-labs imageRepoSecret: name: myrepo-pull-secret selector: node-role.kubernetes.io/worker: "" Module CR の例

Slide 41

Slide 41 text

Kernel Module Management Operator 41 [1] https://docs.openshift.com/container-platform/4.14/hardware_enablement/kmm-kernel-module-management.html#kmm-using-driver-toolkit_kernel-module-management-operator [2] https://docs.openshift.com/container-platform/4.14/hardware_enablement/kmm-kernel-module-management.html#kmm-creating-moduleloader-image_kernel-module-management-operator Dockerfile 上で ARG DTK_AUTO を定義することで KMM が対象 Node のカーネルバージョンに一 致する DTK を自動で使用するよう設定する [1] Module Loader イメージは以下の要件を満たすように作成する [2] ▸ .ko ファイルが /opt/lib/modules/${KERNEL_VERSION} に配置される ▸ modprobe と sleep は環境変数 PATH でパスが通っている KMM によるカーネルモジュールのビルド ARG DTK_AUTO FROM ${DTK_AUTO} as builder ARG KERNEL_VERSION WORKDIR /usr/src RUN ["git", "clone", "https://github.com/rh-ecosystem-edge/kernel-modul e-management.git"] WORKDIR /usr/src/kernel-module-management/ci/kmm-kmod RUN KERNEL_SRC_DIR=/lib/modules/${KERNEL_VERSION}/buil d make all FROM registry.redhat.io/ubi9/ubi-minimal ARG KERNEL_VERSION RUN microdnf install kmod COPY --from=builder /usr/src/kernel-module-management/ci/kmm-kmod/kmm_ ci_a.ko /opt/lib/modules/${KERNEL_VERSION}/ COPY --from=builder /usr/src/kernel-module-management/ci/kmm-kmod/kmm_ ci_b.ko /opt/lib/modules/${KERNEL_VERSION}/ RUN depmod -b /opt ${KERNEL_VERSION} Dockerfile の例

Slide 42

Slide 42 text

Kernel Module Management Operator 42 [1] https://github.com/kubernetes-sigs/kernel-module-management/releases/tag/v2.0.0 [2] OpenShift 4.14 では現時点で KMMO 2.0 のみサポートされる https://access.redhat.com/labs/ocpouic/?operator=kernel&&upgrade_path=4.12%20to%204.14 KMM 2.0 では主に以下のような機能改善が行われている [1][2] ▸ カーネルモジュールのロード方法の変更 (DaemonSet -> Worker Pod) ▸ Module Loader イメージのビルド時やカーネルモジュールロード時にイベントが記 録されるようになった ▸ Module Loader イメージ内に格納したファームウェアファイルを Node のファイルシ ステムにコピーし、カーネルモジュールのロード前に事前にロードできるようになった KMM 2.0 の機能改善

Slide 43

Slide 43 text

Kernel Module Management Operator 43 [1] https://github.com/kubernetes-sigs/kernel-module-management/blob/main/docs/enhancements/0001-worker-pods.md 以前まで Module Loader コンテナは対応するモジュールごと、カーネルバージョンごと に DeamonSet として作成していたが、以下の課題があった [1] ▸ preStopフックによるモジュールのアンロードに失敗したかどうかの判断が難しかっ た (preStopフックの成功 / 失敗に関わらず Pod は終了するため) ▸ KMM Operator アップグレードに伴う Pod の再起動や終了時にモジュールがアン ロードされる ▸ モジュールのロード後も常駐していたため無駄にリソースを確保していた KMM 2.0 の機能改善 カーネルモジュールのロード方法の変更 (DaemonSet -> Worker Pod)

Slide 44

Slide 44 text

Kernel Module Management Operator 44 [1] https://github.com/kubernetes-sigs/kernel-module-management/blob/main/docs/enhancements/0001-worker-pods.md KMM 2.0 ではモジュールのロード時のみアドホックに実行し、フックを使用せずモ ジュールのロードを行う Worker Pod に変更することで改善を行っている。 ▸ Worker Pod は モジュールごと、 Node ごとに起動する ▸ Worker Pod は Module Loader イメージからビルドしたカーネルモジュールを抽 出、 Node 上でモジュールのロード後終了する。 ▸ Node 上で最後に Worker Pod が実行された時刻より Node が Ready になった時 刻が新しい場合、Node 再起動によりモジュールがアンロードされた可能性がある ため再度 Worker Pod を実行する KMM 2.0 の機能改善 カーネルモジュールのロード方法の変更 (DaemonSet -> Worker Pod)

Slide 45

Slide 45 text

Kernel Module Management Operator 45 KMM Operator が以下のイベントを発行することで状態把握がしやすくなった ▸ ビルドおよび署名ジョブの作成、完了、失敗 (Module オブジェクトのイベントとして出力 ) ▸ Node へのカーネルモジュールのロード、アンロード (Node オブジェクトのイベントとして出力 ) KMM 2.0 の機能改善 イベントログの発行

Slide 46

Slide 46 text

Kernel Module Management Operator 46 [1] https://docs.openshift.com/container-platform/4.14/hardware_enablement/kmm-kernel-module-management.html#kmm-firmware-support_kernel-module-management-op erator Module Loader イメージ内に格納したファームウェアファイルを Node のファイルシステ ムにコピーし、カーネルモジュールのロード前に事前にロードできるようになった [1] ▸ .spec.moduleLoader.container.modprobe.firmwarePath に指定したディ レクトリ内のファームウェアファイルが Node 上の /var/lib/firmware にコピーさ れる ▸ 事前に MachineConfig を作成し、ファームウェアのデフォルトの検索パスのセット に /var/lib/firmware を追加しておく必要がある KMM 2.0 の機能改善 ファームウェアファイルのロードのサポート