From 980d43eec23e71430e44b36128d0668fc4a45025 Mon Sep 17 00:00:00 2001 From: David Date: Wed, 26 Feb 2025 15:53:19 -0500 Subject: [PATCH 1/9] initial draft for default-on boot image updates --- .../machine-config/manage-boot-images.md | 147 +++++++++++++++--- .../manage_boot_images_flow.jpg | Bin 59490 -> 0 bytes .../manage_boot_images_reconcile_loop.jpg | Bin 99433 -> 0 bytes 3 files changed, 126 insertions(+), 21 deletions(-) delete mode 100644 enhancements/machine-config/manage_boot_images_flow.jpg delete mode 100644 enhancements/machine-config/manage_boot_images_reconcile_loop.jpg diff --git a/enhancements/machine-config/manage-boot-images.md b/enhancements/machine-config/manage-boot-images.md index 5694455de5..8b9847a55b 100644 --- a/enhancements/machine-config/manage-boot-images.md +++ b/enhancements/machine-config/manage-boot-images.md @@ -13,7 +13,7 @@ approvers: api-approvers: - "@joelspeed" creation-date: 2023-10-16 -last-updated: 2024-03-08 +last-updated: 2025-02-26 tracking-link: - https://issues.redhat.com/browse/MCO-589 see-also: @@ -27,7 +27,7 @@ superseded-by: ## Summary -This is a proposal to manage bootimages via the `Machine Config Operator`(MCO), leveraging some of the [pre-work](https://github.com/openshift/installer/pull/4760) done as a result of the discussion in [#201](https://github.com/openshift/enhancements/pull/201). This feature will only target standalone OCP installs. It will also be user opt-in and is planned to be released behind a feature gate. +This is a proposal to manage bootimages via the `Machine Config Operator`(MCO), leveraging some of the [pre-work](https://github.com/openshift/installer/pull/4760) done as a result of the discussion in [#201](https://github.com/openshift/enhancements/pull/201). This feature will only target standalone OCP installs. This is now released as an opt-in feature and will be rolled out on a per-platform basis (see projected roadmap). This will eventually be on by default, and the MCO will enforce an accepted skew and require non-platform managed bootimage updates to be acknowledged by the cluster admin. For `MachineSet` managed clusters, the end goal is to create an automated mechanism that can: - update the boot images references in `MachineSets` to the latest in the payload image @@ -47,7 +47,11 @@ Additionally, the stub Ignition config [referenced](https://github.com/openshift There has been [a previous effort](https://github.com/openshift/machine-config-operator/pull/1792) to manage the stub Ignition config. It was [reverted](https://github.com/openshift/machine-config-operator/pull/2126) and then [brought back](https://github.com/openshift/machine-config-operator/pull/2827#issuecomment-996156872) just for bare metal clusters. For other platforms, the `*-managed` stubs still get generated by the MCO, but are not injected into the `MachineSet`. The proposal plans to utilize these unused `*-managed` stubs, but it is important to note that this stub is generated(and synced) by the MCO and will ignore/override any user customizations to the original stub Ignition config. This limitation will be mentioned in the documentation, and a later release will provide support for user customization of the stub, either via API or a workaround thorugh additional documentation. This should not be an issue for the majority of users as they very rarely customize the original stub Ignition config. -In certain long lived clusters, the MCS TLS cert contained within the above Ignition configuration may be out of date. Example issue [here](https://issues.redhat.com/browse/OCPBUGS-1817). While this has been partly solved [MCO-642](https://issues.redhat.com/browse/MCO-642) (which allows the user to manually rotate the cert) it would be very beneficial for the MCO to actively manage this TLS cert and take this concern away from the user. +In certain long lived clusters, the MCS TLS cert contained within the above Ignition configuration may be out of date. Example issue [here](https://issues.redhat.com/browse/OCPBUGS-1817). While this has been partly solved [MCO-642](https://issues.redhat.com/browse/MCO-642) (which allows the user to manually rotate the cert) it would be very beneficial for the MCO to actively manage this TLS cert and take this concern away from the user. + +**Note**: As of 4.19, the MCO supports [management of this TLS cert](https://issues.redhat.com/browse/MCO-1208). With this work in place, the MCO can now attempt to upgrade the stub Ignition config, instead of hardcoding to the `*-managed` stub as mentioned previously. This will help preserve any user customizations that were present in the stub Ignition config. + +This is also a soft pre-requisite for both dual-stream RHEL support in OpenShift, and on-cluster layered builds. RPM-OSTree presently does a deploy-from-self to get a new-enough rpm-ostree to deploy image-based RHEL CoreOS systems, and we would like to avoid doing this for bootc if possible. We would also like to prevent RHEL8->RHEL10 direct updates once that is available for OpenShift. ### User Stories @@ -59,7 +63,7 @@ In certain long lived clusters, the MCS TLS cert contained within the above Igni The MCO will take over management of the boot image references and the stub Ignition configuration. The installer is still responsible for creating the `MachineSet` at cluster bring-up, but once cluster installation is complete the MCO will ensure that boot images are in sync with the latest payload. From the user standpoint, this should cause less compatibility issues as nodes will no longer need to pivot to a different version of RHCOS during node scaleup. -This should not interfere with existing workflows such as Hive and ArgoCD. As this is an opt-in mechanism, the cluster admin will be protected against such scenarios of accidental "reconciliation" and for additional safety, the MSBIC will also ensure that machinesets that have a valid OwnerReference will be excluded from boot image updates. +This should not interfere with existing workflows such as Hive and ArgoCD. As this is an opt-in mechanism, the cluster admin will be protected against such scenarios of accidental "reconciliation" and for additional safety, the MSBIC will also ensure that machinesets that have a valid OwnerReference will be excluded from boot image updates. We will work with affected teams to transition them to the new workflow before we turn this feature on by default. ### Non-Goals @@ -77,7 +81,7 @@ __Overview__ - `ManagedBootImages` feature gate is active - The cluster and/or the machineset is opted-in to boot image updates. This is done at the operator level, via the `MachineConfiguration` API object. - The `machineset` does not have a valid owner reference. Having a valid owner reference typically indicates that the `MachineSet` is managed by another workflow, and that updates to it are likely going to cause thrashing. - - The golden configmap is verified to be in sync with the current version of the MCO. The MCO will update("stamp") the golden configmap with version of the new MCO image after atleast 1 master node has succesfully completed an update to the new OCP image. This helps prevent `machinesets` being updated too soon at the end of a cluster upgrade, before the MCO itself has updated and has had a chance to roll out the new OCP image to the cluster. + - The golden configmap is verified to be in sync with the current version of the MCO. The MCO will update("stamp") the golden configmap with version of the new MCO image after at least 1 master node has succesfully completed an update to the new OCP image. This helps prevent `machinesets` being updated too soon at the end of a cluster upgrade, before the MCO itself has updated and has had a chance to roll out the new OCP image to the cluster. If any of the above checks fail, the MSBIC will exit out of the sync. - Based on platform and architecture type, the MSBIC will check if the boot images referenced in the `providerSpec` field of the `MachineSet` is the same as the one in the ConfigMap. Each platform(gcp, aws...and so on) does this differently, so this part of the implementation will have to be special cased. The ConfigMap is considered to be the golden set of bootimage values, i.e. they will never go out of date. If it is not a match, the `providerSpec` field is cloned and updated with the new boot image reference. @@ -115,23 +119,37 @@ Any form factor using the MCO and `MachineSets` will be impacted by this proposa ##### Supported platforms -The initial release(phase 0) will support GCP. In future releases, we will add in support for remaining platforms as we gain confidence in the functionality and understand the specific needs of those platforms. For platforms that cannot be supported, we aim to atleast provide documentation to perform the boot image updates manually. Here is an exhaustive list of all the platforms: +The initial release(phase 0) will support GCP. In future releases, we will add in support for remaining platforms as we gain confidence in the functionality and understand the specific needs of those platforms. For platforms that cannot be supported, we aim to at least provide documentation to perform the boot image updates manually. Here is an exhaustive list of all the platforms: -- gcp - aws - azure -- alibabacloud +- baremetal +- gcp +- ibmcloud - nutanix -- powervs - openstack +- powervs - vsphere -- baremetal -- libvirt -- ovirt -- ibmcloud This work will be tracked in [MCO-793](https://issues.redhat.com/browse/MCO-793). +##### Projected timeline + +This is a tentative timeline, subject to change (GA = General Availability, TP = Tech Preview, EF = Default-on, Skew Enforced). + +| Platform | TP | GA | EF | +| -------- | ------- | ------- | ------- | +| gcp | 4.16 |4.17 |4.19 | +| aws | 4.17 |4.18 |4.20 | +| vsphere | 4.20 |4.21 |4.22 | +| baremetal| |4.22 |4.23 | +| openstack| |4.22 |4.23 | +| nutanix | |4.22 |4.23 | +| ibmcloud | |4.24 |4.25 | +| non-managed* | |4.21 |4.22 | + +*non-managed in this case indicates enforcement of user-initiated bootimage updates. See enforcement section below. + ##### Cluster API backed machinesets As the Cluster API move is impending(initial release in 4.16 and default-on release in 4.17), it is necessary that this enhancement plans for the changes required in an CAPI backed cluster. Here are a couple of sample YAMLs used in CAPI backed `Machinesets`, from the [official Openshift documentation](https://docs.openshift.com/container-platform/4.14/machine_management/capi-machine-management.html#capi-sample-yaml-files-gcp). @@ -208,7 +226,9 @@ Much of the existing design regarding architecture & platform detection, opt-in, This proposal introduces a new field in the MCO operator API, `ManagedBootImages` which encloses an array of `MachineManager` objects. A `MachineManager` object contains the resource type of the machine management object that is being opted-in, the API group of that object and a union discriminant object of the type `MachineManagerSelector`. This object `MachineManagerSelector` contains: - The union discriminator, `Mode`, can be set to two values : All and Partial. -- Partial: This is a set of label selectors that will be used by users to opt-in a custom selection of machine resources. When the Mode is set to Partial mode, all machinesets matched by this object would be considered enrolled for updates. In the first iteration of this API, this object will only allow for label matching with MachineResources. In the future, additional ways of filtering may be added with another label selector, e.g. namespace. For all other values of Mode, this selector object i + - **All**: All machine resources described by this resource/apiGroup type will be opted-in for boot image updates. In most cases, this effectively enables boot image updates for the whole cluster, unless there are multiple kinds of machine resources present in the cluster. + - **Partial**: This is a set of label selectors that will be used by users to opt-in a custom selection of machine resources. When the Mode is set to Partial mode, all machinesets matched by this object would be considered enrolled for updates. In the first iteration of this API, this object will only allow for label matching with MachineResources. In the future, additional ways of filtering may be added with another label selector, e.g. namespace. + ``` type ManagedBootImages struct { @@ -473,23 +493,108 @@ The goal of this is to provide information about the "lineage" of a machine mana ### Implementation Details/Notes/Constraints [optional] -![Sub Controller Flow](manage_boot_images_flow.jpg) - -![MachineSet Reconciliation Flow](manage_boot_images_reconcile_loop.jpg) +MachineSet Reconciliation Loop: + +```mermaid +flowchart-elk TD; + Start((Start)) -->MachineSetOwnerCheck[Does the MachineSet have an OwnerReference?] + MachineSetOwnerCheck -->|Yes|Error + MachineSetOwnerCheck -->|No| ConfigMapCheck[Has the coreos-bootimages ConfigMap been stamped by the MCO?] ; + + ConfigMapCheck -->|Yes|ArchType[Determine arch type of MachineSet, for eg: x86_64, aarch64] ; + ConfigMapCheck -->|No| Wait[A cluster upgrade is ongoing. Wait until atleast 1 control plane node has completed an update.]; + Wait --> |Upgrade Complete| ArchType + Wait --> |Timeout| Error + ArchType -->PlatformType[Determine platform type of MachineSet, for eg: gcp, aws, vsphere] ; + PlatformType -->ProviderSpec[Grab providerSpec from MachineSet, for eg: GCPProviderSpec, AWSProviderSpec etc] ; + + subgraph PlatformSpecific[Platform Specific] + ProviderSpec -->IgnitionCheck[Is stub Ignition referenced in ProviderSpec in spec 3 format?] ; + IgnitionCheck -->|Yes|CompareBootImage[Compare bootimage in ProviderSpec against the coreos-bootimage ConfigMap] ; + end + + IgnitionCheck -->|No| Error[Throw an error to the cluster admin]; + Error -->Stop[Stop]; + CompareBootImage -->|Mismatch| Patch[Patch MachineSet]; + CompareBootImage -->|Match| Stop[Stop]; + + Patch --> Stop((Stop)); +``` -The implementation has a GCP specific MVP here: +The implementation has a GCP specific MVP that can be found here: - https://github.com/openshift/machine-config-operator/pull/4083 ### Risks and Mitigations -The biggest risk in this enhancement would be delivering a bad boot image. To mitigate this, we have outlined a revert option. +The biggest risk in this enhancement would be delivering a bad boot image. However, the chances of this are quite minimal, as it would imply the [boot images](https://github.com/openshift/installer/blob/main/data/data/coreos/rhcos.json) used in the current version of OCP are invalid, which would have been through several iterations of CI. -How will security be reviewed and by whom? TBD +How will security be reviewed and by whom? This is a solution aimed at reducing usage of outdated artifacts and should not introduce any security concerns that do not currently exist. -How will UX be reviewed and by whom? TBD +How will UX be reviewed and by whom? The UX element involved include the user opt-in and opt-out, which is currently up for debate. +#### Enabling Boot Image Updates by default + +This will be done on a platform by platform basis. Some key benchmarks have to be met for a platform to be considered ready +for default on: +- Sufficent runtime(say, atleast 1 release) has been accumulated while boot image updates has been GAed for this platform. +- Periodic tests have been added for this platform in CI and have met certain passing metrics. +- Any teams that are affected by default-on +behavior have been notified and assisted with the transition. + +The default-on flow could look like this: +```mermaid +flowchart-elk LR; + Start((Start)) -->MachineConfigurationCheck[Does the cluster currently have a boot image update configuration?] + MachineConfigurationCheck -->|Yes|Stop + MachineConfigurationCheck -->|No| UpdateConfig[The MCO will opt-in the cluster to boot image updates] ; + UpdateConfig --> Stop((Stop)); +``` +Some points to note: +- For bookkeeping purposes, the MCO will annotate the `MachineConfiguration` object when opting in the cluster. +- If the cluster admin wishes to opt-out of the feature, they have to explicitly do so by removing the boot image configuration. Due to the presence of the "opted in" annotation, the MCO will not attempt to automatically opt-in the cluster for updates again. +- This mechanism will be active on installs and upgrades. + + +### Enforcement of bootimage skew + +There should be some mechanism that will alert the user and fail if a cluster's bootimage are out of date. For example, at upgrade time, the MCO could signal to the CVO by setting Upgradeable=False. + +#### Acceptable skew + +The release payload will describe the current skew policy. The structure of this skew policy is TBD, but at the minimum it should describe the lowest acceptable boot image for the release. Generally speaking, we would like to keep the bootimage version aligned to the RHEL version we are shipping in the payload. For example, a 9.6 bootimage will be allowed until 9.8 is shipped via RHCOS. We would like to keep this customizable, such that any major breaking changes outside of RHEL major/minor can still be enforced as a one-off. + +#### Enforcement options + +Some combination of the following mechanisms should be implemented to alert users, particularly non-machineset backed scaled environments. The options generally fall under proactive enforcement (require users to either update or acknowledge risk before upgrading to a new version) vs. reactive enforcement (only fail when a non-compliant bootimage is being used to scale into the cluster). + +#### Proactive +Introduce a new configmap in the MCO namespace that will store the last updated boot image and allows for easy comparison against the +skew policy described in the release payload. + - For machineset backed clusters, this would be updated by the MSBIC after it succesfully updates boot images. + - For non-machineset backed clusters, this would be updated by the cluster admin to indicate the last manually updated bootimage. The cluster admin would need to update this configmap every few releases, when the RHEL minor on which the RHCOS container is built on changes (e.g. 9.6->9.8). + +The cluster admin may also choose to opt-out of skew management via this configmap, which indicates that they will not require scaling nodes, and thereby opting out of skew enforcement and scaling functionality. + +A potential problem here is that the way boot images are stored in the machineset is lossy. In certain platforms, there is no way to recover the boot image metadata from the MachineSet. This is most likely to happen the first time the MCO attempts to do skew enforcement on a cluster that has never had boot image updates. In such cases, the MCO will default to the install time boot image, which can be recovered from the aleph version of the control plane nodes. + +This configmap can then be monitored to enforce skew limits. This could be done in a couple of ways: +- **via the MCO**: If the skew is determined to be too large, the MCO can update its `ClusterOperator` object with an `Upgradeable=False` condition, along with remediation steps in the `Condition` message. This will signal to the CVO that the cluster is not suitable for an upgrade. The drawback of this approach is that the MCO is not able to signal *prior* to the start of a cluster upgrade, so if an incoming upgrade has a "stricter" skew policy, this could break scaling until the admin takes the remediation steps during the upgrade or after the upgrade is complete. This may present as strange UX to the user. + +- **via the CVO**: If the CVO is able to do the configmap monitoring, the enforcement can be a bit more proactive. The CVO could then potentially block an incoming upgrade based on the skew policy described in the new release payload, until the remediation steps have been done. + +As stated earlier, to remediate, the cluster admin would then have to do one of the following: +- Turn on boot image updates if it is a machineset backed cluster. +- Manually update the boot image and update the configmap if it is a non machineset backed cluster. +- Opt-out of skew enforcement altogether, giving up scaling ability. + +#### Reactive +1. Have the MCS reject new ignition requests if the aformentioned configmap indicates that the cluster's bootimages are out of date. The MCS could then signal to the cluster admin that scale-up is not available until the configmap has been reconciled. +2. Add a service to be shipped via RHCOS/MCO templates, which will do a check on incoming OS container image vs currently booted RHCOS version. This runs on firstboot right after the MCD pulls the new image, and will prevent the node to rebase to the updated image if the drift is too far. + +RHEL major versions will no longer be cross-compatible. i.e. if you wish to have a RHEL10 machineconfigpool, you must use a RHEL10 bootimage. + ### Drawbacks TBD, based on the open questions below. diff --git a/enhancements/machine-config/manage_boot_images_flow.jpg b/enhancements/machine-config/manage_boot_images_flow.jpg deleted file mode 100644 index 6619a791d6d7ce69a1a6d61ef8060fe311864591..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59490 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%0AWP%SCOrrN>+( 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 From c2ef0ca8ae00585a329ce8adfc1428fdd1f0b53a Mon Sep 17 00:00:00 2001 From: David Date: Tue, 4 Mar 2025 10:51:55 -0500 Subject: [PATCH 2/9] updated timeline and API --- .../machine-config/manage-boot-images.md | 71 ++++++++++++++----- 1 file changed, 54 insertions(+), 17 deletions(-) diff --git a/enhancements/machine-config/manage-boot-images.md b/enhancements/machine-config/manage-boot-images.md index 8b9847a55b..bd7499a5af 100644 --- a/enhancements/machine-config/manage-boot-images.md +++ b/enhancements/machine-config/manage-boot-images.md @@ -45,7 +45,7 @@ Currently, bootimage references are [stored](https://github.com/openshift/instal Additionally, the stub Ignition config [referenced](https://github.com/openshift/installer/blob/1ca0848f0f8b2ca9758493afa26bf43ebcd70410/pkg/asset/machines/gcp/machines.go#L197) in the `MachineSet` is also not managed. This stub is used by the ignition binary in firstboot to auth and consume content from the `machine-config-server`(MCS). The content served includes the actual Ignition configuration and the target OCI format RHCOS image. The ignition binary now does first boot provisioning based on this, then hands off to the `machine-config-daemon`(MCD) first boot service to do the reboot into the target OCI format RHCOS image. -There has been [a previous effort](https://github.com/openshift/machine-config-operator/pull/1792) to manage the stub Ignition config. It was [reverted](https://github.com/openshift/machine-config-operator/pull/2126) and then [brought back](https://github.com/openshift/machine-config-operator/pull/2827#issuecomment-996156872) just for bare metal clusters. For other platforms, the `*-managed` stubs still get generated by the MCO, but are not injected into the `MachineSet`. The proposal plans to utilize these unused `*-managed` stubs, but it is important to note that this stub is generated(and synced) by the MCO and will ignore/override any user customizations to the original stub Ignition config. This limitation will be mentioned in the documentation, and a later release will provide support for user customization of the stub, either via API or a workaround thorugh additional documentation. This should not be an issue for the majority of users as they very rarely customize the original stub Ignition config. +There has been [a previous effort](https://github.com/openshift/machine-config-operator/pull/1792) to manage the stub Ignition config. It was [reverted](https://github.com/openshift/machine-config-operator/pull/2126) and then [brought back](https://github.com/openshift/machine-config-operator/pull/2827#issuecomment-996156872) just for bare metal clusters. For other platforms, the `*-managed` stubs still get generated by the MCO, but are not injected into the `MachineSet`. The proposal plans to utilize these unused `*-managed` stubs, but it is important to note that this stub is generated(and synced) by the MCO and will ignore/override any user customizations to the original stub Ignition config. This limitation will be mentioned in the documentation, and a later release will provide support for user customization of the stub, either via API or a workaround through additional documentation. This should not be an issue for the majority of users as they very rarely customize the original stub Ignition config. In certain long lived clusters, the MCS TLS cert contained within the above Ignition configuration may be out of date. Example issue [here](https://issues.redhat.com/browse/OCPBUGS-1817). While this has been partly solved [MCO-642](https://issues.redhat.com/browse/MCO-642) (which allows the user to manually rotate the cert) it would be very beneficial for the MCO to actively manage this TLS cert and take this concern away from the user. @@ -81,7 +81,7 @@ __Overview__ - `ManagedBootImages` feature gate is active - The cluster and/or the machineset is opted-in to boot image updates. This is done at the operator level, via the `MachineConfiguration` API object. - The `machineset` does not have a valid owner reference. Having a valid owner reference typically indicates that the `MachineSet` is managed by another workflow, and that updates to it are likely going to cause thrashing. - - The golden configmap is verified to be in sync with the current version of the MCO. The MCO will update("stamp") the golden configmap with version of the new MCO image after at least 1 master node has succesfully completed an update to the new OCP image. This helps prevent `machinesets` being updated too soon at the end of a cluster upgrade, before the MCO itself has updated and has had a chance to roll out the new OCP image to the cluster. + - The golden configmap is verified to be in sync with the current version of the MCO. The MCO will update("stamp") the golden configmap with version of the new MCO image after at least 1 master node has successfully completed an update to the new OCP image. This helps prevent `machinesets` being updated too soon at the end of a cluster upgrade, before the MCO itself has updated and has had a chance to roll out the new OCP image to the cluster. If any of the above checks fail, the MSBIC will exit out of the sync. - Based on platform and architecture type, the MSBIC will check if the boot images referenced in the `providerSpec` field of the `MachineSet` is the same as the one in the ConfigMap. Each platform(gcp, aws...and so on) does this differently, so this part of the implementation will have to be special cased. The ConfigMap is considered to be the golden set of bootimage values, i.e. they will never go out of date. If it is not a match, the `providerSpec` field is cloned and updated with the new boot image reference. @@ -135,21 +135,22 @@ This work will be tracked in [MCO-793](https://issues.redhat.com/browse/MCO-793) ##### Projected timeline -This is a tentative timeline, subject to change (GA = General Availability, TP = Tech Preview, EF = Default-on, Skew Enforced). +This is a tentative timeline, subject to change (GA = General Availability, TP = Tech Preview, DEF = Default-on). -| Platform | TP | GA | EF | +| Platform | TP | GA | DEF | | -------- | ------- | ------- | ------- | -| gcp | 4.16 |4.17 |4.19 | -| aws | 4.17 |4.18 |4.20 | +| gcp | [4.16](https://docs.redhat.com/en/documentation/openshift_container_platform/4.16/html-single/machine_configuration/index#mco-update-boot-images) |[4.17](https://docs.redhat.com/en/documentation/openshift_container_platform/4.17/html-single/machine_configuration/index#mco-update-boot-images) |4.19 | +| aws | [4.17](https://docs.redhat.com/en/documentation/openshift_container_platform/4.17/html-single/machine_configuration/index#mco-update-boot-images) |[4.18](https://docs.redhat.com/en/documentation/openshift_container_platform/4.18/html-single/machine_configuration/index#mco-update-boot-images) |4.19 | | vsphere | 4.20 |4.21 |4.22 | | baremetal| |4.22 |4.23 | | openstack| |4.22 |4.23 | -| nutanix | |4.22 |4.23 | -| ibmcloud | |4.24 |4.25 | -| non-managed* | |4.21 |4.22 | +| nutanix | |4.23 |4.24 | +| ibmcloud | |4.23 |4.24 | +| non-managed* | x |x |4.25 | -*non-managed in this case indicates enforcement of user-initiated bootimage updates. See enforcement section below. +Once default-on behavior has been deemed to be stable across the above mentioned platforms, skew enforcement will be implemented in a platform agnostic manner. Decoupling the default-on and skew enforcement mechanism would help iron out any edge cases unique to a platform and would also aid in refining the skew enforcement workflow. The tentative timeline for skew enforcement would be 4.25. +**Note** : For non-managed cases, * indicates enforcement of user-initiated bootimage updates. See enforcement section below. ##### Cluster API backed machinesets As the Cluster API move is impending(initial release in 4.16 and default-on release in 4.17), it is necessary that this enhancement plans for the changes required in an CAPI backed cluster. Here are a couple of sample YAMLs used in CAPI backed `Machinesets`, from the [official Openshift documentation](https://docs.openshift.com/container-platform/4.14/machine_management/capi-machine-management.html#capi-sample-yaml-files-gcp). @@ -225,9 +226,10 @@ Much of the existing design regarding architecture & platform detection, opt-in, #### Opt-in Mechanism This proposal introduces a new field in the MCO operator API, `ManagedBootImages` which encloses an array of `MachineManager` objects. A `MachineManager` object contains the resource type of the machine management object that is being opted-in, the API group of that object and a union discriminant object of the type `MachineManagerSelector`. This object `MachineManagerSelector` contains: -- The union discriminator, `Mode`, can be set to two values : All and Partial. +- The union discriminator, `Mode`, can be set to three values : All, Partial and None. - **All**: All machine resources described by this resource/apiGroup type will be opted-in for boot image updates. In most cases, this effectively enables boot image updates for the whole cluster, unless there are multiple kinds of machine resources present in the cluster. - **Partial**: This is a set of label selectors that will be used by users to opt-in a custom selection of machine resources. When the Mode is set to Partial mode, all machinesets matched by this object would be considered enrolled for updates. In the first iteration of this API, this object will only allow for label matching with MachineResources. In the future, additional ways of filtering may be added with another label selector, e.g. namespace. + - **None**: All machine resources described by this resource/apiGroup type will be excluded from boot image updates. In most cases, this effectively disables boot image updates for the whole cluster, unless there are multiple kinds of machine resources present in the cluster. ``` @@ -268,6 +270,7 @@ type MachineManagerSelector struct { // Valid values are All and Partial. // All means that every resource matched by the machine manager will be updated. // Partial requires specified selector(s) and allows customisation of which resources matched by the machine manager will be updated. + // None means that every resource matched by the machine manager will NOT be updated. // +unionDiscriminator // +kubebuilder:validation:Required Mode MachineManagerSelectorMode `json:"mode"` @@ -286,7 +289,7 @@ type PartialSelector struct { } // MachineManagerSelectorMode is a string enum used in the MachineManagerSelector union discriminator. -// +kubebuilder:validation:Enum:="All";"Partial" +// +kubebuilder:validation:Enum:="All";"Partial";"None" type MachineManagerSelectorMode string const ( @@ -296,6 +299,9 @@ const ( // Partial represents a configuration mode that will register resources specified by the parent MachineManager only // if they match with the label selector. Partial MachineManagerSelectorMode = "Partial" + + // None represents a configuration mode that excludes all resources specified by the parent MachineManager from boot image updates. + None MachineManagerSelectorMode = "None" ) // MachineManagerManagedResourceType is a string enum used in the MachineManager type to describe the resource @@ -377,6 +383,37 @@ spec: name: "cluster" namespace: "default" ``` +#### Skew Enforcement +As mentioned in the timeline section, this would only be implemented after default-on behavior has been deemed to be stable across +all platforms. + +This would introduced as an new knob in the `ManagedBootImages` struct: +``` +type ManagedBootImages struct { + ... + ... + // skewEnforcement allows an admin to set behavior of the boot image skew enforcement mechanism. + // Enabled means that the MCO will degrade and prevent upgrades when the boot image skew is too large. + // Disabled means that the MCO will no longer degrade and will permit upgrades when the boot image skew is + // too large. This may also hinder the cluster's scaling ability. + // +optional + SkewEnforcement SkewEnforcementSelectorMode `json:"skewEnforcement"` +} + +// SkewEnforcementSelectorMode is a string enum used to indicate the cluster's boot image skew enforcement mode. +// +kubebuilder:validation:Enum:="Enabled";"Disabled" +type SkewEnforcementSelectorMode string + +const ( + // Enabled represents a configuration mode that enables boot image skew enforcement. + Enabled SkewEnforcementSelectorMode = "Enabled" + + // Disabled represents a configuration mode that disables boot image skew enforcement. + Disabled SkewEnforcementSelectorMode = "Disabled" +) + +``` + #### Tracking boot image history Note: This section is just an idea for the moment and is considered out of scope. This CR will require thorough API review in a follow-up enhancement. @@ -502,7 +539,7 @@ flowchart-elk TD; MachineSetOwnerCheck -->|No| ConfigMapCheck[Has the coreos-bootimages ConfigMap been stamped by the MCO?] ; ConfigMapCheck -->|Yes|ArchType[Determine arch type of MachineSet, for eg: x86_64, aarch64] ; - ConfigMapCheck -->|No| Wait[A cluster upgrade is ongoing. Wait until atleast 1 control plane node has completed an update.]; + ConfigMapCheck -->|No| Wait[A cluster upgrade is ongoing. Wait until at least 1 control plane node has completed an update.]; Wait --> |Upgrade Complete| ArchType Wait --> |Timeout| Error ArchType -->PlatformType[Determine platform type of MachineSet, for eg: gcp, aws, vsphere] ; @@ -538,7 +575,7 @@ The UX element involved include the user opt-in and opt-out, which is currently This will be done on a platform by platform basis. Some key benchmarks have to be met for a platform to be considered ready for default on: -- Sufficent runtime(say, atleast 1 release) has been accumulated while boot image updates has been GAed for this platform. +- Sufficent runtime(say, at least 1 release) has been accumulated while boot image updates has been GAed for this platform. - Periodic tests have been added for this platform in CI and have met certain passing metrics. - Any teams that are affected by default-on behavior have been notified and assisted with the transition. @@ -552,8 +589,8 @@ flowchart-elk LR; UpdateConfig --> Stop((Stop)); ``` Some points to note: -- For bookkeeping purposes, the MCO will annotate the `MachineConfiguration` object when opting in the cluster. -- If the cluster admin wishes to opt-out of the feature, they have to explicitly do so by removing the boot image configuration. Due to the presence of the "opted in" annotation, the MCO will not attempt to automatically opt-in the cluster for updates again. +- For bookkeeping purposes, the MCO will annotate the `MachineConfiguration` object when opting in the cluster by default. +- If the cluster admin wishes to opt-out of the feature, they have to do so by removing the boot image configuration or explicitly opting out the cluster via the API knob. Due to the presence of the "default opted-in" annotation, the MCO will not attempt to opt-in the cluster by default again. - This mechanism will be active on installs and upgrades. @@ -577,7 +614,7 @@ skew policy described in the release payload. The cluster admin may also choose to opt-out of skew management via this configmap, which indicates that they will not require scaling nodes, and thereby opting out of skew enforcement and scaling functionality. -A potential problem here is that the way boot images are stored in the machineset is lossy. In certain platforms, there is no way to recover the boot image metadata from the MachineSet. This is most likely to happen the first time the MCO attempts to do skew enforcement on a cluster that has never had boot image updates. In such cases, the MCO will default to the install time boot image, which can be recovered from the aleph version of the control plane nodes. +A potential problem here is that the way boot images are stored in the machineset is lossy. In certain platforms, there is no way to recover the boot image metadata from the MachineSet. This is most likely to happen the first time the MCO attempts to do skew enforcement on a cluster that has never had boot image updates. In such cases, the MCO will default to the install time boot image, which can be recovered from the [aleph version](https://github.com/coreos/coreos-assembler/pull/768) of the control plane nodes. This configmap can then be monitored to enforce skew limits. This could be done in a couple of ways: - **via the MCO**: If the skew is determined to be too large, the MCO can update its `ClusterOperator` object with an `Upgradeable=False` condition, along with remediation steps in the `Condition` message. This will signal to the CVO that the cluster is not suitable for an upgrade. The drawback of this approach is that the MCO is not able to signal *prior* to the start of a cluster upgrade, so if an incoming upgrade has a "stricter" skew policy, this could break scaling until the admin takes the remediation steps during the upgrade or after the upgrade is complete. This may present as strange UX to the user. From 54d1b564601fa647159b2e1ba15c59acf8508812 Mon Sep 17 00:00:00 2001 From: David Date: Tue, 11 Mar 2025 14:44:55 -0400 Subject: [PATCH 3/9] updated motivation, ownerref changes, status API --- .../machine-config/manage-boot-images.md | 105 +++++++++++++++--- 1 file changed, 90 insertions(+), 15 deletions(-) diff --git a/enhancements/machine-config/manage-boot-images.md b/enhancements/machine-config/manage-boot-images.md index bd7499a5af..c2e5fd0638 100644 --- a/enhancements/machine-config/manage-boot-images.md +++ b/enhancements/machine-config/manage-boot-images.md @@ -42,6 +42,7 @@ Currently, bootimage references are [stored](https://github.com/openshift/instal - Afterburn [[1](https://issues.redhat.com/browse/OCPBUGS-7559)],[[2](https://issues.redhat.com/browse/OCPBUGS-4769)] - podman [[1](https://issues.redhat.com/browse/OCPBUGS-9969)] - skopeo [[1](https://issues.redhat.com/browse/OCPBUGS-3621)] +- composefs [[1](https://github.com/openshift/os/issues/1678#issuecomment-2546310833)] Additionally, the stub Ignition config [referenced](https://github.com/openshift/installer/blob/1ca0848f0f8b2ca9758493afa26bf43ebcd70410/pkg/asset/machines/gcp/machines.go#L197) in the `MachineSet` is also not managed. This stub is used by the ignition binary in firstboot to auth and consume content from the `machine-config-server`(MCS). The content served includes the actual Ignition configuration and the target OCI format RHCOS image. The ignition binary now does first boot provisioning based on this, then hands off to the `machine-config-daemon`(MCD) first boot service to do the reboot into the target OCI format RHCOS image. @@ -51,6 +52,9 @@ In certain long lived clusters, the MCS TLS cert contained within the above Igni **Note**: As of 4.19, the MCO supports [management of this TLS cert](https://issues.redhat.com/browse/MCO-1208). With this work in place, the MCO can now attempt to upgrade the stub Ignition config, instead of hardcoding to the `*-managed` stub as mentioned previously. This will help preserve any user customizations that were present in the stub Ignition config. +This is also considered a blocking issue for [SigStore GA](https://issues.redhat.com/browse/OCPNODE-2619). It has caused issues such as [OCPBUGS-38809](https://issues.redhat.com/browse/OCPBUGS-38809) due to the older podman binary not being able to understand `sigstoreSigned` fields in `/etc/containers/policy.json`. There can be similar issues in the future that can be hard to anticipate. + + This is also a soft pre-requisite for both dual-stream RHEL support in OpenShift, and on-cluster layered builds. RPM-OSTree presently does a deploy-from-self to get a new-enough rpm-ostree to deploy image-based RHEL CoreOS systems, and we would like to avoid doing this for bootc if possible. We would also like to prevent RHEL8->RHEL10 direct updates once that is available for OpenShift. ### User Stories @@ -92,7 +96,6 @@ __Overview__ #### Error & Alert Mechanism MSBIC sync failures may be caused by multiple reasons: -- The MSBIC notices an OwnerReference and is able to determine that updating the `MachineSet` will likely cause thrashing. This is considered a misconfiguration and in such cases, the user is expected to exclude this `MachineSet` from boot image management. - The `coreos-bootimages` ConfigMap is unavailable or in an incorrect format. This will likely happen if a user manually edits the ConfigMap, overriding the CVO. - The `coreos-bootimages` ConfigMap takes too long to be stamped by the MCO. This indicates that there are larger problems in the cluster such as an upgrade failure/timeout or an unrelated cluster failure. - Patching the `MachineSet` fails. This indicates a temporary API server blip, or larger RBAC issues. @@ -115,7 +118,7 @@ Any form factor using the MCO and `MachineSets` will be impacted by this proposa - Standalone OpenShift: Yes, this is the main target form factor. - microshift: No, as it does [not](https://github.com/openshift/microshift/blob/main/docs/contributor/enabled_apis.md) use `MachineSets`. - Hypershift: No, Hypershift does not have this issue. -- Hive: Hive manages `MachineSets` via `MachinePools`. The MachinePool controller generates the `MachineSets` manifests (by invoking vendored installer code) which include the `providerSpec`. Once a `MachineSet` has been created on the spoke, the only things that will be reconciled on it are replicas, labels, and taints - [unless a backdoor is enabled](https://github.com/openshift/hive/blob/0d5507f91935701146f3615c990941f24bd42fe1/pkg/constants/constants.go#L518). If the `providerSpec` ever goes out of sync, a warning will be logged by the MachinePool controller but otherwise this discrepancy is ignored. In such cases, the MSBIC will not have any issue reconciling the `providerSpec` to the correct boot image. However, if the backdoor is enabled, both the MSBIC and the MachinePool Controller will attempt to reconcile the `providerSpec` field, causing churn. The Hive team will update the comment on the backdoor annotation to indicate that it is mutually exclusive with this feature. +- Hive: Hive manages `MachineSets` via `MachinePools`. The MachinePool controller generates the `MachineSets` manifests (by invoking vendored installer code) which include the `providerSpec`. Once a `MachineSet` has been created on the spoke, the only things that will be reconciled on it are replicas, labels, and taints - [unless a backdoor is enabled](https://github.com/openshift/hive/blob/0d5507f91935701146f3615c990941f24bd42fe1/pkg/constants/constants.go#L518). If the `providerSpec` ever goes out of sync, a warning will be logged by the MachinePool controller but otherwise this discrepancy is ignored. In such cases, the MSBIC will not have any issue reconciling the `providerSpec` to the correct boot image. However, if the backdoor is enabled, both the MSBIC and the MachinePool Controller will attempt to reconcile the `providerSpec` field, causing churn. The Hive team has [updated the comment](https://github.com/openshift/hive/pull/2596/files) on the backdoor annotation to indicate that it is mutually exclusive with this feature. ##### Supported platforms @@ -135,13 +138,14 @@ This work will be tracked in [MCO-793](https://issues.redhat.com/browse/MCO-793) ##### Projected timeline -This is a tentative timeline, subject to change (GA = General Availability, TP = Tech Preview, DEF = Default-on). +This is a tentative timeline, subject to change (GA = General Availability(opt-in), TP = Tech Preview(opt-in), DEF = Default-on(opt-out)). | Platform | TP | GA | DEF | | -------- | ------- | ------- | ------- | | gcp | [4.16](https://docs.redhat.com/en/documentation/openshift_container_platform/4.16/html-single/machine_configuration/index#mco-update-boot-images) |[4.17](https://docs.redhat.com/en/documentation/openshift_container_platform/4.17/html-single/machine_configuration/index#mco-update-boot-images) |4.19 | | aws | [4.17](https://docs.redhat.com/en/documentation/openshift_container_platform/4.17/html-single/machine_configuration/index#mco-update-boot-images) |[4.18](https://docs.redhat.com/en/documentation/openshift_container_platform/4.18/html-single/machine_configuration/index#mco-update-boot-images) |4.19 | | vsphere | 4.20 |4.21 |4.22 | +| azure | 4.20 |4.21 |4.22 | | baremetal| |4.22 |4.23 | | openstack| |4.22 |4.23 | | nutanix | |4.23 |4.24 | @@ -383,6 +387,77 @@ spec: name: "cluster" namespace: "default" ``` + +Alongside the implementation of default-on behavior, a Status field for ManagedBootImages is also planned. This would reflect the +current ManagedBootImages configuration and if unspecified, it will represent the current cluster defaults. +``` +type MachineConfigurationStatus struct { + ... + ... + + // managedBootImagesStatus reflects what the latest cluster-validated boot image configuration is + // and will be used by Machine Config Controller while performing boot image updates. + // +openshift:enable:FeatureGate=ManagedBootImages + // +optional + ManagedBootImagesStatus ManagedBootImages `json:"managedBootImagesStatus"` +} + +``` +Here are some examples to illustrate how this works. + +Scenario: No admin configuration and the currrent release **does not** opt-in by default: +``` +apiVersion: operator.openshift.io/v1 +kind: MachineConfiguration +spec: +status: + managedBootImagesStatus: + machineManagers: + - resource: machinesets + apiGroup: machine.openshift.io + selection: + mode: None +``` +Scenario: No admin configuration and the currrent release **does** opt-in by default: +``` +apiVersion: operator.openshift.io/v1 +kind: MachineConfiguration +spec: +status: + managedBootImagesStatus: + machineManagers: + - resource: machinesets + apiGroup: machine.openshift.io + selection: + mode: All +``` +Regardless of the default-on behavior of the release, if the admin were to add a configuration, the status must reflect that in the next update. +``` +apiVersion: operator.openshift.io/v1 +kind: MachineConfiguration +spec: + managedBootImages: + machineManagers: + - resource: machinesets + apiGroup: machine.openshift.io + selection: + mode: Partial + partial: + machineResourceSelector: + matchLabels: {} +status: + managedBootImagesStatus: + machineManagers: + - resource: machinesets + apiGroup: machine.openshift.io + selection: + mode: Partial + partial: + machineResourceSelector: + matchLabels: {} +``` + + #### Skew Enforcement As mentioned in the timeline section, this would only be implemented after default-on behavior has been deemed to be stable across all platforms. @@ -393,9 +468,10 @@ type ManagedBootImages struct { ... ... // skewEnforcement allows an admin to set behavior of the boot image skew enforcement mechanism. - // Enabled means that the MCO will degrade and prevent upgrades when the boot image skew is too large. - // Disabled means that the MCO will no longer degrade and will permit upgrades when the boot image skew is - // too large. This may also hinder the cluster's scaling ability. + // Enabled means that the MCO will degrade and prevent upgrades when the boot image skew exceeds the + // skew limit described by the release image. + // Disabled means that the MCO will no longer degrade and will permit upgrades when the boot image + // exceeds the skew limit described by the release image. This will likely hinder the cluster's scaling ability. // +optional SkewEnforcement SkewEnforcementSelectorMode `json:"skewEnforcement"` } @@ -535,7 +611,7 @@ MachineSet Reconciliation Loop: ```mermaid flowchart-elk TD; Start((Start)) -->MachineSetOwnerCheck[Does the MachineSet have an OwnerReference?] - MachineSetOwnerCheck -->|Yes|Error + MachineSetOwnerCheck -->|Yes|Stop MachineSetOwnerCheck -->|No| ConfigMapCheck[Has the coreos-bootimages ConfigMap been stamped by the MCO?] ; ConfigMapCheck -->|Yes|ArchType[Determine arch type of MachineSet, for eg: x86_64, aarch64] ; @@ -548,9 +624,11 @@ flowchart-elk TD; subgraph PlatformSpecific[Platform Specific] ProviderSpec -->IgnitionCheck[Is stub Ignition referenced in ProviderSpec in spec 3 format?] ; IgnitionCheck -->|Yes|CompareBootImage[Compare bootimage in ProviderSpec against the coreos-bootimage ConfigMap] ; + IgnitionCheck -->|No| IgnitionUpgrade[Attempt Ignition Upgrade]; + IgnitionUpgrade -->|Ignition Upgrade Successful| CompareBootImage; end - IgnitionCheck -->|No| Error[Throw an error to the cluster admin]; + IgnitionUpgrade -->|Ignition Upgrade Failed| Error[Throw an error to the cluster admin]; Error -->Stop[Stop]; CompareBootImage -->|Mismatch| Patch[Patch MachineSet]; CompareBootImage -->|Match| Stop[Stop]; @@ -590,8 +668,9 @@ flowchart-elk LR; ``` Some points to note: - For bookkeeping purposes, the MCO will annotate the `MachineConfiguration` object when opting in the cluster by default. -- If the cluster admin wishes to opt-out of the feature, they have to do so by removing the boot image configuration or explicitly opting out the cluster via the API knob. Due to the presence of the "default opted-in" annotation, the MCO will not attempt to opt-in the cluster by default again. - This mechanism will be active on installs and upgrades. +- If the cluster admin wishes to opt-out of the feature, they have to do so by explicitly opting out the cluster via the API knob prior to the upgrade. +- If any of the MachineSets have an OwnerReference, it will be skipped for boot image updates. This will cause an alert/warning to the cluster admin, but it will no longer cause a degrade. ### Enforcement of bootimage skew @@ -607,8 +686,7 @@ The release payload will describe the current skew policy. The structure of this Some combination of the following mechanisms should be implemented to alert users, particularly non-machineset backed scaled environments. The options generally fall under proactive enforcement (require users to either update or acknowledge risk before upgrading to a new version) vs. reactive enforcement (only fail when a non-compliant bootimage is being used to scale into the cluster). #### Proactive -Introduce a new configmap in the MCO namespace that will store the last updated boot image and allows for easy comparison against the -skew policy described in the release payload. +Add a new field in the `coreos-bootimages` configmap in the MCO namespace that will store the cluster's current boot image and allows for easy comparison against the skew policy described in the release payload. - For machineset backed clusters, this would be updated by the MSBIC after it succesfully updates boot images. - For non-machineset backed clusters, this would be updated by the cluster admin to indicate the last manually updated bootimage. The cluster admin would need to update this configmap every few releases, when the RHEL minor on which the RHCOS container is built on changes (e.g. 9.6->9.8). @@ -616,10 +694,7 @@ The cluster admin may also choose to opt-out of skew management via this configm A potential problem here is that the way boot images are stored in the machineset is lossy. In certain platforms, there is no way to recover the boot image metadata from the MachineSet. This is most likely to happen the first time the MCO attempts to do skew enforcement on a cluster that has never had boot image updates. In such cases, the MCO will default to the install time boot image, which can be recovered from the [aleph version](https://github.com/coreos/coreos-assembler/pull/768) of the control plane nodes. -This configmap can then be monitored to enforce skew limits. This could be done in a couple of ways: -- **via the MCO**: If the skew is determined to be too large, the MCO can update its `ClusterOperator` object with an `Upgradeable=False` condition, along with remediation steps in the `Condition` message. This will signal to the CVO that the cluster is not suitable for an upgrade. The drawback of this approach is that the MCO is not able to signal *prior* to the start of a cluster upgrade, so if an incoming upgrade has a "stricter" skew policy, this could break scaling until the admin takes the remediation steps during the upgrade or after the upgrade is complete. This may present as strange UX to the user. - -- **via the CVO**: If the CVO is able to do the configmap monitoring, the enforcement can be a bit more proactive. The CVO could then potentially block an incoming upgrade based on the skew policy described in the new release payload, until the remediation steps have been done. +This configmap can then be monitored to enforce skew limits. This could be done in a couple of ways. If the skew is determined to be too large, the MCO can update its `ClusterOperator` object with an `Upgradeable=False` condition, along with remediation steps in the `Condition` message. This will signal to the CVO that the cluster is not suitable for an upgrade. As stated earlier, to remediate, the cluster admin would then have to do one of the following: - Turn on boot image updates if it is a machineset backed cluster. From ddb88853e9825ad11d82a1fa946bfc2a7363381d Mon Sep 17 00:00:00 2001 From: David Date: Thu, 10 Apr 2025 15:51:38 -0400 Subject: [PATCH 4/9] drafted skew enforcement API, updated timeline --- .../machine-config/manage-boot-images.md | 149 +++++++++++------- 1 file changed, 89 insertions(+), 60 deletions(-) diff --git a/enhancements/machine-config/manage-boot-images.md b/enhancements/machine-config/manage-boot-images.md index c2e5fd0638..b9b2bf0427 100644 --- a/enhancements/machine-config/manage-boot-images.md +++ b/enhancements/machine-config/manage-boot-images.md @@ -5,6 +5,7 @@ authors: reviewers: - "@yuqi-zhang" - "@mrunal" + - "@jlebon" - "@cgwalters, for rhcos context" - "@joelspeed, for machine-api context" - "@sdodson, for installer context" @@ -13,7 +14,7 @@ approvers: api-approvers: - "@joelspeed" creation-date: 2023-10-16 -last-updated: 2025-02-26 +last-updated: 2025-04-10 tracking-link: - https://issues.redhat.com/browse/MCO-589 see-also: @@ -29,11 +30,12 @@ superseded-by: This is a proposal to manage bootimages via the `Machine Config Operator`(MCO), leveraging some of the [pre-work](https://github.com/openshift/installer/pull/4760) done as a result of the discussion in [#201](https://github.com/openshift/enhancements/pull/201). This feature will only target standalone OCP installs. This is now released as an opt-in feature and will be rolled out on a per-platform basis (see projected roadmap). This will eventually be on by default, and the MCO will enforce an accepted skew and require non-platform managed bootimage updates to be acknowledged by the cluster admin. -For `MachineSet` managed clusters, the end goal is to create an automated mechanism that can: +For `MachineSet` managed clusters, the end goal is to create automated mechanisms that can: - update the boot images references in `MachineSets` to the latest in the payload image - ensure stub Ignition config referenced in each `Machinesets` is in spec 3 format +- ensure cluster is within acceptable skew to prevent scaling failures -For clusters that are not managed by `MachineSets`, the end goal is to create a document(KB or otherwise) that a cluster admin would follow to update their boot images. +For clusters that are not managed by `MachineSets`, the end goal is to create a document(KB or otherwise) that a cluster admin would follow to update their boot images to be compliant with the acceptable skew. In such cases, the admin will be expected to record their cluster's boot image in the skew enforcement API object. ## Motivation @@ -43,17 +45,15 @@ Currently, bootimage references are [stored](https://github.com/openshift/instal - podman [[1](https://issues.redhat.com/browse/OCPBUGS-9969)] - skopeo [[1](https://issues.redhat.com/browse/OCPBUGS-3621)] - composefs [[1](https://github.com/openshift/os/issues/1678#issuecomment-2546310833)] +- sigstore GA [[1](https://issues.redhat.com/browse/OCPNODE-2619)],[[2](https://issues.redhat.com/browse/OCPBUGS-38809)] -Additionally, the stub Ignition config [referenced](https://github.com/openshift/installer/blob/1ca0848f0f8b2ca9758493afa26bf43ebcd70410/pkg/asset/machines/gcp/machines.go#L197) in the `MachineSet` is also not managed. This stub is used by the ignition binary in firstboot to auth and consume content from the `machine-config-server`(MCS). The content served includes the actual Ignition configuration and the target OCI format RHCOS image. The ignition binary now does first boot provisioning based on this, then hands off to the `machine-config-daemon`(MCD) first boot service to do the reboot into the target OCI format RHCOS image. +Additionally, the stub Ignition config [referenced](https://github.com/openshift/installer/blob/1ca0848f0f8b2ca9758493afa26bf43ebcd70410/pkg/asset/machines/gcp/machines.go#L197) in the `MachineSet` is also not managed. This stub is also generated by the installer, and it typically consists of an endpoint and a Certificate Authority(CA), which are used by the ignition binary in firstboot to auth and consume content from the `machine-config-server`(MCS). This CA is called the [`RootCA`](https://github.com/openshift/installer/blob/99b48742d2f89b4978fe14cb6fe842e283c0ce4d/pkg/asset/tls/root.go#L19-L20) by the installer which is bit of a misnomer, as it does not give actual root access to the cluster - it is only used to generate the MCS TLS cert pair. Going forward, the proposal will be refer to these artifacts as the MCS CA & TLS cert. In 4.19, the MCO took ownership of [rotating the MCS CA & TLS cert](https://issues.redhat.com/browse/MCO-1208). -There has been [a previous effort](https://github.com/openshift/machine-config-operator/pull/1792) to manage the stub Ignition config. It was [reverted](https://github.com/openshift/machine-config-operator/pull/2126) and then [brought back](https://github.com/openshift/machine-config-operator/pull/2827#issuecomment-996156872) just for bare metal clusters. For other platforms, the `*-managed` stubs still get generated by the MCO, but are not injected into the `MachineSet`. The proposal plans to utilize these unused `*-managed` stubs, but it is important to note that this stub is generated(and synced) by the MCO and will ignore/override any user customizations to the original stub Ignition config. This limitation will be mentioned in the documentation, and a later release will provide support for user customization of the stub, either via API or a workaround through additional documentation. This should not be an issue for the majority of users as they very rarely customize the original stub Ignition config. +The content served by the MCS includes the actual Ignition configuration and the target OCI format RHCOS image. The ignition binary now does first boot provisioning based on this, then hands off to the `machine-config-daemon`(MCD) first boot service to do the reboot into the target OCI format RHCOS image. -In certain long lived clusters, the MCS TLS cert contained within the above Ignition configuration may be out of date. Example issue [here](https://issues.redhat.com/browse/OCPBUGS-1817). While this has been partly solved [MCO-642](https://issues.redhat.com/browse/MCO-642) (which allows the user to manually rotate the cert) it would be very beneficial for the MCO to actively manage this TLS cert and take this concern away from the user. - -**Note**: As of 4.19, the MCO supports [management of this TLS cert](https://issues.redhat.com/browse/MCO-1208). With this work in place, the MCO can now attempt to upgrade the stub Ignition config, instead of hardcoding to the `*-managed` stub as mentioned previously. This will help preserve any user customizations that were present in the stub Ignition config. - -This is also considered a blocking issue for [SigStore GA](https://issues.redhat.com/browse/OCPNODE-2619). It has caused issues such as [OCPBUGS-38809](https://issues.redhat.com/browse/OCPBUGS-38809) due to the older podman binary not being able to understand `sigstoreSigned` fields in `/etc/containers/policy.json`. There can be similar issues in the future that can be hard to anticipate. +Hence, it is critical that the Ignition binary in the boot image is able to process the stub Ignition config to make the initial MCS request and join the cluster. On clusters installed [prior to 4.6](https://docs.redhat.com/en/documentation/openshift_container_platform/4.6/html/release_notes/ocp-4-6-release-notes#ocp-4-6-ignition-spect-updated-v3), the stub Ignition would be of the spec 2 format - which cannot be used by the newer boot images. In very rare cases, some users also [customize](https://docs.redhat.com/en/documentation/openshift_container_platform/4.18/html/postinstallation_configuration/post-install-node-tasks#machine-node-custom-partition_post-install-node-tasks) the original stub Ignition config. Therefore, to make boot image updates as seamless as possible, there is a need to upgrade these stub Ignition configs to the spec 3 format, while preserving any customizations done to it at install time. +> **_NOTE:_** There has been [a previous effort](https://github.com/openshift/machine-config-operator/pull/1792) to manage the stub Ignition config. It was [reverted](https://github.com/openshift/machine-config-operator/pull/2126) and then [brought back](https://github.com/openshift/machine-config-operator/pull/2827#issuecomment-996156872) just for bare metal clusters. For other platforms, the `*-managed` stubs still get generated by the MCO, but are not injected into the `MachineSet`. Since they are generated and synced by the MCO, it ignores any user customizations. This proposal originally used the `*-managed` stubs in its initial implementation, but with the [MCS CA & TLS management](https://issues.redhat.com/browse/MCO-1208) work in place, the upgrade path mentioned above is preferred. This is also a soft pre-requisite for both dual-stream RHEL support in OpenShift, and on-cluster layered builds. RPM-OSTree presently does a deploy-from-self to get a new-enough rpm-ostree to deploy image-based RHEL CoreOS systems, and we would like to avoid doing this for bootc if possible. We would also like to prevent RHEL8->RHEL10 direct updates once that is available for OpenShift. @@ -65,7 +65,7 @@ This is also a soft pre-requisite for both dual-stream RHEL support in OpenShift ### Goals -The MCO will take over management of the boot image references and the stub Ignition configuration. The installer is still responsible for creating the `MachineSet` at cluster bring-up, but once cluster installation is complete the MCO will ensure that boot images are in sync with the latest payload. From the user standpoint, this should cause less compatibility issues as nodes will no longer need to pivot to a different version of RHCOS during node scaleup. +The MCO will take over management of the boot image references and the stub Ignition configuration. The installer is still responsible for creating the `MachineSet` at cluster bring-up, but once cluster installation is complete the MCO will ensure that boot images are in sync with the latest payload. From the user standpoint, this should cause less compatibility issues as nodes will no longer need to pivot to a substantially different version of RHCOS during node scaleup. This should not interfere with existing workflows such as Hive and ArgoCD. As this is an opt-in mechanism, the cluster admin will be protected against such scenarios of accidental "reconciliation" and for additional safety, the MSBIC will also ensure that machinesets that have a valid OwnerReference will be excluded from boot image updates. We will work with affected teams to transition them to the new workflow before we turn this feature on by default. @@ -82,15 +82,13 @@ __Overview__ - The `machine-config-controller`(MCC) pod will gain a new sub-controller `machine_set_boot_image_controller`(MSBIC) that monitors `MachineSet` changes and the `coreos-bootimages` [ConfigMap](https://github.com/openshift/installer/pull/4760) changes. - Before processing a MachineSet, the MSBIC will check if the following conditions are satisfied: - - `ManagedBootImages` feature gate is active - The cluster and/or the machineset is opted-in to boot image updates. This is done at the operator level, via the `MachineConfiguration` API object. - The `machineset` does not have a valid owner reference. Having a valid owner reference typically indicates that the `MachineSet` is managed by another workflow, and that updates to it are likely going to cause thrashing. - The golden configmap is verified to be in sync with the current version of the MCO. The MCO will update("stamp") the golden configmap with version of the new MCO image after at least 1 master node has successfully completed an update to the new OCP image. This helps prevent `machinesets` being updated too soon at the end of a cluster upgrade, before the MCO itself has updated and has had a chance to roll out the new OCP image to the cluster. If any of the above checks fail, the MSBIC will exit out of the sync. - Based on platform and architecture type, the MSBIC will check if the boot images referenced in the `providerSpec` field of the `MachineSet` is the same as the one in the ConfigMap. Each platform(gcp, aws...and so on) does this differently, so this part of the implementation will have to be special cased. The ConfigMap is considered to be the golden set of bootimage values, i.e. they will never go out of date. If it is not a match, the `providerSpec` field is cloned and updated with the new boot image reference. -- Next, it will check if the stub secret referenced within the `providerSpec` field of the `MachineSet` is managed i.e. `worker-user-data-managed` and not `worker-user-data`. If it is unmanaged, the cloned `providerSpec` will be updated to reference the managed stub secret. This step is platform/arch agnostic. - +- Next, it will check if the stub Ignition secret referenced within the `providerSpec` field of the `MachineSet` is of the spec 3 format. If it is not of the spec 3 format, it will attempt to upgrade it to spec 3. - Finally, the MSBIC will attempt to patch the `MachineSet` if an update is required. #### Error & Alert Mechanism @@ -98,12 +96,11 @@ __Overview__ MSBIC sync failures may be caused by multiple reasons: - The `coreos-bootimages` ConfigMap is unavailable or in an incorrect format. This will likely happen if a user manually edits the ConfigMap, overriding the CVO. - The `coreos-bootimages` ConfigMap takes too long to be stamped by the MCO. This indicates that there are larger problems in the cluster such as an upgrade failure/timeout or an unrelated cluster failure. +- The stub Ignition referenced in the `MachineSet` could not be upgraded to the spec 3 format. This will only happen when a user has heavily customized their Ignition stub, which is quite rare(and unsupported potentially). Resolving this will need manual intervention and this will be explained in the documentation. - Patching the `MachineSet` fails. This indicates a temporary API server blip, or larger RBAC issues. An error condition will be applied on the operator level `MachineConfiguration` object when the sync failures of a given `MachineSet` exceed a threshold amount for a period of time. The condition will include information regarding the sync failures and the logs of the MSBIC can be checked for additional details. -In addition to this, a Prometheus alert will also be triggered by the MSBIC. This alert will list the misbehaving `MachineSet` and will be cleared automatically by the MSBIC if the sync is successfully completed later. - Note: In the future, patches to `MachineSets` will be prevented when they are not authoritative [#1465](https://github.com/openshift/enhancements/pull/1465). This will need to be accounted for within the logic of the MSBIC. ### Workflow Description @@ -138,23 +135,29 @@ This work will be tracked in [MCO-793](https://issues.redhat.com/browse/MCO-793) ##### Projected timeline -This is a tentative timeline, subject to change (GA = General Availability(opt-in), TP = Tech Preview(opt-in), DEF = Default-on(opt-out)). +This is a tentative timeline for managed platforms, subject to change: -| Platform | TP | GA | DEF | +| Platform | TechPreview (opt-in) | GA (opt-in) | Default-On (opt-out) | | -------- | ------- | ------- | ------- | | gcp | [4.16](https://docs.redhat.com/en/documentation/openshift_container_platform/4.16/html-single/machine_configuration/index#mco-update-boot-images) |[4.17](https://docs.redhat.com/en/documentation/openshift_container_platform/4.17/html-single/machine_configuration/index#mco-update-boot-images) |4.19 | | aws | [4.17](https://docs.redhat.com/en/documentation/openshift_container_platform/4.17/html-single/machine_configuration/index#mco-update-boot-images) |[4.18](https://docs.redhat.com/en/documentation/openshift_container_platform/4.18/html-single/machine_configuration/index#mco-update-boot-images) |4.19 | | vsphere | 4.20 |4.21 |4.22 | | azure | 4.20 |4.21 |4.22 | -| baremetal| |4.22 |4.23 | -| openstack| |4.22 |4.23 | -| nutanix | |4.23 |4.24 | -| ibmcloud | |4.23 |4.24 | -| non-managed* | x |x |4.25 | +| baremetal| 4.21 |4.22 |4.23 | +| openstack| 4.21 |4.22 |4.23 | +| nutanix | 4.22 |4.23 |4.24 | +| ibmcloud | 4.22 |4.23 |4.24 | +| non-managed | * |* |4.23* | + +For **non-managed*** cases, boot image updates will be user initiated and supported via documentation. Hence, this will not be guarded by a feature gate, and the 4.23 timeline described above is for documentation. For managed cases, depending on initial feedback received from default-on behavior, it may be viable for the GA stage to be opt-out as well. This will be evaluated on a platform by platform basis. -Once default-on behavior has been deemed to be stable across the above mentioned platforms, skew enforcement will be implemented in a platform agnostic manner. Decoupling the default-on and skew enforcement mechanism would help iron out any edge cases unique to a platform and would also aid in refining the skew enforcement workflow. The tentative timeline for skew enforcement would be 4.25. +The skew enforcement mechanism could be developed in parallel to the above timeline, in a platform agnostic manner: +| | DevPreview | TechPreview | GA | +| -------- | ------- | ------- | ------- | +| skew management | 4.21 |4.22 |4.23* | + +Decoupling the default-on and skew enforcement mechanisms would help iron out any edge cases unique to a platform and would also aid in refining the skew enforcement workflow. It is important to note that while skew management could be developed independantly, it should only be deemed ready for **GA*** after most widely used platforms have reached the opt-out stage. This is to minimize user disruption as much as possible. -**Note** : For non-managed cases, * indicates enforcement of user-initiated bootimage updates. See enforcement section below. ##### Cluster API backed machinesets As the Cluster API move is impending(initial release in 4.16 and default-on release in 4.17), it is necessary that this enhancement plans for the changes required in an CAPI backed cluster. Here are a couple of sample YAMLs used in CAPI backed `Machinesets`, from the [official Openshift documentation](https://docs.openshift.com/container-platform/4.14/machine_management/capi-machine-management.html#capi-sample-yaml-files-gcp). @@ -455,34 +458,56 @@ status: partial: machineResourceSelector: matchLabels: {} -``` - +``` #### Skew Enforcement -As mentioned in the timeline section, this would only be implemented after default-on behavior has been deemed to be stable across -all platforms. -This would introduced as an new knob in the `ManagedBootImages` struct: +This would introduced as an new knob in the `MachineConfiguration` Spec: ``` -type ManagedBootImages struct { +type MachineConfigurationSpec struct { ... ... - // skewEnforcement allows an admin to set behavior of the boot image skew enforcement mechanism. - // Enabled means that the MCO will degrade and prevent upgrades when the boot image skew exceeds the - // skew limit described by the release image. - // Disabled means that the MCO will no longer degrade and will permit upgrades when the boot image - // exceeds the skew limit described by the release image. This will likely hinder the cluster's scaling ability. + // bootImageSkewEnforcement allows an admin to set the behavior of the boot image skew enforcement mechanism. // +optional - SkewEnforcement SkewEnforcementSelectorMode `json:"skewEnforcement"` + BootImageSkewEnforcement SkewEnforcementSelector `json:"bootImageSkewEnforcement"` +} + +// +kubebuilder:validation:XValidation:rule="has(self.mode) && (self.mode == 'Automatic' || self.mode =='Manual') ? has(self.bootImageOCPVersion) : !has(self.bootImageOCPVersion)",message="BootImageOCPVersion is required when type is Automatic or Manual, and forbidden otherwise" +// +union +type SkewEnforcementSelector struct { + // mode determines the underlying behavior of skew enforcement mechanism. + // Valid values are Automatic, Manual and Disabled. + // Automatic means that the MCO will store the OCP version associated with the last boot image update in the + // BootImageOCPVersion field. + // Manual means that the cluster admin is expected to perform manual boot image updates and store OCP version + // associated with the last boot image update in the BootImageOCPVersion field. + // In Automatic and Manual mode, the MCO will prevent upgrades when the boot image skew exceeds the + // skew limit described by the release image. + // Disabled means that the MCO will permit upgrades when the boot image exceeds the skew limit + // described by the release image. This may affect the cluster's ability to scale. + // +unionDiscriminator + // +kubebuilder:validation:Required + Mode SkewEnforcementSelectorMode `json:"mode"` + + // bootImageOCPVersion provides a string which will be used to enforce the skew limit. + // Only permitted when mode is set to "Automatic" or "Manual". + // +kubebuilder:validation:XValidation:rule="self.matches('^[0-9]*.[0-9]*.[0-9]*$')",message="bootImageOCPVersion must be in a semver compatible format of x.y.z" + // +kubebuilder:validation:MaxLength:=8 + // +optional + BootImageOCPVersion string `json:"bootImageOCPVersion,omitempty"` } + // SkewEnforcementSelectorMode is a string enum used to indicate the cluster's boot image skew enforcement mode. -// +kubebuilder:validation:Enum:="Enabled";"Disabled" +// +kubebuilder:validation:Enum:="Automatic";"Manual";"Disabled" type SkewEnforcementSelectorMode string const ( - // Enabled represents a configuration mode that enables boot image skew enforcement. - Enabled SkewEnforcementSelectorMode = "Enabled" + // Automatic represents a configuration mode that allows automatic skew enforcement. + Automatic SkewEnforcementSelectorMode = "Automatic" + + // Manual represents a configuration mode that allows manual skew enforcement. + Manual SkewEnforcementSelectorMode = "Manual" // Disabled represents a configuration mode that disables boot image skew enforcement. Disabled SkewEnforcementSelectorMode = "Disabled" @@ -605,8 +630,12 @@ status: The goal of this is to provide information about the "lineage" of a machine management resource to the user. The user can then manually restore their machine management resource to an earlier state if they wish to do so by following documentation. ### Implementation Details/Notes/Constraints [optional] +The reconciliation loop below is run on any `MachineSet` that is opted in for updates when any of the following in-cluster resources are added or updated: +1. A `MachineSet`'s providerSpec field. This is where a MachineSet's boot image references reference are stored. +2. The `coreos-bootimages` ConfigMap, which is the cluster's golden reference for boot images. This is typically updated by the CVO during an upgrade. +3. The singleton `MachineConfiguration` object called `cluster`. This is used to configure the Managed Boot Images feature. + -MachineSet Reconciliation Loop: ```mermaid flowchart-elk TD; @@ -615,8 +644,8 @@ flowchart-elk TD; MachineSetOwnerCheck -->|No| ConfigMapCheck[Has the coreos-bootimages ConfigMap been stamped by the MCO?] ; ConfigMapCheck -->|Yes|ArchType[Determine arch type of MachineSet, for eg: x86_64, aarch64] ; - ConfigMapCheck -->|No| Wait[A cluster upgrade is ongoing. Wait until at least 1 control plane node has completed an update.]; - Wait --> |Upgrade Complete| ArchType + ConfigMapCheck -->|No| Wait((Poll coreos-bootimages ConfigMap until it has been stamped)); + Wait --> |ConfigMap has been stamped| ArchType Wait --> |Timeout| Error ArchType -->PlatformType[Determine platform type of MachineSet, for eg: gcp, aws, vsphere] ; PlatformType -->ProviderSpec[Grab providerSpec from MachineSet, for eg: GCPProviderSpec, AWSProviderSpec etc] ; @@ -654,16 +683,18 @@ The UX element involved include the user opt-in and opt-out, which is currently This will be done on a platform by platform basis. Some key benchmarks have to be met for a platform to be considered ready for default on: - Sufficent runtime(say, at least 1 release) has been accumulated while boot image updates has been GAed for this platform. -- Periodic tests have been added for this platform in CI and have met certain passing metrics. +- Periodic tests have been added for this platform in CI and have met certain passing metrics. This should include Y stream upgrade e2es. - Any teams that are affected by default-on behavior have been notified and assisted with the transition. The default-on flow could look like this: ```mermaid flowchart-elk LR; - Start((Start)) -->MachineConfigurationCheck[Does the cluster currently have a boot image update configuration?] + Start((Start)) -->PlatformCheck[Does the cluster platform have boot image updates suppport?] + PlatformCheck -->|Yes|MachineConfigurationCheck[Does the cluster currently have a boot image update configuration?] + PlatformCheck -->|No| Stop ; MachineConfigurationCheck -->|Yes|Stop - MachineConfigurationCheck -->|No| UpdateConfig[The MCO will opt-in the cluster to boot image updates] ; + MachineConfigurationCheck -->|No| UpdateConfig["The MCO will inject a default configuration based on the platform, which could be opt-in or opt-out"] ; UpdateConfig --> Stop((Stop)); ``` Some points to note: @@ -675,34 +706,32 @@ Some points to note: ### Enforcement of bootimage skew -There should be some mechanism that will alert the user and fail if a cluster's bootimage are out of date. For example, at upgrade time, the MCO could signal to the CVO by setting Upgradeable=False. - -#### Acceptable skew +There should be some mechanism that will alert the user when a cluster's bootimage are out of date. To allow for this, the release payload will gain a new field, which will store the OCP version of the minimum acceptable boot image for that release. -The release payload will describe the current skew policy. The structure of this skew policy is TBD, but at the minimum it should describe the lowest acceptable boot image for the release. Generally speaking, we would like to keep the bootimage version aligned to the RHEL version we are shipping in the payload. For example, a 9.6 bootimage will be allowed until 9.8 is shipped via RHCOS. We would like to keep this customizable, such that any major breaking changes outside of RHEL major/minor can still be enforced as a one-off. +Generally speaking, we would like to keep the bootimage version aligned to the RHEL version we are shipping in the payload. For example, a 9.6 bootimage will be allowed until 9.8 is shipped via RHCOS. We would like to keep this customizable, such that any major breaking changes outside of RHEL major/minor can still be enforced as a one-off. #### Enforcement options Some combination of the following mechanisms should be implemented to alert users, particularly non-machineset backed scaled environments. The options generally fall under proactive enforcement (require users to either update or acknowledge risk before upgrading to a new version) vs. reactive enforcement (only fail when a non-compliant bootimage is being used to scale into the cluster). #### Proactive -Add a new field in the `coreos-bootimages` configmap in the MCO namespace that will store the cluster's current boot image and allows for easy comparison against the skew policy described in the release payload. - - For machineset backed clusters, this would be updated by the MSBIC after it succesfully updates boot images. - - For non-machineset backed clusters, this would be updated by the cluster admin to indicate the last manually updated bootimage. The cluster admin would need to update this configmap every few releases, when the RHEL minor on which the RHCOS container is built on changes (e.g. 9.6->9.8). +Add a new field in the `MachineConfiguration` object for configuration of the skew enforcement mechanism. More details about this can be found in the [API extensions section](#skew-enforcement). This field will store the OCP version of the cluster's current boot image and allows for easy comparison against the skew limit described in the release payload. + - For machineset backed clusters, this would be updated by the MSBIC after it succesfully updates boot images for all machine resources in the cluster. + - For non-machineset backed clusters, this would be updated by the cluster admin to indicate the last manually updated bootimage. The cluster admin would need to update this API object every few releases, when the RHEL minor on which the RHCOS container is built on changes (e.g. 9.6->9.8). -The cluster admin may also choose to opt-out of skew management via this configmap, which indicates that they will not require scaling nodes, and thereby opting out of skew enforcement and scaling functionality. +The cluster admin may also choose to opt-out of skew management via this field, acknowledge that their scaling ability may be limited. -A potential problem here is that the way boot images are stored in the machineset is lossy. In certain platforms, there is no way to recover the boot image metadata from the MachineSet. This is most likely to happen the first time the MCO attempts to do skew enforcement on a cluster that has never had boot image updates. In such cases, the MCO will default to the install time boot image, which can be recovered from the [aleph version](https://github.com/coreos/coreos-assembler/pull/768) of the control plane nodes. +This object can then be monitored to enforce skew limits. If the skew is determined to be too large, the MCO can update its `ClusterOperator` object with an `Upgradeable=False` condition, along with remediation steps in the `Condition` message. This will signal to the CVO that the cluster is not suitable for an upgrade. -This configmap can then be monitored to enforce skew limits. This could be done in a couple of ways. If the skew is determined to be too large, the MCO can update its `ClusterOperator` object with an `Upgradeable=False` condition, along with remediation steps in the `Condition` message. This will signal to the CVO that the cluster is not suitable for an upgrade. - -As stated earlier, to remediate, the cluster admin would then have to do one of the following: +To remediate, the cluster admin would then have to do one of the following: - Turn on boot image updates if it is a machineset backed cluster. -- Manually update the boot image and update the configmap if it is a non machineset backed cluster. +- Manually update the boot image and update the skew enforcement object if it is a non machineset backed cluster. - Opt-out of skew enforcement altogether, giving up scaling ability. +A potential problem here is that the way boot images are stored in the machineset is lossy. In certain platforms, there is no way to recover the boot image metadata from the MachineSet. This is most likely to happen the first time the MCO attempts to do skew enforcement on a cluster that has never had boot image updates. In such cases, the MCO will use the OCP version from install time to determine skew instead. + #### Reactive -1. Have the MCS reject new ignition requests if the aformentioned configmap indicates that the cluster's bootimages are out of date. The MCS could then signal to the cluster admin that scale-up is not available until the configmap has been reconciled. +1. Have the MCS reject new ignition requests if the aformentioned object indicates that the cluster's bootimages are out of date. The MCS would then signal to the cluster admin that scale-up is not available until the skew has been resolved. Raising the alarm from the MCS at the cluster level will help prevent avoid additional noise for the cluster infra team, and make apparent that the scaling failure was intentional. The MCS will also attempt to serve an Ignition config that writes a message to `/etc/issue` explaining that the bootimage is too old, which will be visible from the node's console. 2. Add a service to be shipped via RHCOS/MCO templates, which will do a check on incoming OS container image vs currently booted RHCOS version. This runs on firstboot right after the MCD pulls the new image, and will prevent the node to rebase to the updated image if the drift is too far. RHEL major versions will no longer be cross-compatible. i.e. if you wish to have a RHEL10 machineconfigpool, you must use a RHEL10 bootimage. From 95759fc963f8fcf6ec48d3a5f5d759362aed55b1 Mon Sep 17 00:00:00 2001 From: David Date: Thu, 24 Apr 2025 15:13:02 -0400 Subject: [PATCH 5/9] timeline updatge --- enhancements/machine-config/manage-boot-images.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/enhancements/machine-config/manage-boot-images.md b/enhancements/machine-config/manage-boot-images.md index b9b2bf0427..68248e7b69 100644 --- a/enhancements/machine-config/manage-boot-images.md +++ b/enhancements/machine-config/manage-boot-images.md @@ -143,13 +143,12 @@ This is a tentative timeline for managed platforms, subject to change: | aws | [4.17](https://docs.redhat.com/en/documentation/openshift_container_platform/4.17/html-single/machine_configuration/index#mco-update-boot-images) |[4.18](https://docs.redhat.com/en/documentation/openshift_container_platform/4.18/html-single/machine_configuration/index#mco-update-boot-images) |4.19 | | vsphere | 4.20 |4.21 |4.22 | | azure | 4.20 |4.21 |4.22 | -| baremetal| 4.21 |4.22 |4.23 | | openstack| 4.21 |4.22 |4.23 | -| nutanix | 4.22 |4.23 |4.24 | +| nutanix | 4.21 |4.22 |4.23 | | ibmcloud | 4.22 |4.23 |4.24 | | non-managed | * |* |4.23* | -For **non-managed*** cases, boot image updates will be user initiated and supported via documentation. Hence, this will not be guarded by a feature gate, and the 4.23 timeline described above is for documentation. For managed cases, depending on initial feedback received from default-on behavior, it may be viable for the GA stage to be opt-out as well. This will be evaluated on a platform by platform basis. +For **non-managed***(including baremetal) cases, boot image updates will be user initiated and supported via documentation. Hence, this will not be guarded by a feature gate, and the 4.23 timeline described above is for documentation. For managed cases, depending on initial feedback received from default-on behavior, it may be viable for the GA stage to be opt-out as well. This will be evaluated on a platform by platform basis. The skew enforcement mechanism could be developed in parallel to the above timeline, in a platform agnostic manner: | | DevPreview | TechPreview | GA | @@ -494,7 +493,7 @@ type SkewEnforcementSelector struct { // +kubebuilder:validation:XValidation:rule="self.matches('^[0-9]*.[0-9]*.[0-9]*$')",message="bootImageOCPVersion must be in a semver compatible format of x.y.z" // +kubebuilder:validation:MaxLength:=8 // +optional - BootImageOCPVersion string `json:"bootImageOCPVersion,omitempty"` + BootImageOCPVersion string `json:"bootImageOCPVersion,omitempty"` } From 7d37a633ef1b68c5c38c186591ed30238160ca90 Mon Sep 17 00:00:00 2001 From: David Date: Wed, 28 May 2025 15:28:02 -0400 Subject: [PATCH 6/9] updated skew API, rootCA & reactive methods clarification --- .../machine-config/manage-boot-images.md | 58 ++++++++++++------- 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/enhancements/machine-config/manage-boot-images.md b/enhancements/machine-config/manage-boot-images.md index 68248e7b69..56bb5b1829 100644 --- a/enhancements/machine-config/manage-boot-images.md +++ b/enhancements/machine-config/manage-boot-images.md @@ -46,8 +46,9 @@ Currently, bootimage references are [stored](https://github.com/openshift/instal - skopeo [[1](https://issues.redhat.com/browse/OCPBUGS-3621)] - composefs [[1](https://github.com/openshift/os/issues/1678#issuecomment-2546310833)] - sigstore GA [[1](https://issues.redhat.com/browse/OCPNODE-2619)],[[2](https://issues.redhat.com/browse/OCPBUGS-38809)] +- aarch64 bootloaders [[1](https://issues.redhat.com/browse/COS-3240)] -Additionally, the stub Ignition config [referenced](https://github.com/openshift/installer/blob/1ca0848f0f8b2ca9758493afa26bf43ebcd70410/pkg/asset/machines/gcp/machines.go#L197) in the `MachineSet` is also not managed. This stub is also generated by the installer, and it typically consists of an endpoint and a Certificate Authority(CA), which are used by the ignition binary in firstboot to auth and consume content from the `machine-config-server`(MCS). This CA is called the [`RootCA`](https://github.com/openshift/installer/blob/99b48742d2f89b4978fe14cb6fe842e283c0ce4d/pkg/asset/tls/root.go#L19-L20) by the installer which is bit of a misnomer, as it does not give actual root access to the cluster - it is only used to generate the MCS TLS cert pair. Going forward, the proposal will be refer to these artifacts as the MCS CA & TLS cert. In 4.19, the MCO took ownership of [rotating the MCS CA & TLS cert](https://issues.redhat.com/browse/MCO-1208). +Additionally, the stub Ignition config [referenced](https://github.com/openshift/installer/blob/1ca0848f0f8b2ca9758493afa26bf43ebcd70410/pkg/asset/machines/gcp/machines.go#L197) in the `MachineSet` is also not managed. This stub is also generated by the installer, and it typically consists of an endpoint and a Certificate Authority(CA), which are used by the ignition binary in firstboot to auth and consume content from the `machine-config-server`(MCS). This CA is called the [`RootCA`](https://github.com/openshift/installer/blob/99b48742d2f89b4978fe14cb6fe842e283c0ce4d/pkg/asset/tls/root.go#L19-L20) and is only used to generate the MCS TLS cert pair. Going forward, the proposal will be refer to these artifacts as the MCS CA & TLS cert. In 4.19, the MCO took ownership of [rotating the MCS CA & TLS cert](https://issues.redhat.com/browse/MCO-1208). The content served by the MCS includes the actual Ignition configuration and the target OCI format RHCOS image. The ignition binary now does first boot provisioning based on this, then hands off to the `machine-config-daemon`(MCD) first boot service to do the reboot into the target OCI format RHCOS image. @@ -95,9 +96,9 @@ __Overview__ MSBIC sync failures may be caused by multiple reasons: - The `coreos-bootimages` ConfigMap is unavailable or in an incorrect format. This will likely happen if a user manually edits the ConfigMap, overriding the CVO. -- The `coreos-bootimages` ConfigMap takes too long to be stamped by the MCO. This indicates that there are larger problems in the cluster such as an upgrade failure/timeout or an unrelated cluster failure. - The stub Ignition referenced in the `MachineSet` could not be upgraded to the spec 3 format. This will only happen when a user has heavily customized their Ignition stub, which is quite rare(and unsupported potentially). Resolving this will need manual intervention and this will be explained in the documentation. - Patching the `MachineSet` fails. This indicates a temporary API server blip, or larger RBAC issues. +- The same `MachineSet` is patched multiple times to the same boot image. This indicates that there is atleast one external actor actively stomping on the value applied by the MSBIC. An error condition will be applied on the operator level `MachineConfiguration` object when the sync failures of a given `MachineSet` exceed a threshold amount for a period of time. The condition will include information regarding the sync failures and the logs of the MSBIC can be checked for additional details. @@ -461,41 +462,56 @@ status: #### Skew Enforcement +Note: This section is still a WIP and will require thorough API review. Once the form of the API has been settled, this will be updated again. + This would introduced as an new knob in the `MachineConfiguration` Spec: ``` type MachineConfigurationSpec struct { ... ... - // bootImageSkewEnforcement allows an admin to set the behavior of the boot image skew enforcement mechanism. - // +optional - BootImageSkewEnforcement SkewEnforcementSelector `json:"bootImageSkewEnforcement"` + // bootImageSkewEnforcement allows an admin to set the behavior of the boot image skew enforcement mechanism. + // +optional + BootImageSkewEnforcement SkewEnforcementSelector `json:"bootImageSkewEnforcement"` } -// +kubebuilder:validation:XValidation:rule="has(self.mode) && (self.mode == 'Automatic' || self.mode =='Manual') ? has(self.bootImageOCPVersion) : !has(self.bootImageOCPVersion)",message="BootImageOCPVersion is required when type is Automatic or Manual, and forbidden otherwise" +// +kubebuilder:validation:XValidation:rule="has(self.mode) && (self.mode == 'Automatic' || self.mode =='Manual') ? has(self.clusterBootImage) : !has(self.clusterBootImage)",message="clusterBootImage is required when type is Automatic or Manual, and forbidden otherwise" // +union type SkewEnforcementSelector struct { // mode determines the underlying behavior of skew enforcement mechanism. // Valid values are Automatic, Manual and Disabled. // Automatic means that the MCO will store the OCP version associated with the last boot image update in the - // BootImageOCPVersion field. - // Manual means that the cluster admin is expected to perform manual boot image updates and store OCP version - // associated with the last boot image update in the BootImageOCPVersion field. - // In Automatic and Manual mode, the MCO will prevent upgrades when the boot image skew exceeds the + // clusterBootImage field. + // Manual means that the cluster admin is expected to perform manual boot image updates and store OCP version + // associated with the last boot image update in the clusterBootImage field. + // In Automatic and Manual mode, the MCO will prevent upgrades when the boot image skew exceeds the // skew limit described by the release image. - // Disabled means that the MCO will permit upgrades when the boot image exceeds the skew limit - // described by the release image. This may affect the cluster's ability to scale. + // Disabled means that the MCO will permit upgrades when the boot image exceeds the skew limit + // described by the release image. This may affect the cluster's ability to scale. // +unionDiscriminator - // +kubebuilder:validation:Required + // +required Mode SkewEnforcementSelectorMode `json:"mode"` - // bootImageOCPVersion provides a string which will be used to enforce the skew limit. + // clusterBootImage describes the current boot image of the cluster. This will be used to enforce the skew limit. // Only permitted when mode is set to "Automatic" or "Manual". - // +kubebuilder:validation:XValidation:rule="self.matches('^[0-9]*.[0-9]*.[0-9]*$')",message="bootImageOCPVersion must be in a semver compatible format of x.y.z" - // +kubebuilder:validation:MaxLength:=8 // +optional - BootImageOCPVersion string `json:"bootImageOCPVersion,omitempty"` + ClusterBootImage ClusterBootImage `json:"clusterBootImage,omitempty"` } +// MachineManager describes a target machine resource that is registered for boot image updates. It stores identifying information +// such as the resource type and the API Group of the resource. It also provides granular control via the selection field. +type ClusterBootImage struct { + // ocpVersion provides a string which represents the OCP version of the boot image + // +kubebuilder:validation:XValidation:rule="self.matches('^[0-9]*.[0-9]*.[0-9]*$')",message="bootImageOCPVersion must be in a semver compatible format of x.y.z" + // +kubebuilder:validation:MaxLength:=8 + // +required + OCPVersion string `json:"ocpVersion"` + + // rhcosVersion provides a string which represents the RHCOS version of the boot image + // +kubebuilder:validation:XValidation:rule="self.matches('^[0-9]*.[0-9]*$')",message="rhcosVersion must be in a semver compatible format of x.y" + // +kubebuilder:validation:MaxLength:=8 + // +optional + RHCOSVersion string `json:"rhcosVersion,omitempty"` +} // SkewEnforcementSelectorMode is a string enum used to indicate the cluster's boot image skew enforcement mode. // +kubebuilder:validation:Enum:="Automatic";"Manual";"Disabled" @@ -705,7 +721,7 @@ Some points to note: ### Enforcement of bootimage skew -There should be some mechanism that will alert the user when a cluster's bootimage are out of date. To allow for this, the release payload will gain a new field, which will store the OCP version of the minimum acceptable boot image for that release. +There should be some mechanism that will alert the user when a cluster's bootimage are out of date. To allow for this, the `coreos-bootimages` configmap will gain a new field, which will store the the boot image required for upgrading to the next y stream release. Generally speaking, we would like to keep the bootimage version aligned to the RHEL version we are shipping in the payload. For example, a 9.6 bootimage will be allowed until 9.8 is shipped via RHCOS. We would like to keep this customizable, such that any major breaking changes outside of RHEL major/minor can still be enforced as a one-off. @@ -715,12 +731,12 @@ Some combination of the following mechanisms should be implemented to alert user #### Proactive Add a new field in the `MachineConfiguration` object for configuration of the skew enforcement mechanism. More details about this can be found in the [API extensions section](#skew-enforcement). This field will store the OCP version of the cluster's current boot image and allows for easy comparison against the skew limit described in the release payload. - - For machineset backed clusters, this would be updated by the MSBIC after it succesfully updates boot images for all machine resources in the cluster. + - For machineset backed clusters, this would be updated by the MSBIC after it successfully updates boot images for all machine resources in the cluster. - For non-machineset backed clusters, this would be updated by the cluster admin to indicate the last manually updated bootimage. The cluster admin would need to update this API object every few releases, when the RHEL minor on which the RHCOS container is built on changes (e.g. 9.6->9.8). The cluster admin may also choose to opt-out of skew management via this field, acknowledge that their scaling ability may be limited. -This object can then be monitored to enforce skew limits. If the skew is determined to be too large, the MCO can update its `ClusterOperator` object with an `Upgradeable=False` condition, along with remediation steps in the `Condition` message. This will signal to the CVO that the cluster is not suitable for an upgrade. +This object can then be monitored to enforce skew limits. If the skew is determined to be too large, the MCO can update its `ClusterOperator` object with an `Upgradeable=False` condition, along with remediation steps in the `Condition` message. This will signal to the CVO that the cluster is not suitable for an upgrade to the next y stream release. To remediate, the cluster admin would then have to do one of the following: - Turn on boot image updates if it is a machineset backed cluster. @@ -730,7 +746,7 @@ To remediate, the cluster admin would then have to do one of the following: A potential problem here is that the way boot images are stored in the machineset is lossy. In certain platforms, there is no way to recover the boot image metadata from the MachineSet. This is most likely to happen the first time the MCO attempts to do skew enforcement on a cluster that has never had boot image updates. In such cases, the MCO will use the OCP version from install time to determine skew instead. #### Reactive -1. Have the MCS reject new ignition requests if the aformentioned object indicates that the cluster's bootimages are out of date. The MCS would then signal to the cluster admin that scale-up is not available until the skew has been resolved. Raising the alarm from the MCS at the cluster level will help prevent avoid additional noise for the cluster infra team, and make apparent that the scaling failure was intentional. The MCS will also attempt to serve an Ignition config that writes a message to `/etc/issue` explaining that the bootimage is too old, which will be visible from the node's console. +1. Have the MCS reject new ignition requests if the aformentioned object indicates that the cluster's bootimages are out of date. The MCS would then signal to the cluster admin that scale-up is not available until the skew has been resolved. Raising the alarm from the MCS at the cluster level will help prevent additional noise for the cluster infra team, and make apparent that the scaling failure was intentional. The MCS will also attempt to serve an Ignition config that writes a message to `/etc/issue` explaining that the bootimage is too old, which will be visible from the node's console. 2. Add a service to be shipped via RHCOS/MCO templates, which will do a check on incoming OS container image vs currently booted RHCOS version. This runs on firstboot right after the MCD pulls the new image, and will prevent the node to rebase to the updated image if the drift is too far. RHEL major versions will no longer be cross-compatible. i.e. if you wish to have a RHEL10 machineconfigpool, you must use a RHEL10 bootimage. From 783cfaf528085f30f8af9f0171b342e8d55b82aa Mon Sep 17 00:00:00 2001 From: David Date: Tue, 3 Jun 2025 15:18:45 -0400 Subject: [PATCH 7/9] minor fixes --- enhancements/machine-config/manage-boot-images.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/enhancements/machine-config/manage-boot-images.md b/enhancements/machine-config/manage-boot-images.md index 56bb5b1829..3a0d98b05e 100644 --- a/enhancements/machine-config/manage-boot-images.md +++ b/enhancements/machine-config/manage-boot-images.md @@ -98,7 +98,7 @@ MSBIC sync failures may be caused by multiple reasons: - The `coreos-bootimages` ConfigMap is unavailable or in an incorrect format. This will likely happen if a user manually edits the ConfigMap, overriding the CVO. - The stub Ignition referenced in the `MachineSet` could not be upgraded to the spec 3 format. This will only happen when a user has heavily customized their Ignition stub, which is quite rare(and unsupported potentially). Resolving this will need manual intervention and this will be explained in the documentation. - Patching the `MachineSet` fails. This indicates a temporary API server blip, or larger RBAC issues. -- The same `MachineSet` is patched multiple times to the same boot image. This indicates that there is atleast one external actor actively stomping on the value applied by the MSBIC. +- The same `MachineSet` is patched multiple times to the same boot image. This indicates that there is at least one external actor actively stomping on the value applied by the MSBIC. An error condition will be applied on the operator level `MachineConfiguration` object when the sync failures of a given `MachineSet` exceed a threshold amount for a period of time. The condition will include information regarding the sync failures and the logs of the MSBIC can be checked for additional details. @@ -646,7 +646,7 @@ The goal of this is to provide information about the "lineage" of a machine mana ### Implementation Details/Notes/Constraints [optional] The reconciliation loop below is run on any `MachineSet` that is opted in for updates when any of the following in-cluster resources are added or updated: -1. A `MachineSet`'s providerSpec field. This is where a MachineSet's boot image references reference are stored. +1. A `MachineSet`'s providerSpec field. This is where a MachineSet's boot image references are stored. 2. The `coreos-bootimages` ConfigMap, which is the cluster's golden reference for boot images. This is typically updated by the CVO during an upgrade. 3. The singleton `MachineConfiguration` object called `cluster`. This is used to configure the Managed Boot Images feature. @@ -721,7 +721,7 @@ Some points to note: ### Enforcement of bootimage skew -There should be some mechanism that will alert the user when a cluster's bootimage are out of date. To allow for this, the `coreos-bootimages` configmap will gain a new field, which will store the the boot image required for upgrading to the next y stream release. +There should be some mechanism that will alert the user when a cluster's bootimage are out of date. To allow for this, the `coreos-bootimages` configmap will gain a new field, which will store the boot image required for upgrading to the next y stream release. Generally speaking, we would like to keep the bootimage version aligned to the RHEL version we are shipping in the payload. For example, a 9.6 bootimage will be allowed until 9.8 is shipped via RHCOS. We would like to keep this customizable, such that any major breaking changes outside of RHEL major/minor can still be enforced as a one-off. From d4507d04249245d327f279717ce9b90ed84ef4de Mon Sep 17 00:00:00 2001 From: David Date: Tue, 3 Jun 2025 16:30:50 -0400 Subject: [PATCH 8/9] minor fixes and clarify non MCS scenario --- enhancements/machine-config/manage-boot-images.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/enhancements/machine-config/manage-boot-images.md b/enhancements/machine-config/manage-boot-images.md index 3a0d98b05e..0a84bdce28 100644 --- a/enhancements/machine-config/manage-boot-images.md +++ b/enhancements/machine-config/manage-boot-images.md @@ -277,7 +277,7 @@ type MachineManagerSelector struct { // Valid values are All and Partial. // All means that every resource matched by the machine manager will be updated. // Partial requires specified selector(s) and allows customisation of which resources matched by the machine manager will be updated. - // None means that every resource matched by the machine manager will NOT be updated. + // None means that every resource matched by the machine manager will NOT be updated. // +unionDiscriminator // +kubebuilder:validation:Required Mode MachineManagerSelectorMode `json:"mode"` @@ -464,7 +464,7 @@ status: Note: This section is still a WIP and will require thorough API review. Once the form of the API has been settled, this will be updated again. -This would introduced as an new knob in the `MachineConfiguration` Spec: +This would be introduced as a new knob in the `MachineConfiguration` Spec: ``` type MachineConfigurationSpec struct { ... @@ -497,8 +497,8 @@ type SkewEnforcementSelector struct { ClusterBootImage ClusterBootImage `json:"clusterBootImage,omitempty"` } -// MachineManager describes a target machine resource that is registered for boot image updates. It stores identifying information -// such as the resource type and the API Group of the resource. It also provides granular control via the selection field. +// ClusterBootImage describes the boot image of a cluster. It stores the RHCOS version of the boot image and +// the OCP release version which shipped with that RHCOS boot image. type ClusterBootImage struct { // ocpVersion provides a string which represents the OCP version of the boot image // +kubebuilder:validation:XValidation:rule="self.matches('^[0-9]*.[0-9]*.[0-9]*$')",message="bootImageOCPVersion must be in a semver compatible format of x.y.z" @@ -734,7 +734,7 @@ Add a new field in the `MachineConfiguration` object for configuration of the sk - For machineset backed clusters, this would be updated by the MSBIC after it successfully updates boot images for all machine resources in the cluster. - For non-machineset backed clusters, this would be updated by the cluster admin to indicate the last manually updated bootimage. The cluster admin would need to update this API object every few releases, when the RHEL minor on which the RHCOS container is built on changes (e.g. 9.6->9.8). -The cluster admin may also choose to opt-out of skew management via this field, acknowledge that their scaling ability may be limited. +The cluster admin may also choose to opt-out of skew management via this field, acknowledging that their scaling ability may be limited. This object can then be monitored to enforce skew limits. If the skew is determined to be too large, the MCO can update its `ClusterOperator` object with an `Upgradeable=False` condition, along with remediation steps in the `Condition` message. This will signal to the CVO that the cluster is not suitable for an upgrade to the next y stream release. @@ -747,7 +747,7 @@ A potential problem here is that the way boot images are stored in the machinese #### Reactive 1. Have the MCS reject new ignition requests if the aformentioned object indicates that the cluster's bootimages are out of date. The MCS would then signal to the cluster admin that scale-up is not available until the skew has been resolved. Raising the alarm from the MCS at the cluster level will help prevent additional noise for the cluster infra team, and make apparent that the scaling failure was intentional. The MCS will also attempt to serve an Ignition config that writes a message to `/etc/issue` explaining that the bootimage is too old, which will be visible from the node's console. -2. Add a service to be shipped via RHCOS/MCO templates, which will do a check on incoming OS container image vs currently booted RHCOS version. This runs on firstboot right after the MCD pulls the new image, and will prevent the node to rebase to the updated image if the drift is too far. +2. Add a service to be shipped via RHCOS/MCO templates, which will do a check on incoming OS container image vs currently booted RHCOS version. This runs on firstboot right after the MCD pulls the new image, and will prevent the node to rebase to the updated image if the drift is too far. This would cover environments that do not use the MCS such as [installing via ISO on bare metal](https://docs.redhat.com/en/documentation/openshift_container_platform/4.18/html/installing_on_bare_metal/user-provisioned-infrastructure#installation-user-infra-machines-iso_installing-bare-metal). RHEL major versions will no longer be cross-compatible. i.e. if you wish to have a RHEL10 machineconfigpool, you must use a RHEL10 bootimage. From d5046280a4d5c8b4ca85dcc780748b0c02f3570f Mon Sep 17 00:00:00 2001 From: David Date: Wed, 4 Jun 2025 15:38:30 -0400 Subject: [PATCH 9/9] clarify skew limit & install boot image version --- enhancements/machine-config/manage-boot-images.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/enhancements/machine-config/manage-boot-images.md b/enhancements/machine-config/manage-boot-images.md index 0a84bdce28..5cd619ce66 100644 --- a/enhancements/machine-config/manage-boot-images.md +++ b/enhancements/machine-config/manage-boot-images.md @@ -723,7 +723,7 @@ Some points to note: There should be some mechanism that will alert the user when a cluster's bootimage are out of date. To allow for this, the `coreos-bootimages` configmap will gain a new field, which will store the boot image required for upgrading to the next y stream release. -Generally speaking, we would like to keep the bootimage version aligned to the RHEL version we are shipping in the payload. For example, a 9.6 bootimage will be allowed until 9.8 is shipped via RHCOS. We would like to keep this customizable, such that any major breaking changes outside of RHEL major/minor can still be enforced as a one-off. +Generally speaking, we would like to keep the minimum required bootimage version aligned to the RHEL version we are shipping in the payload and constant for a given release's z stream. For example, a 9.6 bootimage will be allowed until 9.8 is shipped via RHCOS. We would like to keep this customizable, such that any major breaking changes outside of RHEL major/minor can still be enforced as a one-off. #### Enforcement options @@ -743,7 +743,7 @@ To remediate, the cluster admin would then have to do one of the following: - Manually update the boot image and update the skew enforcement object if it is a non machineset backed cluster. - Opt-out of skew enforcement altogether, giving up scaling ability. -A potential problem here is that the way boot images are stored in the machineset is lossy. In certain platforms, there is no way to recover the boot image metadata from the MachineSet. This is most likely to happen the first time the MCO attempts to do skew enforcement on a cluster that has never had boot image updates. In such cases, the MCO will use the OCP version from install time to determine skew instead. +A potential problem here is that the way boot images are stored in the machineset is lossy. In certain platforms, there is no way to recover the boot image metadata from the MachineSet. This is most likely to happen the first time the MCO attempts to do skew enforcement on a cluster that has never had boot image updates. In such cases, the MCO will use the OCP version from install time(derived from the [`clusterversion`](https://github.com/openshift/enhancements/blob/master/enhancements/update/clusterversion-history-pruning.md) object) to determine skew instead. #### Reactive 1. Have the MCS reject new ignition requests if the aformentioned object indicates that the cluster's bootimages are out of date. The MCS would then signal to the cluster admin that scale-up is not available until the skew has been resolved. Raising the alarm from the MCS at the cluster level will help prevent additional noise for the cluster infra team, and make apparent that the scaling failure was intentional. The MCS will also attempt to serve an Ignition config that writes a message to `/etc/issue` explaining that the bootimage is too old, which will be visible from the node's console.