// Module included in the following assemblies:
//
// * machine_configuration/mco-coreos-layering.adoc

ifeval::["{context}" == "installing-"]
:install:
endif::[]

:_mod-docs-content-type: PROCEDURE
[id="coreos-layering-install-time_{context}"]
= Applying a custom layered image during {product-title} installation

[role="_abstract"]
You can use the standard {product-title} installation process to apply a custom layered image to your nodes by adding a `MachineOSConfig` custom resource (CR) YAML and a push secret YAML to the `<installation_directory>/manifests/` directory. This allows you to use {image-mode-os-lower} to apply additional functionality to specific nodes upon cluster installation.

ifdef::install[]
With {image-mode-os-lower}, you can extend the functionality of your base {op-system-first} image by layering additional images onto the base image. This layering does not modify the base RHCOS image. Instead, it creates a custom layered image that includes all {op-system} functionality and adds additional functionality to specific nodes in the cluster. For example, you can create custom layered images to apply hotfixes, RHEL packages, or third-party RPMs to the nodes your cluster.

For more information on {image-mode-os-lower}, see the "Additional resources" section.
endif::install[]

After the installation, if you modify a machine config pool or update the {product-title} version, the Machine Config Operator (MCO) builds and applies a new custom layered image, and pushes the updated image to your repository.

.Prerequisites

* You have a custom layered image in a repository that your cluster can access.
+
.Example containerFile for a custom layered image
[source,yaml]
----
FROM quay.io/centos/centos:stream9 AS centos
RUN dnf install -y epel-release

FROM [rhel-coreos image] AS configs
COPY --from=centos /etc/yum.repos.d /etc/yum.repos.d
COPY --from=centos /etc/pki/rpm-gpg/RPM-GPG-KEY-* /etc/pki/rpm-gpg/
RUN sed -i 's/\$stream/9-stream/g' /etc/yum.repos.d/centos*.repo && \
    rpm-ostree install cowsay && \
    ostree container commit
----

* You have a repository and any needed secret where the MCO can push any updated custom layered images. 

.Procedure

include::snippets/coreos-layering-on-callouts.adoc[]

. Create a YAML file for the push secret similar to the following:
+
[source,yaml]
----
apiVersion: v1
kind: Secret
metadata:
  name: push-secret
  namespace: openshift-machine-config-operator
data:
  .dockerconfigjson: secret
type: kubernetes.io/dockerconfigjson
----

. When the `manifests` directory is available, add the `MachineOSConfig` YAML to the directory by using a command similar to the following:
+
[source,terminal]
----
$ cp <file-name>.yaml manifests/
----
where:
+
`file-name`:: Specifies the YAML file for the `MachineOSConfig` object.

. Add the push secret YAML to the `manifests` directory by using a command similar to the following:
+
[source,terminal]
----
$ cp <file-name>.yaml manifests/
----
where:
+
`file-name`:: Specifies the YAML file for the push secret.

. Continue with the installation process as usual.

.Verification

* After the installation is complete, check that the `MachineOSConfig` object displays the `PreBuiltImageSeeded` status as `True` and contains a reference to the custom layered image by using the following command:
+
[source,terminal]
----
$ oc get machineosconfigs.machineconfiguration.openshift.io -o yaml
----
+
.Example output
[source,yaml]
----
apiVersion: v1
items:
- apiVersion: machineconfiguration.openshift.io/v1
  kind: MachineOSConfig
  metadata:
    annotations:
      machineconfiguration.openshift.io/current-machine-os-build: worker-4cedbc10da849ae7019288febc3a2d17
# ...
  status:
    conditions:
    - lastTransitionTime: "2025-11-19T13:32:17Z"
      message: MachineOSConfig seeded with pre-built image "quay.io/myorg/custom-rhcos@sha256:abc123..."
      reason: PreBuiltImageSeeded
      status: "True"
      type: Seeded
    currentImagePullSpec: image-registry.openshift-image-registry.svc:5000/openshift-machine-config-operator/layered-rhcos@sha256:3c8fc667adcb432ce0c83581f16086afec08a961dd28fed69bb6bad6db0a0754 
----
where:
+
--
`items.status.conditions.reason.PreBuiltImageSeeded.True`:: Specifies that the associated nodes were created using your custom layered image. 
`items.status.currentImagePullSpec`:: Specifies the digested image pull spec for the new custom layered image.
--
