こんにちは、Red Hatでアーキテクトをしている石井です。
普段は主に通信の事業者様向けにOpenShiftやOpenStack、Cephなどのコンサルティングをしています。
OpenShift Advent Calendar 2025 Day2ということで、Day2といえばMCO、MCOといえばDay2ですよね。
書きたいことが多すぎてアドベントカレンダー2日目にして重めな記事を書いてしまいましたが、MCOに興味があればぜひ読んでいただければと思います!
はじめに
OpenShiftが持つOperatorの一つにMachine Config Operator (MCO) があります。
ノードのインストール時の設定からDay2での設定変更、アップグレードまでを一元的に管理し、ノード台数が多い環境下に置いても共通化された設定を一括して適用・管理することが可能となります。
様々な設定ができてとても便利なOperatorなのですが、一方でそれ故にうっかり変な設定を投入してしまうと簡単にDegraded状態に陥り、ノードがなかなか戻ってきてくれず、最悪の場合にっちもさっちもいかなくなる…
「トホホ、もうMachineConfigはこりごりだよ〜」という苦い経験をされた方もいらっしゃるのではないかと思います。
今日はそんなMCOのことをちゃんと理解するために、MCOが実施している処理を肩代わりしてこちらでMachineConfigの設定追加を行ってみましょう。AIが人間の代わりに働いてくれることが増えた昨今ですが、逆に人間がOpenShiftの代わりに働いてあげたっていいですよね。逆に。
なお、MCO/MachineConfigについては公式ドキュメントやOpenShift徹底入門の11.1.6章に詳しい説明がありますので、今回の内容と重複するところもありますが、ぜひそちらも参照してみてください。
また、ソースコードが大好きな皆様におかれましてはぜひrepositoryを必要に応じて直接ご確認いただければと思います。
今回の検証環境
今回はAWS上にIPIで構築したOpenShift 4.20.4を利用します。MCOの基本的な動作はどのプラットフォームのどのバージョンでもずっと変わっていないので別のプラットフォームや以前のバージョンでも今回の内容は基本的に同一の結果になるはずです。
[lab-user@bastion machineconfig]$ oc get clusterversion
NAME VERSION AVAILABLE PROGRESSING SINCE STATUS
version 4.20.4 True False 43h Cluster version is 4.20.4
[lab-user@bastion machineconfig]$ oc get node
NAME STATUS ROLES AGE VERSION
ip-10-0-10-165.us-east-2.compute.internal Ready control-plane,master 43h v1.33.5
ip-10-0-11-138.us-east-2.compute.internal Ready worker 43h v1.33.5
ip-10-0-13-189.us-east-2.compute.internal Ready control-plane,master 43h v1.33.5
ip-10-0-44-17.us-east-2.compute.internal Ready control-plane,master 43h v1.33.5
ip-10-0-61-247.us-east-2.compute.internal Ready worker 43h v1.33.5
ip-10-0-61-98.us-east-2.compute.internal Ready worker 43h v1.33.5
とりあえず壊してみる
まず、正しく動かすためには正しく動かないパターンを見てなぜ正しく動かないのかを見てみることが有効ですよね。少なくとも私はそう考えています。人は壊したクラスタの数だけ成長できる、そう信じてまずはにっちもさっちもいかない状況を作ってみましょう。
下記のMachineConfigを適用してみます。
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
metadata:
labels:
machineconfiguration.openshift.io/role: worker
name: 99-worker-always-degraded
spec:
config:
ignition:
version: 3.5.0
storage:
files:
- mode: 420
overwrite: false
path: /tmp/tmpfile
このMCは絶対に適用できない、必ず失敗する設定です。
なぜDegradedになるかが現時点でわかる方は、かなりMachineConfigへの造詣が深いと言えます。それが嬉しいかどうかはさておき。
[lab-user@bastion machineconfig]$ oc apply -f 99-worker-always-degraded.yaml
machineconfig.machineconfiguration.openshift.io/99-worker-always-degraded created
[lab-user@bastion machineconfig]$ oc get mcp
NAME CONFIG UPDATED UPDATING DEGRADED MACHINECOUNT READYMACHINECOUNT UPDATEDMACHINECOUNT DEGRADEDMACHINECOUNT AGE
master rendered-master-d868db98f6b40ee2e6719f5226faab58 True False False 3 3 3 0 43h
worker rendered-worker-2bc1dfd10eba3b11a558e7b8edddd605 False True True 3 0 0 1 43h
[lab-user@bastion machineconfig]$ oc get node
NAME STATUS ROLES AGE VERSION
ip-10-0-10-165.us-east-2.compute.internal Ready control-plane,master 46h v1.33.5
ip-10-0-11-138.us-east-2.compute.internal Ready,SchedulingDisabled worker 46h v1.33.5
ip-10-0-13-189.us-east-2.compute.internal Ready control-plane,master 46h v1.33.5
ip-10-0-44-17.us-east-2.compute.internal Ready control-plane,master 46h v1.33.5
ip-10-0-61-247.us-east-2.compute.internal Ready worker 46h v1.33.5
ip-10-0-61-98.us-east-2.compute.internal Ready worker 46h v1.33.5
無事(?)、Degraded状態になりましたね。
このままでは別のMachineConfigも適用できないので困ってしまいます。Degraded状態は解消せねばなりません。
applyした設定が悪さしているはずなので、一旦元のMachineConfigに切り戻しましょう。
[lab-user@bastion machineconfig]$ oc delete -f 99-worker-always-degraded.yaml
machineconfig.machineconfiguration.openshift.io "99-worker-always-degraded" deleted
[lab-user@bastion machineconfig]$ oc get mcp
NAME CONFIG UPDATED UPDATING DEGRADED MACHINECOUNT READYMACHINECOUNT UPDATEDMACHINECOUNT DEGRADEDMACHINECOUNT AGE
master rendered-master-d868db98f6b40ee2e6719f5226faab58 True False False 3 3 3 0 44h
worker rendered-worker-2bc1dfd10eba3b11a558e7b8edddd605 False True True 3 2 2 1 44h
まだ変更が加えられる前のノードはupdated/ready状態にカウントされるようになりましたが、Degradedになってしまったノードはそのままです。にっちもさっちもいかない環境が生まれました。
設定内容は違えどこの状態に陥った方は少なくないのではと思います。
Degradedになった原因の調査
とりあえず何が問題なのか、ログを見てみましょう。
pod一覧を取得、適当にあたりをつけてログを見ることにします。
[lab-user@bastion machineconfig]$ oc get pod -n openshift-machine-config-operator -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
kube-rbac-proxy-crio-ip-10-0-10-165.us-east-2.compute.internal 1/1 Running 5 47h 10.0.10.165 ip-10-0-10-165.us-east-2.compute.internal <none> <none>
kube-rbac-proxy-crio-ip-10-0-11-138.us-east-2.compute.internal 1/1 Running 7 47h 10.0.11.138 ip-10-0-11-138.us-east-2.compute.internal <none> <none>
kube-rbac-proxy-crio-ip-10-0-13-189.us-east-2.compute.internal 1/1 Running 5 47h 10.0.13.189 ip-10-0-13-189.us-east-2.compute.internal <none> <none>
kube-rbac-proxy-crio-ip-10-0-44-17.us-east-2.compute.internal 1/1 Running 5 47h 10.0.44.17 ip-10-0-44-17.us-east-2.compute.internal <none> <none>
kube-rbac-proxy-crio-ip-10-0-61-247.us-east-2.compute.internal 1/1 Running 10 47h 10.0.61.247 ip-10-0-61-247.us-east-2.compute.internal <none> <none>
kube-rbac-proxy-crio-ip-10-0-61-98.us-east-2.compute.internal 1/1 Running 2 47h 10.0.61.98 ip-10-0-61-98.us-east-2.compute.internal <none> <none>
machine-config-controller-587ff89599-pjcj5 2/2 Running 4 47h 10.128.0.24 ip-10-0-13-189.us-east-2.compute.internal <none> <none>
machine-config-daemon-2xh79 2/2 Running 13 41m 10.0.11.138 ip-10-0-11-138.us-east-2.compute.internal <none> <none>
machine-config-daemon-62kgp 2/2 Running 4 47h 10.0.44.17 ip-10-0-44-17.us-east-2.compute.internal <none> <none>
machine-config-daemon-hh9q9 2/2 Running 47 47h 10.0.61.247 ip-10-0-61-247.us-east-2.compute.internal <none> <none>
machine-config-daemon-ktgw5 2/2 Running 4 47h 10.0.10.165 ip-10-0-10-165.us-east-2.compute.internal <none> <none>
machine-config-daemon-w95fz 2/2 Running 4 47h 10.0.13.189 ip-10-0-13-189.us-east-2.compute.internal <none> <none>
machine-config-daemon-zzdjq 2/2 Running 4 47h 10.0.61.98 ip-10-0-61-98.us-east-2.compute.internal <none> <none>
machine-config-nodes-crd-cleanup-29402346-4wgrx 0/1 Completed 0 47h <none> ip-10-0-44-17.us-east-2.compute.internal <none> <none>
machine-config-operator-5b66b667d4-mtmdm 2/2 Running 4 47h 10.130.0.29 ip-10-0-44-17.us-east-2.compute.internal <none> <none>
machine-config-server-bp7tj 1/1 Running 2 47h 10.0.13.189 ip-10-0-13-189.us-east-2.compute.internal <none> <none>
machine-config-server-dc7ph 1/1 Running 2 47h 10.0.44.17 ip-10-0-44-17.us-east-2.compute.internal <none> <none>
machine-config-server-fq2jm 1/1 Running 2 47h 10.0.10.165 ip-10-0-10-165.us-east-2.compute.internal <none> <none>
Degradedになっているノード上の動作が怪しいので、ip-10-0-11-138.us-east-2.compute.internalで動作しているmachine-config-daemon-2xh79のログを見てみることにします。
[lab-user@bastion machineconfig]$ oc logs -n openshift-machine-config-operator machine-config-daemon-2xh79 --tail 20
Defaulted container "machine-config-daemon" out of: machine-config-daemon, kube-rbac-proxy
I1128 06:52:26.340960 5494 update.go:2685] "Disk currentConfig \"rendered-worker-54bfb1db8c9874ddc358422b48d57485\" overrides node's currentConfig annotation \"rendered-worker-2bc1dfd10eba3b11a558e7b8edddd605\""
I1128 06:52:26.343826 5494 daemon.go:2264] Validating against current config rendered-worker-54bfb1db8c9874ddc358422b48d57485
I1128 06:52:26.343888 5494 daemon.go:2176] SSH key location ("/home/core/.ssh/authorized_keys.d/ignition") up-to-date!
I1128 06:52:26.343900 5494 command_runner.go:24] Running captured: rpm-ostree kargs
E1128 06:52:26.411981 5494 writer.go:231] Marking Degraded due to: "unexpected on-disk state validating against rendered-worker-54bfb1db8c9874ddc358422b48d57485: could not stat file \"/tmp/tmpfile\": lstat /tmp/tmpfile: no such file or directory"
I1128 06:53:26.416849 5494 daemon.go:2066] Running: /run/machine-config-daemon-bin/nmstatectl persist-nic-names --root / --kargs-out /tmp/nmstate-kargs1434092388 --cleanup
[2025-11-28T06:53:26Z INFO nmstatectl] Nmstate version: 2.2.54
[2025-11-28T06:53:26Z INFO nmstatectl::persist_nic] /etc/systemd/network/.nmstate-persist.stamp does not exist, no need to clean up
I1128 06:53:26.427723 5494 daemon.go:1654] Previous boot ostree-finalize-staged.service appears successful
I1128 06:53:26.427752 5494 daemon.go:1795] Current config: rendered-worker-2bc1dfd10eba3b11a558e7b8edddd605
I1128 06:53:26.427761 5494 daemon.go:1796] Desired config: rendered-worker-54bfb1db8c9874ddc358422b48d57485
I1128 06:53:26.427768 5494 daemon.go:1804] state: Degraded
I1128 06:53:26.427789 5494 update.go:2640] Running: rpm-ostree cleanup -r
Deployments unchanged.
I1128 06:53:26.486520 5494 update.go:2685] "Disk currentConfig \"rendered-worker-54bfb1db8c9874ddc358422b48d57485\" overrides node's currentConfig annotation \"rendered-worker-2bc1dfd10eba3b11a558e7b8edddd605\""
I1128 06:53:26.489342 5494 daemon.go:2264] Validating against current config rendered-worker-54bfb1db8c9874ddc358422b48d57485
I1128 06:53:26.489404 5494 daemon.go:2176] SSH key location ("/home/core/.ssh/authorized_keys.d/ignition") up-to-date!
I1128 06:53:26.489423 5494 command_runner.go:24] Running captured: rpm-ostree kargs
E1128 06:53:26.556733 5494 writer.go:231] Marking Degraded due to: "unexpected on-disk state validating against rendered-worker-54bfb1db8c9874ddc358422b48d57485: could not stat file \"/tmp/tmpfile\": lstat /tmp/tmpfile: no such file or directory"
[lab-user@bastion machineconfig]$
最終行にちょうどDegradedになった理由が書いてありました。 /tmp/tmpfile: no such file or directoryとのことです。
[lab-user@bastion machineconfig]$ oc debug node/ip-10-0-11-138.us-east-2.compute.internal -- chroot /host ls -lah /tmp/
Starting pod/ip-10-0-11-138us-east-2computeinternal-debug-n254s ...
To use host binaries, run `chroot /host`. Instead, if you need to access host namespaces, run `nsenter -a -t 1`.
total 4.0K
drwxrwxrwt. 11 root root 220 Nov 28 07:03 .
drwxr-xr-x. 12 root root 4.0K Jan 1 1970 ..
drwxrwxrwt. 2 root root 40 Nov 28 06:47 .ICE-unix
drwxrwxrwt. 2 root root 40 Nov 28 06:47 .X11-unix
drwxrwxrwt. 2 root root 40 Nov 28 06:47 .XIM-unix
drwxrwxrwt. 2 root root 40 Nov 28 06:47 .font-unix
drwx------. 3 root root 60 Nov 28 06:47 systemd-private-aaaf68eaa82747e08ca87549ac9732cb-chronyd.service-u7yTRz
drwx------. 3 root root 60 Nov 28 06:47 systemd-private-aaaf68eaa82747e08ca87549ac9732cb-dbus-broker.service-PMxhsC
drwx------. 3 root root 60 Nov 28 06:47 systemd-private-aaaf68eaa82747e08ca87549ac9732cb-irqbalance.service-VKrVQr
drwx------. 3 root root 60 Nov 28 06:48 systemd-private-aaaf68eaa82747e08ca87549ac9732cb-rpm-ostreed.service-mjDkMZ
drwx------. 3 root root 60 Nov 28 06:47 systemd-private-aaaf68eaa82747e08ca87549ac9732cb-systemd-logind.service-hjezOT
Removing debug pod ...
MachineConfigは新たな設定の適用時に、特定の条件の変更を除いて変更適用のためのリブート処理を行います。
今回追加したいファイルは/tmp/配下なのでmachine-config-daemonによって一度ファイルが配置されるものの、リブートのタイミングでファイルが消えてしまい、再起動後のmachine-config-daemonから見るとあるべき姿と一致しない、という状態が発生していることがDegradedの原因でした。
復旧させてみる
さて、切り戻しをしようとして投入したMachineConfigをdeleteしたので、現在のあるべき姿としては/tmp/tmpfileは別に無くても良いはずです。
しかしながら上記のログを見る限り、ノードから見たあるべき姿は/tmp/tmpfileがノードに存在している状態、ということになります。ノード、厳密に言えばノード上で動作するmachine-config-daemonはどこを参照してあるべき姿を定義しているのでしょうか。
ドキュメントを見てもそれらしい情報がなかったのでソースコードを直接確認したところ、/etc/machine-config-daemon/currentconfigであることが確認できました。
さっそく中身を確認してみましょう。
[lab-user@bastion machineconfig]$ oc debug node/ip-10-0-11-138.us-east-2.compute.internal -- chroot /host cat /etc/machine-config-daemon/currentconfig
Starting pod/ip-10-0-11-138us-east-2computeinternal-debug-m97lt ...
To use host binaries, run `chroot /host`. Instead, if you need to access host namespaces, run `nsenter -a -t 1`.
{"kind":"MachineConfig","apiVersion":"machineconfiguration.openshift.io/v1","metadata":{"name":"rendered-worker-54bfb1db8c9874ddc358422b48d57485","uid":"d1106696-4db9-4651-838b-58fc9102247a","resourceVersion":"233700","generation":1,"creationTimestamp":"2025-11-28T02:37:40Z","annotations":{"machineconfiguration.openshift.io/generated-by-controller-version":"0c58628362f7471071da6d0263fa65766691f28c","machineconfiguration.openshift.io/release-image-version":"4.20.4"},"ownerReferences":[{"apiVersion":"machineconfiguration.openshift.io/v1","kind":"MachineConfigPool","name":"worker","uid":"10f15d2b-342a-4406-8573-3306f397b211","controller":true,"blockOwnerDeletion":true}],"managedFields":[{"manager":"machine-config-controller","operation":"Update","apiVersion":"machineconfiguration.openshift.io/v1","time":"2025-11-28T02:37:40Z",
...snip...
Removing debug pod ...
無邪気にcatすると長大な1行のファイルが出てきますが、json形式のようなのでjqで整形して見てみましょう。
[lab-user@bastion machineconfig]$ oc debug node/ip-10-0-11-138.us-east-2.compute.internal -- chroot /host cat /etc/machine-config-daemon/currentconfig | jq . | head -n 10
Starting pod/ip-10-0-11-138us-east-2computeinternal-debug-9vlpc ...
To use host binaries, run `chroot /host`. Instead, if you need to access host namespaces, run `nsenter -a -t 1`.
Removing debug pod ...
{
"kind": "MachineConfig",
"apiVersion": "machineconfiguration.openshift.io/v1",
"metadata": {
"name": "rendered-worker-54bfb1db8c9874ddc358422b48d57485",
"uid": "d1106696-4db9-4651-838b-58fc9102247a",
"resourceVersion": "233700",
"generation": 1,
"creationTimestamp": "2025-11-28T02:37:40Z",
"annotations": {
なんだか見覚えがあるな…?
[lab-user@bastion machineconfig]$ oc get mc rendered-worker-54bfb1db8c9874ddc358422b48d57485 -o json | head -n 9
{
"apiVersion": "machineconfiguration.openshift.io/v1",
"kind": "MachineConfig",
"metadata": {
"annotations": {
"machineconfiguration.openshift.io/generated-by-controller-version": "0c58628362f7471071da6d0263fa65766691f28c",
"machineconfiguration.openshift.io/release-image-version": "4.20.4"
},
"creationTimestamp": "2025-11-28T02:37:40Z",
"generation": 1,
"name": "rendered-worker-54bfb1db8c9874ddc358422b48d57485",
"ownerReferences": [
{
"apiVersion": "machineconfiguration.openshift.io/v1",
"blockOwnerDeletion": true,
[lab-user@bastion machineconfig]$
そう、順番の違いと.metadata.managedFieldsの追加はありますがこれはほぼoc get mcで出力されるレンダリングされたrenderedファイルです。
ということはどうにかしてこれを元の設定に戻してあげたいですね。
今しがたさらっと述べた.metadata.managedFieldsを見てみると、このような設定が見えます。
[lab-user@bastion machineconfig]$ oc debug node/ip-10-0-11-138.us-east-2.compute.internal -- chroot /host cat /etc/machine-config-daemon/currentconfig | jq .metadata.managedFields
Starting pod/ip-10-0-11-138us-east-2computeinternal-debug-zb5rz ...
To use host binaries, run `chroot /host`. Instead, if you need to access host namespaces, run `nsenter -a -t 1`.
Removing debug pod ...
[
{
"manager": "machine-config-controller",
"operation": "Update",
"apiVersion": "machineconfiguration.openshift.io/v1",
"time": "2025-11-28T02:37:40Z",
"fieldsType": "FieldsV1",
"fieldsV1": {
"f:metadata": {
"f:annotations": {
".": {},
"f:machineconfiguration.openshift.io/generated-by-controller-version": {},
"f:machineconfiguration.openshift.io/release-image-version": {}
},
"f:ownerReferences": {
".": {},
"k:{\"uid\":\"10f15d2b-342a-4406-8573-3306f397b211\"}": {}
}
},
"f:spec": {
".": {},
...snip...
どうやらmachine-config-controllerがこのファイルを配っているようなのでログをちょっと見てみます。
[lab-user@bastion machineconfig]$ oc logs -n openshift-machine-config-operator machine-config-controller-587ff89599-pjcj5
...snip...
I1129 05:23:45.009999 1 event.go:377] Event(v1.ObjectReference{Kind:"MachineConfigPool", Namespace:"openshift-machine-config-operator", Name:"worker", UID:"10f15d2b-342a-4406-8573-3306f397b211", APIVersion:"machineconfiguration.openshift.io/v1", ResourceVersion:"373714", FieldPath:""}): type: 'Normal' reason: 'SetDesiredConfig' Targeted node ip-10-0-11-138.us-east-2.compute.internal to MachineConfig: rendered-worker-54bfb1db8c9874ddc358422b48d57485
...snip...
対象ノードのDesiredConfigを変更した、というようなログが出ていますが、ノードのDesiredConfigがどこに定義されているかというと、ここです。ノードのannotationに含まれているんですね。
[lab-user@bastion machineconfig]$ oc get node ip-10-0-11-138.us-east-2.compute.internal -o json | jq .metadata.annotations
{
...snip...
"machineconfiguration.openshift.io/currentConfig": "rendered-worker-2bc1dfd10eba3b11a558e7b8edddd605",
"machineconfiguration.openshift.io/desiredConfig": "rendered-worker-54bfb1db8c9874ddc358422b48d57485",
"machineconfiguration.openshift.io/desiredDrain": "drain-rendered-worker-54bfb1db8c9874ddc358422b48d57485",
"machineconfiguration.openshift.io/lastAppliedDrain": "drain-rendered-worker-54bfb1db8c9874ddc358422b48d57485",
...snip...
"machineconfiguration.openshift.io/reason": "unexpected on-disk state validating against rendered-worker-54bfb1db8c9874ddc358422b48d57485: could not stat file \"/tmp/tmpfile\": lstat /tmp/tmpfile: no such file or directory",
"machineconfiguration.openshift.io/state": "Degraded",
"volumes.kubernetes.io/controller-managed-attach-detach": "true"
}
ということは、このdesiredConfigを一旦editしちゃえばいいんじゃない?という雑な考えで書き換えてみましょう。エイヤ。
[lab-user@bastion machineconfig]$ oc get node ip-10-0-11-138.us-east-2.compute.internal -o yaml | grep -i config
cloud.network.openshift.io/egress-ipconfig: '[{"interface":"eni-0b33c94a6428cad5d","ifaddr":{"ipv4":"10.0.0.0/18"},"capacity":{"ipv4":29,"ipv6":30}}]'
k8s.ovn.org/l3-gateway-config: '{"default":{"mode":"shared","bridge-id":"br-ex","interface-id":"br-ex_ip-10-0-11-138.us-east-2.compute.internal","mac-address":"02:26:31:89:fa:c7","ip-addresses":["10.0.11.138/18"],"ip-address":"10.0.11.138/18","next-hops":["10.0.0.1"],"next-hop":"10.0.0.1","node-port-enable":"true","vlan-id":"0"}}'
machineconfiguration.openshift.io/controlPlaneTopology: HighlyAvailable
machineconfiguration.openshift.io/currentConfig: rendered-worker-2bc1dfd10eba3b11a558e7b8edddd605
machineconfiguration.openshift.io/desiredConfig: rendered-worker-2bc1dfd10eba3b11a558e7b8edddd605
machineconfiguration.openshift.io/desiredDrain: drain-rendered-worker-54bfb1db8c9874ddc358422b48d57485
machineconfiguration.openshift.io/lastAppliedDrain: drain-rendered-worker-54bfb1db8c9874ddc358422b48d57485
machineconfiguration.openshift.io/lastObservedServerCAAnnotation: "false"
machineconfiguration.openshift.io/lastSyncedControllerConfigResourceVersion: "370770"
machineconfiguration.openshift.io/post-config-action: ""
machineconfiguration.openshift.io/reason: 'unexpected on-disk state validating'
machineconfiguration.openshift.io/state: Degraded
[lab-user@bastion machineconfig]$ oc get node,mcp
NAME STATUS ROLES AGE VERSION
node/ip-10-0-10-165.us-east-2.compute.internal Ready control-plane,master 2d22h v1.33.5
node/ip-10-0-11-138.us-east-2.compute.internal Ready,SchedulingDisabled worker 2d22h v1.33.5
node/ip-10-0-13-189.us-east-2.compute.internal Ready control-plane,master 2d22h v1.33.5
node/ip-10-0-44-17.us-east-2.compute.internal Ready control-plane,master 2d22h v1.33.5
node/ip-10-0-61-247.us-east-2.compute.internal Ready worker 2d22h v1.33.5
node/ip-10-0-61-98.us-east-2.compute.internal Ready worker 2d22h v1.33.5
NAME CONFIG UPDATED UPDATING DEGRADED MACHINECOUNT READYMACHINECOUNT UPDATEDMACHINECOUNT DEGRADEDMACHINECOUNT AGE
machineconfigpool.machineconfiguration.openshift.io/master rendered-master-d868db98f6b40ee2e6719f5226faab58 True False False 3 3 3 0 2d22h
machineconfigpool.machineconfiguration.openshift.io/worker rendered-worker-2bc1dfd10eba3b11a558e7b8edddd605 False True True 3 2 2 1 2d22h
どうやらまだDegradedは解消されないようです。
再びmachine-config-daemonのログを見ると理由が書いてありました。
[lab-user@bastion machineconfig]$ oc logs -n openshift-machine-config-operator machine-config-daemon-2xh79
...snip...
I1129 05:40:21.935420 9699 update.go:2685] "Disk currentConfig \"rendered-worker-54bfb1db8c9874ddc358422b48d57485\" overrides node's currentConfig annotation \"rendered-worker-2bc1dfd10eba3b11a558e7b8edddd605\""
...snip...
ふむふむ、先程の/etc/machine-config-daemon/currentconfigの設定がnodeのannotationに記載されたcurrentConfigよりも優先されて状態が不一致になって止まっているため、その先のDesiredConfigを定義してももはや意味が無いそうです。万事休す。
じゃあどうすればよいの、という答えはこちらのKCSにあります。
How to skip validation of failing / stuck MachineConfig in OCP 4?
https://access.redhat.com/solutions/5414371
currentconfigを消して空にしてしまうか、/run/machine-config-daemon-forceをtouchすることで自動的に現状のconfigを一回適用済みとみなしてその先に進めるようになります。
ということで、/run/machine-config-daemon-forceを適用してみましょう。
[lab-user@bastion machineconfig]$ oc debug node/ip-10-0-11-138.us-east-2.compute.internal -- chroot /host touch /run/machine-config-daemon-force
Starting pod/ip-10-0-11-138us-east-2computeinternal-debug-vt79k ...
To use host binaries, run `chroot /host`. Instead, if you need to access host namespaces, run `nsenter -a -t 1`
Removing debug pod ...
なお、このタイミングでノードがSchedulingDisabledのままだとmachine-config-daemon podが再起動できずにCrashLoopBackOffに陥ります。oc adm uncordonを実施しましょう。
[lab-user@bastion machineconfig]$ oc adm uncordon ip-10-0-11-138.us-east-2.compute.internal
node/ip-10-0-11-138.us-east-2.compute.internal uncordoned
なんとか最終的に元の状態に戻すことができました。
[lab-user@bastion machineconfig]$ oc get mcp
NAME CONFIG UPDATED UPDATING DEGRADED MACHINECOUNT READYMACHINECOUNT UPDATEDMACHINECOUNT DEGRADEDMACHINECOUNT AGE
master rendered-master-d868db98f6b40ee2e6719f5226faab58 True False False 3 3 3 0 2d22h
worker rendered-worker-2bc1dfd10eba3b11a558e7b8edddd605 True False False 3 3 3 0 2d22h
ちなみに今回の場合は変更後の変更内容が存在せず、実質的なノードの状態としては以前のMachineConfigと同一の状態となっているためこの方法で切り戻しても問題ありませんが、変更した内容によってはノードの状態が既に書き換えられている可能性があるので、変更された内容が把握できていない場合にこのような切り戻しをすることはあまりオススメしません。
目指せ人間MCO
長過ぎる前置きを終えて長過ぎる本題に入りたいと思います。
先の例で使ったMachineConfigの代わりに、今度は下記のMacineConfigを適用することを考えます。
ファイルの生成先パスを変えただけです。
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
metadata:
labels:
machineconfiguration.openshift.io/role: worker
name: 99-worker-add-mc-test
spec:
config:
ignition:
version: 3.5.0
storage:
files:
- mode: 420
overwrite: false
path: /usr/local/bin/mc-test
このMachineConfigを人力で適用して、MCOに気付かれなければ成功です。
MachineConfigOperator上のmachine-config-controller/machine-config-server/machine-config-daemonにはお休みしてもらいましょう。
[lab-user@bastion humanmco-test]$ oc scale -n openshift-machine-config-operator deployment.apps/machine-config-controller --replicas=0
Warning: spec.template.spec.nodeSelector[node-role.kubernetes.io/master]: use "node-role.kubernetes.io/control-plane" instead
deployment.apps/machine-config-controller scaled
[lab-user@bastion humanmco-test]$ oc -n openshift-machine-config-operator patch daemonset machine-config-server -p '{"spec": {"template": {"spec": {"nodeSelector": {"non-existing": "true"}}}}}'
Warning: spec.template.spec.nodeSelector[node-role.kubernetes.io/master]: use "node-role.kubernetes.io/control-plane" instead
daemonset.apps/machine-config-server patched
[lab-user@bastion humanmco-test]$ oc -n openshift-machine-config-operator patch daemonset machine-config-daemon -p '{"spec": {"template": {"spec": {"nodeSelector": {"non-existing": "true"}}}}}'
daemonset.apps/machine-config-daemon patched
[lab-user@bastion humanmco-test]$ oc get pod -n openshift-machine-config-operator
NAME READY STATUS RESTARTS AGE
kube-rbac-proxy-crio-ip-10-0-10-165.us-east-2.compute.internal 1/1 Running 9 4d21h
kube-rbac-proxy-crio-ip-10-0-13-189.us-east-2.compute.internal 1/1 Running 9 4d21h
kube-rbac-proxy-crio-ip-10-0-14-22.us-east-2.compute.internal 1/1 Running 7 12h
kube-rbac-proxy-crio-ip-10-0-40-69.us-east-2.compute.internal 1/1 Running 6 12h
kube-rbac-proxy-crio-ip-10-0-44-17.us-east-2.compute.internal 1/1 Running 9 4d21h
kube-rbac-proxy-crio-ip-10-0-61-98.us-east-2.compute.internal 1/1 Running 16 4d20h
machine-config-nodes-crd-cleanup-29402346-4wgrx 0/1 Completed 0 4d21h
machine-config-operator-5b66b667d4-mtmdm 2/2 Running 12 4d21h
まず、今回のMachineConfigを適用することで新たに生成されるはずのrenderedファイルを作成します。普段は自動で生成されるCRです。
適用するMachineConfigはworkerが対象なので、workerのMachineConfigPoolに現在適用されているrenderedファイルを確認します。
[lab-user@bastion humanmco-test]$ oc get mcp worker
NAME CONFIG UPDATED UPDATING DEGRADED MACHINECOUNT READYMACHINECOUNT UPDATEDMACHINECOUNT DEGRADEDMACHINECOUNT AGE
worker rendered-worker-2bc1dfd10eba3b11a558e7b8edddd605 True False False 3 3 3 0 4d21h
renderedファイルをyaml形式で取得します。
[lab-user@bastion humanmco-test]$ oc get mc rendered-worker-2bc1dfd10eba3b11a558e7b8edddd605 -o yaml > rendered-worker-2bc1dfd10eba3b11a558e7b8edddd605.yaml
コピーして編集します。
[lab-user@bastion humanmco-test]$ cp rendered-worker-2bc1dfd10eba3b11a558e7b8edddd605.yaml new-rendered-mc.yaml
[lab-user@bastion humanmco-test]$ vi new-rendered-mc.yaml
[lab-user@bastion humanmco-test]$ diff rendered-worker-2bc1dfd10eba3b11a558e7b8edddd605.yaml new-rendered-mc.yaml
9c9
< name: rendered-worker-2bc1dfd10eba3b11a558e7b8edddd605
---
> name: rendered-worker-b13c0797871dd0befef5e24d34172a31
267a268,270
> - mode: 420
> overwrite: false
> path: /usr/local/bin/mc-test
変更箇所は2点、新たに追加するMachineConfigの設定内容を追加し、CRの名前を変更しました。
なんかいきなりハッシュ値出てきたな、とお思いかもしれませんが、CRの名前に使うハッシュ値は下記で計算されます。
https://github.com/openshift/machine-config-operator/blob/release-4.20/pkg/controller/render/hash.go
config内のspec部分にmachineconfigのsalt文字列を加えてmd5のハッシュを計算すればよいのですが、configの形式がgoのオブジェクト形式にデシリアライズされたものなので容易に計算できるものではないです。やる必要も無いですしやる人はいないと思いますが、上記のソースコードを元に別途yamlからハッシュ値を計算するgoスクリプトを書くことで今回は対応しました。
// main.go
package main
import (
//nolint:gosec
"crypto/md5"
"fmt"
"os"
"github.com/ghodss/yaml"
"k8s.io/apimachinery/pkg/runtime/serializer/json"
"k8s.io/apimachinery/pkg/runtime/schema"
mcfgv1 "github.com/openshift/api/machineconfiguration/v1"
"k8s.io/client-go/kubernetes/scheme"
yamlutil "k8s.io/apimachinery/pkg/runtime/serializer/yaml"
)
var (
// salt is 80 random bytes.
// The salt was generated by `od -vAn -N80 -tu1 < /dev/urandom`. Do not change it.
salt = []byte{
16, 124, 206, 228, 139, 56, 175, 175, 79, 229, 134, 118, 157, 154, 211, 110,
25, 93, 47, 253, 172, 106, 37, 7, 174, 13, 160, 185, 110, 17, 87, 52,
219, 131, 12, 206, 218, 141, 116, 135, 188, 181, 192, 151, 233, 62, 126, 165,
64, 83, 179, 119, 15, 168, 208, 197, 146, 107, 58, 227, 133, 188, 238, 26,
33, 26, 235, 202, 32, 173, 31, 234, 41, 144, 148, 79, 6, 206, 23, 22,
}
)
func hashData(data []byte) ([]byte, error) {
//nolint:gosec
hasher := md5.New()
if _, err := hasher.Write(salt); err != nil {
return nil, fmt.Errorf("error computing hash: %w", err)
}
if _, err := hasher.Write(data); err != nil {
return nil, fmt.Errorf("error computing hash: %w", err)
}
return hasher.Sum(nil), nil
}
// Given a config from a pool, generate a name for the config
// of the form rendered-<poolname>-<hash>
func main() {
mcfgv1.AddToScheme(scheme.Scheme)
jsonSerializer := json.NewSerializerWithOptions(
json.SimpleMetaFactory{},
nil,
scheme.Scheme,
json.SerializerOptions{},
)
yamlDecoder := yamlutil.NewDecodingSerializer(jsonSerializer)
yamlFile := os.Args[1]
config, err := os.ReadFile(yamlFile)
if err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
gvk := schema.GroupVersionKind{
Group: "machineconfiguration.openshift.io",
Version: "v1",
Kind: "MachineConfig",
}
obj := &mcfgv1.MachineConfig{}
_, _, err = yamlDecoder.Decode(config, &gvk, obj)
if err != nil {
fmt.Printf("Error decoding YAML to MachineConfig: %v\n", err)
os.Exit(1)
}
data, err := yaml.Marshal(obj.Spec)
if err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
h, err := hashData(data)
if err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
fmt.Printf("rendered-worker-%x\n", h)
}
[lab-user@bastion mco-hasher]$ go build -o machine-hasher main.go
[lab-user@bastion mco-hasher]$ ./machine-hasher ../humanmco-test/new-rendered-mc.yaml
rendered-worker-b13c0797871dd0befef5e24d34172a31
生成したrenderedファイルと元のMachineConfigファイルを適用します。MCOがお休み中なのでCRを生成してもMCPなどに変化は発生しません。
[lab-user@bastion humanmco-test]$ oc apply -f 99-worker-add-mc-test.yaml
machineconfig.machineconfiguration.openshift.io/99-worker-add-mc-test created
[lab-user@bastion humanmco-test]$ oc apply -f new-rendered-mc.yaml
machineconfig.machineconfiguration.openshift.io/rendered-worker-b13c0797871dd0befef5e24d34172a31 created
[lab-user@bastion humanmco-test]$ oc get mc
NAME GENERATEDBYCONTROLLER IGNITIONVERSION AGE
00-master 0c58628362f7471071da6d0263fa65766691f28c 3.5.0 4d21h
00-worker 0c58628362f7471071da6d0263fa65766691f28c 3.5.0 4d21h
01-master-container-runtime 0c58628362f7471071da6d0263fa65766691f28c 3.5.0 4d21h
01-master-kubelet 0c58628362f7471071da6d0263fa65766691f28c 3.5.0 4d21h
01-worker-container-runtime 0c58628362f7471071da6d0263fa65766691f28c 3.5.0 4d21h
01-worker-kubelet 0c58628362f7471071da6d0263fa65766691f28c 3.5.0 4d21h
97-master-generated-kubelet 0c58628362f7471071da6d0263fa65766691f28c 3.5.0 4d21h
97-worker-generated-kubelet 0c58628362f7471071da6d0263fa65766691f28c 3.5.0 4d21h
98-master-generated-kubelet 0c58628362f7471071da6d0263fa65766691f28c 3.5.0 4d21h
98-worker-generated-kubelet 0c58628362f7471071da6d0263fa65766691f28c 3.5.0 4d21h
99-master-generated-registries 0c58628362f7471071da6d0263fa65766691f28c 3.5.0 4d21h
99-master-ssh 3.2.0 4d21h
99-worker-add-mc-test 3.5.0 13s
99-worker-generated-registries 0c58628362f7471071da6d0263fa65766691f28c 3.5.0 4d21h
99-worker-ssh 3.2.0 4d21h
rendered-master-d868db98f6b40ee2e6719f5226faab58 0c58628362f7471071da6d0263fa65766691f28c 3.5.0 4d21h
rendered-worker-2bc1dfd10eba3b11a558e7b8edddd605 0c58628362f7471071da6d0263fa65766691f28c 3.5.0 3d2h
rendered-worker-3185bc599fe45dfa55589eb49fb732a5 0c58628362f7471071da6d0263fa65766691f28c 3.5.0 4d21h
rendered-worker-54bfb1db8c9874ddc358422b48d57485 0c58628362f7471071da6d0263fa65766691f28c 3.5.0 37h
rendered-worker-b13c0797871dd0befef5e24d34172a31 0c58628362f7471071da6d0263fa65766691f28c 3.5.0 8s
[lab-user@bastion humanmco-test]$ oc get mcp
NAME CONFIG UPDATED UPDATING DEGRADED MACHINECOUNT READYMACHINECOUNT UPDATEDMACHINECOUNT DEGRADEDMACHINECOUNT AGE
master rendered-master-d868db98f6b40ee2e6719f5226faab58 True False False 3 3 3 0 4d21h
worker rendered-worker-2bc1dfd10eba3b11a558e7b8edddd605 True False False 3 3 3 0 4d21h
ノード上のcurrentconfigを置き換えるためのファイルも作っておきます。
差分となる.metadata.managedFieldsの情報も元のcurrentconfigから流用してしまいましょう。新規のrenderedのjsonファイルが持つ値があればそれで上書きを行いますが、kubectl.kubernetes.io/last-applied-configurationのannotationだけは不要なので消しておきます。また、.metadata.managedFields[0].timeの項目は元のcurrentconfig側にしかありませんが、ここはrendered machineconfig CRの時刻情報と一致させたいのでここも別途上書きしておきます。
[lab-user@bastion humanmco-test]$ oc debug node/ip-10-0-14-22.us-east-2.compute.internal -- chroot /host cat /etc/machine-config-daemon/currentconfig > currentconfig.json
Starting pod/ip-10-0-14-22us-east-2computeinternal-debug-c69fm ...
To use host binaries, run `chroot /host`. Instead, if you need to access host namespaces, run `nsenter -a -t 1`.
Removing debug pod ...
[lab-user@bastion humanmco-test]$ oc get mc rendered-worker-b13c0797871dd0befef5e24d34172a31 -o json > rendered-worker-b13c0797871dd0befef5e24d34172a31.json
[lab-user@bastion humanmco-test]$ jq -s '.[0] * .[1]' currentconfig.json rendered-worker-b13c0797871dd0befef5e24d34172a31.json | jq 'del(.metadata.annotations["kubectl.kubernetes.io/last-applied-configuration"])' | jq '.metadata.managedFields[0].time = .metadata.creationTimestamp' > new-currentconfig.json
[lab-user@bastion humanmco-test]$ cat new-currentconfig.json | jq . -c > new-currentconfig.txt
次に3台のwoker node側を手作業で変更しましょう。
[lab-user@bastion humanmco-test]$ oc debug node/ip-10-0-14-22.us-east-2.compute.internal
Starting pod/ip-10-0-14-22us-east-2computeinternal-debug-j4r4r ...
To use host binaries, run `chroot /host`. Instead, if you need to access host namespaces, run `nsenter -a -t 1`.
Pod IP: 10.0.14.22
If you don\'t see a command prompt, try pressing enter.
sh-5.1# chroot /host
sh-5.1# touch /usr/local/bin/mc-test
sh-5.1# ls -lah /usr/local/bin/mc-test
-rw-r--r--. 1 root root 0 Dec 1 04:31 /usr/local/bin/mc-test
sh-5.1# cd /etc/machine-config-daemon/
sh-5.1# mv currentconfig currentconfig.bak
debugセッションを維持したまま別画面でcurrentconfigを転送します。
[lab-user@bastion humanmco-test]$ oc get pod
NAME READY STATUS RESTARTS AGE
ip-10-0-11-138us-east-2computeinternal-debug-sqs8h 1/1 Running 0 41s
[lab-user@bastion humanmco-test]$ oc cp ./new-currentconfig.txt ip-10-0-11-138us-east-2computeinternal-debug-sqs8h:/host/etc/machine-config-daemon/currentconfig -c container-00
[lab-user@bastion humanmco-test]$ oc debug node/ip-10-0-11-138.us-east-2.compute.internal -- chroot /host chown root:root /etc/machine-config-daemon/currentconfig
Starting pod/ip-10-0-11-138us-east-2computeinternal-debug-68shh ...
To use host binaries, run `chroot /host`. Instead, if you need to access host namespaces, run `nsenter -a -t 1`.
Removing debug pod ...
残り2台のノードも同様に実施します。
最後に、各ノードのannotationのcurrentConfigとdesiredConfig、MachineConfigPoolの.spec.configuration.nameを新しいMachineConfigに変更しておきます。
[lab-user@bastion humanmco-test]$ oc get node --no-headers | grep worker | awk '{print $1}' | while read node; do oc annotate node ${node} --overwrite machineconfiguration.openshift.io/currentConfig=rendered-worker-b13c0797871dd0befef5e24d34172a31; oc annotate node ${node} --overwrite machineconfiguration.openshift.io/desiredConfig=rendered-worker-b13c0797871dd0befef5e24d34172a31; done
node/ip-10-0-14-22.us-east-2.compute.internal annotated
node/ip-10-0-14-22.us-east-2.compute.internal annotated
node/ip-10-0-40-69.us-east-2.compute.internal annotated
node/ip-10-0-40-69.us-east-2.compute.internal annotated
node/ip-10-0-61-98.us-east-2.compute.internal annotated
node/ip-10-0-61-98.us-east-2.compute.internal annotated
[lab-user@bastion humanmco-test]$ oc patch mcp worker -p '{"spec":{"configuration":{"name":"rendered-worker-b13c0797871dd0befef5e24d34172a31"}}}' --type merge
machineconfigpool.machineconfiguration.openshift.io/worker patched
これで全ての変更は実施したはずです。
まだMCPの状態に変化は見えていません。
[lab-user@bastion humanmco-test]$ oc get node,mcp
NAME STATUS ROLES AGE VERSION
node/ip-10-0-10-165.us-east-2.compute.internal Ready control-plane,master 4d21h v1.33.5
node/ip-10-0-13-189.us-east-2.compute.internal Ready control-plane,master 4d21h v1.33.5
node/ip-10-0-14-22.us-east-2.compute.internal Ready worker 13h v1.33.5
node/ip-10-0-40-69.us-east-2.compute.internal Ready worker 13h v1.33.5
node/ip-10-0-44-17.us-east-2.compute.internal Ready control-plane,master 4d21h v1.33.5
node/ip-10-0-61-98.us-east-2.compute.internal Ready worker 4d21h v1.33.5
NAME CONFIG UPDATED UPDATING DEGRADED MACHINECOUNT READYMACHINECOUNT UPDATEDMACHINECOUNT DEGRADEDMACHINECOUNT AGE
machineconfigpool.machineconfiguration.openshift.io/master rendered-master-d868db98f6b40ee2e6719f5226faab58 True False False 3 3 3 0 4d21h
machineconfigpool.machineconfiguration.openshift.io/worker rendered-worker-2bc1dfd10eba3b11a558e7b8edddd605 True False False 3 3 3 0 4d21h
machine-config-controller/machine-config-server/machine-config-daemonに戻ってきてもらいましょう。
[lab-user@bastion humanmco-test]$ oc -n openshift-machine-config-operator patch daemonset machine-config-daemon --type json -p='[{"op": "remove", "path": "/spec/template/spec/nodeSelector/non-existing"}]'
[lab-user@bastion humanmco-test]$ oc -n openshift-machine-config-operator patch daemonset machine-config-server --type json -p='[{"op": "remove", "path": "/spec/template/spec/nodeSelector/non-existing"}]'
[lab-user@bastion humanmco-test]$ oc scale -n openshift-machine-config-operator deployment.apps/machine-config-controller --replicas=1
[lab-user@bastion humanmco-test]$ oc get pod -n openshift-machine-config-operator
NAME READY STATUS RESTARTS AGE
kube-rbac-proxy-crio-ip-10-0-10-165.us-east-2.compute.internal 1/1 Running 9 4d21h
kube-rbac-proxy-crio-ip-10-0-13-189.us-east-2.compute.internal 1/1 Running 9 4d21h
kube-rbac-proxy-crio-ip-10-0-14-22.us-east-2.compute.internal 1/1 Running 7 13h
kube-rbac-proxy-crio-ip-10-0-40-69.us-east-2.compute.internal 1/1 Running 6 13h
kube-rbac-proxy-crio-ip-10-0-44-17.us-east-2.compute.internal 1/1 Running 9 4d21h
kube-rbac-proxy-crio-ip-10-0-61-98.us-east-2.compute.internal 1/1 Running 16 4d21h
machine-config-controller-587ff89599-ghht4 2/2 Running 0 85s
machine-config-daemon-4dnsw 2/2 Running 0 108s
machine-config-daemon-5cwhm 2/2 Running 0 108s
machine-config-daemon-qwsjg 2/2 Running 0 108s
machine-config-daemon-rstzn 2/2 Running 0 108s
machine-config-daemon-ss4sk 2/2 Running 0 108s
machine-config-daemon-xcs5c 2/2 Running 0 108s
machine-config-nodes-crd-cleanup-29402346-4wgrx 0/1 Completed 0 4d21h
machine-config-operator-5b66b667d4-mtmdm 2/2 Running 12 4d21h
machine-config-server-8m4m2 1/1 Running 0 94s
machine-config-server-gps56 1/1 Running 0 94s
machine-config-server-kw46d 1/1 Running 0 94s
すると無事、rebootすることなくMachineConfigPoolのCONFIG列が新しいMachineConfigに切り替わりました。
[lab-user@bastion humanmco-test]$ oc get node,mcp
NAME STATUS ROLES AGE VERSION
node/ip-10-0-10-165.us-east-2.compute.internal Ready control-plane,master 4d21h v1.33.5
node/ip-10-0-13-189.us-east-2.compute.internal Ready control-plane,master 4d21h v1.33.5
node/ip-10-0-14-22.us-east-2.compute.internal Ready worker 13h v1.33.5
node/ip-10-0-40-69.us-east-2.compute.internal Ready worker 13h v1.33.5
node/ip-10-0-44-17.us-east-2.compute.internal Ready control-plane,master 4d21h v1.33.5
node/ip-10-0-61-98.us-east-2.compute.internal Ready worker 4d21h v1.33.5
NAME CONFIG UPDATED UPDATING DEGRADED MACHINECOUNT READYMACHINECOUNT UPDATEDMACHINECOUNT DEGRADEDMACHINECOUNT AGE
machineconfigpool.machineconfiguration.openshift.io/master rendered-master-d868db98f6b40ee2e6719f5226faab58 True False False 3 3 3 0 4d21h
machineconfigpool.machineconfiguration.openshift.io/worker rendered-worker-b13c0797871dd0befef5e24d34172a31 True False False 3 3 3 0 4d21h
machine-config-controllerのログにもUpdateが完了した旨が記録されています。
[lab-user@bastion humanmco-test]$ oc logs -n openshift-machine-config-operator machine-config-controller-587ff89599-ghht4 | grep rendered-worker-b13c0797871dd0befef5e24d34172a31
Defaulted container "machine-config-controller" out of: machine-config-controller, kube-rbac-proxy
I1201 04:36:55.732802 1 status.go:273] Pool worker: All nodes are updated with MachineConfig rendered-worker-b13c0797871dd0befef5e24d34172a31
I1201 04:36:55.744285 1 event.go:377] Event(v1.ObjectReference{Kind:"MachineConfigPool", Namespace:"openshift-machine-config-operator", Name:"worker", UID:"10f15d2b-342a-4406-8573-3306f397b211", APIVersion:"machineconfiguration.openshift.io/v1", ResourceVersion:"779354", FieldPath:""}): type: 'Normal' reason: 'Completed' Pool worker has completed update to MachineConfig rendered-worker-b13c0797871dd0befef5e24d34172a31
I1201 04:37:00.756062 1 status.go:273] Pool worker: All nodes are updated with MachineConfig rendered-worker-b13c0797871dd0befef5e24d34172a31
まとめ
ということで、今回はOpenShiftの根幹機能の一つであるMachineConfigOperatorがどのように設定を管理し、変更を投入していくのかを自分の手で確認してみました。
なお、手作業と言うからにはgoは使わずにbashだけで頑張るつもりだったんですが、ハッシュの計算だけはどう頑張ってもできませんでした…
コンテナだけでなくそれをホストするノードやクラスタ自身もこのような形でk8sの宣言的な設定を利用して自動的に管理してくれるのがOpenShiftのいいところの一つですね。
明日のOpenShift Advent Calendar 2025 三日目は@tawatanaさんの"1サーバでOpenShiftの構築検証をする(Virtもできるよ)"話です、お楽しみに!