You can use the image mode for OpenShift on-cluster build process to apply a custom layered image to your nodes by creating a MachineOSConfig
custom resource (CR), as described in "Using On-cluster image mode to apply a custom layered image".
When you create the object, the Machine Config Operator (MCO) creates a MachineOSBuild
object and a builder pod. The process also creates transient objects, such as config maps, which are cleaned up after the build is complete. The MachineOSBuild
object and the associated builder-*
pod use the same naming scheme, <MachineOSConfig_CR_name>-<hash>
, for example:
Example MachineOSBuild
object
NAME PREPARED BUILDING SUCCEEDED INTERRUPTED FAILED
layered-image-c8765e26ebc87e1e17a7d6e0a78e8bae False False True False False
Example builder pod
NAME READY STATUS RESTARTS AGE
build-layered-image-c8765e26ebc87e1e17a7d6e0a78e8bae 2/2 Running 0 11m
You should not need to interact with these new objects or the machine-os-builder
pod. However, you can use all of these resources for troubleshooting, if necessary.
When the build is complete, the MCO pushes the new custom layered image to your repository and rolls the image out to the nodes in the associated machine config pool. You can see the digested image pull spec for the new custom layered image in the MachineOSConfig
object. This is now the active image pull spec for this MachineOSConfig
.
Example digested image pull spec
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineOSConfig
metadata:
annotations:
machineconfiguration.openshift.io/current-machine-os-build: layered-9a8f89455246fa0c42ecee6ff1fa1a45
labels:
machineconfiguration.openshift.io/createdByOnClusterBuildsHelper: ""
name: layered-image
# ...
status:
currentImagePullSpec: image-registry.openshift-image-registry.svc:5000/openshift-machine-config-operator/os-image@sha256:3c8fc667adcb432ce0c83581f16086afec08a961dd28fed69bb6bad6db0a0754
|
You can test a MachineOSBuild object to make sure it builds correctly without rolling out the custom layered image to active nodes by using a custom machine config pool that contains non-production nodes. Alternatively, you can use a custom machine config pool that has no nodes. The MachineOSBuild object builds even if there are no nodes for the MCO to deploy the custom layered image onto.
|
You can apply a custom layered image to any machine config pool in your cluster, including the control plane, worker, or custom pools.
|
For single-node OpenShift clusters, you can apply a custom layered image to the control plane node only.
|
Making certain changes to a MachineOSConfig
object triggers an automatic rebuild of the associated custom layered image. You can mitigate the effects of the rebuild by pausing the machine config pool where the custom layered image is applied as described in "Pausing the machine config pools". While the pools are paused, the MCO does not roll out the newly built image to the nodes after the build is complete. However, the build runs regardless of whether the pool is paused or not. For example, if you want to remove and replace a MachineOSCOnfig
object, pausing the machine config pools before making the change prevents the MCO from reverting the associated nodes to the base image, reducing the number of reboots needed.
When a machine config pool is paused, the oc get machineconfigpools
reports the following status:
Example output
NAME CONFIG UPDATED UPDATING DEGRADED MACHINECOUNT READYMACHINECOUNT UPDATEDMACHINECOUNT DEGRADEDMACHINECOUNT AGE
master rendered-master-a0b404d061a6183cc36d302363422aba True False False 3 3 3 0 4h14m
worker rendered-worker-221507009cbcdec0eec8ab3ccd789d18 False False False 2 2 2 0 4h14m (1)
1 |
The worker machine config pool is paused, as indicated by the three False statuses and the READYMACHINECOUNT at 0 . |
After the changes have been rolled out, you can unpause the machine config pool.
In the case of a build failure, for example due to network issues or an invalid secret, the MCO retries the build three additional times before the job fails. The MCO creates a different build pod for each build attempt. You can use the build pod logs to troubleshoot any build failures. Note that the MCO automatically removes these build pods after a short period of time.
Example failed MachineOSBuild
object
NAME PREPARED BUILDING SUCCEEDED INTERRUPTED FAILED AGE
layered-image-c8765e26ebc87e1e17a7d6e0a78e8bae False False False False True 12m
You can manually rebuild your custom layered image by either modifying your MachineOSConfig
object or applying an annotation to the MachineOSConfig
object. For more information, see "Rebuilding an on-cluster custom layered image".
If you used a custom machine config pool to apply an on-cluster layered image to a node, you can remove the custom layered image from the node and revert to the base image. For more information, see "Reverting an on-cluster layered node".
You can modify an on-custom layered image as needed, to install additional packages, remove existing packages, change repositories, update secrets, or other similar changes, by editing the MachineOSConfig object. For more information, see "Modifying a custom layered image".
On-cluster image mode known limitations
Note the following limitations when working with the on-cluster layering feature:
-
On-cluster image mode is not supported on multi-architecture compute machines.
-
Using multiple MachineOSConfig
objects on the same machine config pool is not supported. You need a separate MachineOSConfig
CR for each machine config pool where you want to use a distinct custom layered image.
-
If you scale up a machine set that uses a custom layered image, the nodes reboot two times. The first, when the node is initially created with the base image and a second time when the custom layered image is applied.
-
Node disruption policies are not supported on nodes with a custom layered image. As a result the following configuration changes cause a node reboot:
-
Modifying the configuration files in the /var
or /etc
directory
-
Adding or modifying a systemd service
-
Changing SSH keys
-
Removing mirroring rules from ICSP
, ITMS
, and IDMS
objects
-
Changing the trusted CA, by updating the user-ca-bundle
configmap in the openshift-config
namespace
-
The images used in creating custom layered images take up space in your push registry. Always be aware of the free space in your registry and prune the images as needed. You can automatically remove an on-cluster custom layered image from the repository by deleting the MachineOSBuild
object that created the image. Note that the credentials provided by the registry push secret must also grant permission to delete an image from the registry. For more information, see "Removing an on-cluster custom layered image".
Using the on-cluster image mode to apply a custom layered image
To apply a custom layered image to your cluster by using the on-cluster build process, create a MachineOSConfig
custom resource (CR) that specifies the following parameters:
-
the Containerfile to build
-
the machine config pool to associate the build
-
where the final image should be pushed and pulled from
-
the push and pull secrets to use
Prerequisites
-
You have the pull secret in the openshift-machine-config-operator
namespace that the Machine Config Operator (MCO) needs in order to pull the base operating system image from your repository. By default, the MCO uses the cluster global pull secret, which it synchronizes into the openshift-machine-config-operator
namespace. You can add your pull secret to the OKD global pull secret or you can use a different pull secret. For information on modifying the global pull secret, see "Updating the global cluster pull secret".
-
You have the push secret of the registry that the MCO needs to push the new custom layered image to. The credentials provided by the secret must also grant permission to delete an image from the registry.
|
In a disconnected environment, ensure that the disconnected cluster can access the registry where you want to push the image. Image mirroring applies only to pulling images.
|
-
You have the pull secret that your nodes need to pull the new custom layered image from your registry. This should be a different secret than the one used to push the image to the repository.
-
You are familiar with how to configure a Containerfile. Instructions on how to create a Containerfile are beyond the scope of this documentation.
-
Optional: You have a separate machine config pool for the nodes where you want to apply the custom layered image. One benefit to having a custom machine config pool for the nodes it that you can easily revert to the base image, if needed. For more information, see "Reverting an on-cluster layered node".
Procedure
-
Create a MachineOSconfig
object:
-
Create a YAML file similar to the following:
apiVersion: machineconfiguration.openshift.io/v1 (1)
kind: MachineOSConfig
metadata:
name: layered-image (2)
spec:
machineConfigPool:
name: layered (3)
containerFile: (4)
- containerfileArch: NoArch (5)
content: |-
FROM configs AS final
RUN dnf install -y cowsay && \
dnf clean all && \
ostree container commit
imageBuilder: (6)
imageBuilderType: Job
baseImagePullSecret: (7)
name: global-pull-secret-copy
renderedImagePushSpec: image-registry.openshift-image-registry.svc:5000/openshift/os-image:latest (8)
renderedImagePushSecret: (9)
name: builder-dockercfg-mtcl23
1 |
Specifies the machineconfiguration.openshift.io/v1 API that is required for MachineConfig CRs. |
2 |
Specifies a name for the MachineOSConfig object. This name is used with other [image-mode-os-on-lower] resources. The examples in this documentation use the name layered-image . |
3 |
Specifies the name of the machine config pool associated with the nodes where you want to deploy the custom layered image. The examples in this documentation use the layered machine config pool. |
4 |
Specifies the Containerfile to configure the custom layered image. |
5 |
Specifies the architecture this containerfile is to be built for: ARM64 , AMD64 , PPC64LE , S390X , or NoArch . The default is NoArch , which defines a Containerfile that can be applied to any architecture. |
6 |
Specifies the name of the image builder to use. This must be Job , which is a reference to the job object that is managing the image build. |
7 |
Optional: Specifies the name of the pull secret that the MCO needs to pull the base operating system image from the registry. By default, the global pull secret is used. |
8 |
Specifies the image registry to push the newly-built custom layered image to. This can be any registry that your cluster has access to in the host[:port][/namespace]/name or svc_name.namespace.svc[:port]/repository/name:<tag> format. This example uses the internal OKD registry. You can specify a mirror registry if you cluster is properly configured to use a mirror registry. |
9 |
Specifies the name of the push secret that the MCO needs to push the newly-built custom layered image to that registry. |
-
Create the MachineOSConfig
object:
$ oc create -f <filename>.yaml
-
If necessary, when the MachineOSBuild
object has been created and is in the READY
state, modify the node spec for the nodes where you want to use the new custom layered image:
-
Check that the MachineOSBuild
object is ready, by running the following command:
When the SUCCEEDED
value is True
, the build is complete:
Example output showing that the MachineOSBuild
object is ready
NAME PREPARED BUILDING SUCCEEDED INTERRUPTED FAILED AGE
layered-image-ad5a3cad36303c363cf458ab0524e7c0-builder False False True False False 43s
-
Edit the nodes where you want to deploy the custom layered image by adding a label for the machine config pool you specified in the MachineOSConfig
object:
$ oc label node <node_name> 'node-role.kubernetes.io/<mcp_name>='
- node-role.kubernetes.io/<mcp_name>=
-
Specifies a node selector that identifies the nodes to deploy the custom layered image.
When you save the changes, the MCO drains, cordons, and reboots the nodes. After the reboot, the node uses the new custom layered image.
Verification
-
Verify that the new pods are ready by running the following command:
$ oc get pods -n openshift-machine-config-operator
Example output
NAME READY STATUS RESTARTS AGE
build-layered-image-ad5a3cad36303c363cf458ab0524e7c0-hxrws 2/2 Running 0 2m40s (1)
# ...
machine-os-builder-6fb66cfb99-zcpvq 1/1 Running 0 2m42s (2)
1 |
This is the build pod where the custom layered image is building, named in the build-<MachineOSConfig_CR_name>-<hash> format. |
2 |
This pod can be used for troubleshooting. |
-
Verify the current stage of your layered build by running the following command:
Example output
NAME PREPARED BUILDING SUCCEEDED INTERRUPTED FAILED AGE
layered-image-ad5a3cad36303c363cf458ab0524e7c0 False True False False False 12m (1)
1 |
The MachineOSBuild is named in the <MachineOSConfig_CR_name>-<hash> format. |
-
Verify that the MachineOSConfig
object contains a reference to the new custom layered image by running the following command:
$ oc describe machineosconfig <object_name>
Example digested image pull spec
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineOSConfig
metadata:
annotations:
machineconfiguration.openshift.io/current-machine-os-build: layered-9a8f89455246fa0c42ecee6ff1fa1a45
labels:
machineconfiguration.openshift.io/createdByOnClusterBuildsHelper: ""
name: layered-image
# ...
status:
currentImagePullSpec: image-registry.openshift-image-registry.svc:5000/openshift-machine-config-operator/os-image@sha256:3c8fc667adcb432ce0c83581f16086afec08a961dd28fed69bb6bad6db0a0754 (1)
1 |
Digested image pull spec for the new custom layered image. |
-
Verify that the appropriate nodes are using the new custom layered image:
-
Start a debug session as root for a control plane node by running the following command:
$ oc debug node/<node_name>
-
Set /host
as the root directory within the debug shell:
-
Run the rpm-ostree status
command to view that the custom layered image is in use:
sh-5.1# rpm-ostree status
Example output
# ...
Deployments:
* ostree-unverified-registry:image-registry.openshift-image-registry.svc:5000/openshift-machine-config-operator/os-images@sha256:3c8fc667adcb432ce0c83581f16086afec08a961dd28fed69bb6bad6db0a0754
Digest: sha256:3c8fc667adcb432ce0c83581f16086afec08a961dd28fed69bb6bad6db0a0754 (1)
Version: 419.94.202502100215-0 (2025-02-12T19:20:44Z)
1 |
Digested image pull spec for the new custom layered image. |
Modifying an on-cluster custom layered image
You can modify an on-cluster custom layered image, as needed. This allows you to install additional packages, remove existing packages, change the pull or push repositories, update secrets, or other similar changes. You can edit the MachineOSConfig
object, apply changes to the YAML file that created the MachineOSConfig
object, or create a new YAML file for that purpose.
If you modify and apply the MachineOSConfig
object YAML or create a new YAML file, the YAML overwrites any changes you made directly to the MachineOSConfig
object itself.
Making certain changes to a MachineOSConfig
object triggers an automatic rebuild of the associated custom layered image. You can mitigate the effects of the rebuild by pausing the machine config pool where the custom layered image is applied as described in "Pausing the machine config pools". While the pools are paused, the MCO does not roll out the newly built image to the nodes after the build is complete. However, the build runs regardless of whether the pool is paused or not. For example, if you want to remove and replace a MachineOSCOnfig
object, pausing the machine config pools before making the change prevents the MCO from reverting the associated nodes to the base image, reducing the number of reboots needed.
When a machine config pool is paused, the oc get machineconfigpools
reports the following status:
Example output
NAME CONFIG UPDATED UPDATING DEGRADED MACHINECOUNT READYMACHINECOUNT UPDATEDMACHINECOUNT DEGRADEDMACHINECOUNT AGE
master rendered-master-a0b404d061a6183cc36d302363422aba True False False 3 3 3 0 4h14m
worker rendered-worker-221507009cbcdec0eec8ab3ccd789d18 False False False 2 2 2 0 4h14m (1)
1 |
The worker machine config pool is paused, as indicated by the three False statuses and the READYMACHINECOUNT at 0 . |
After the changes have been rolled out, you can unpause the machine config pool.
Verification
-
Verify that the new MachineOSBuild
object was created by using the following command:
Example output
NAME PREPARED BUILDING SUCCEEDED INTERRUPTED FAILED AGE
layered-image-a5457b883f5239cdcb71b57e1a30b6ef False False True False False 4d17h
layered-image-f91f0f5593dd337d89bf4d38c877590b False True False False False 2m41s (1)
1 |
The value True in the BUILDING column indicates that the MachineOSBuild object is building. When the SUCCEEDED column reports True , the build is complete. |
-
You can watch as the new machine config is rolled out to the nodes by using the following command:
$ oc get machineconfigpools
Example output
NAME CONFIG UPDATED UPDATING DEGRADED MACHINECOUNT READYMACHINECOUNT UPDATEDMACHINECOUNT DEGRADEDMACHINECOUNT AGE
master rendered-master-a0b404d061a6183cc36d302363422aba True False False 3 3 3 0 3h38m
worker rendered-worker-221507009cbcdec0eec8ab3ccd789d18 False True False 2 2 2 0 3h38m (1)
1 |
The value FALSE in the UPDATED column indicates that the MachineOSBuild object is building. When the UPDATED column reports FALSE , the new custom layered image has rolled out to the nodes. |
-
When the node is back in the Ready
state, check that the changes were applied:
-
Open an oc debug
session to the node by running the following command:
$ oc debug node/<node_name>
-
Set /host
as the root directory within the debug shell by running the following command:
-
Use an appropriate command to verify that change was applied. The following examples shows that the rngd
daemon was installed:
sh-5.1# rpm -qa |grep rng-tools
Example output
rng-tools-6.17-3.fc41.x86_64
Rebuilding an on-cluster custom layered image
In situations where you want to rebuild an on-cluster custom layered image, you can either modify your MachineOSConfig
object or add an annotation to the MachineOSConfig
object. Both of these actions trigger an automatic rebuild of the object. For example, you could perform a rebuild if the you change the Containerfile or need to update the osimageurl
location in a machine config.
After you add the annotation, the Machine Config Operator (MCO) deletes the current MachineOSBuild
object and creates a new one in its place. When the build process is complete, the MCO automatically removes the annotation.
Verification
-
Check that the MachineOSBuild
object is building by using the following command:
Example output
NAME PREPARED BUILDING SUCCEEDED INTERRUPTED FAILED AGE
layered-image-d6b929a29c6dbfa8e4007c8069a2fd08 False True False False False 2m41s (1)
1 |
The value True in the BUILDING column indicates that the MachineOSBuild object is building. |
-
Edit the MachineOSConfig
object to verify that the MCO removed the machineconfiguration.openshift.io/rebuild
annotation by using the following command:
$ oc edit MachineOSConfig <object_name>
Example MachineOSConfig
object
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineOSConfig
metadata:
annotations:
machineconfiguration.openshift.io/current-machine-os-build: layering-c26d4a003432df70ee66c83981144cfa
# ...
name: layered-image
# ...
Reverting an on-cluster custom layered image
If you applied an on-cluster layered image to a node in a custom machine config pool (MCP), you can remove the custom layered image from the node and revert to the base image.
To revert the node, remove the node from the custom MCP by removing the custom machine config pool label from the node. After you remove the label, the Machine Config Operator (MCO) reboots the node with the cluster base Fedora CoreOS (FCOS) image, overriding the custom layered image.
|
Before you remove the label, make sure the node is associated with another MCP.
|
Removing an on-cluster custom layered image
To prevent the custom layered images from taking up excessive space in your registry, you can automatically remove an on-cluster custom layered image from the repository by deleting the MachineOSBuild
object that created the image.
The credentials provided by the registry push secret that you added to the MachineOSBuild
object must grant the permission for deleting an image from the registry. If the delete permission is not provided, the image is not removed when you delete the MachineOSBuild
object.
Note that the custom layered image is not deleted if the image is either currently in use on a node or is desired by the nodes, as indicated by the machineconfiguration.openshift.io/currentConfig
or machineconfiguration.openshift.io/desiredConfig
annotation on the node.