Sitemap

Automate Single Node OpenShift Deployment Using Red Hat ACM and SiteConfig (Part 1)

5 min readApr 7, 2025

--

In this blog post, I’ll walk through a complete and streamlined process for deploying a Single Node OpenShift (SNO) cluster using Red Hat Advanced Cluster Management (ACM), SiteConfig, and kvm virtual machines (VMs) exposed using sushy tool to simulate a bare metal environment. This guide is designed for users who want to automate and standardize OpenShift deployments across environments using ACM.

Press enter or click to view image in full size

This blog is to support this youtube video, it makes easy to copy/paste the content.

Manage Openshift Cluster at Scale

Prerequisites

  • A working OpenShift hub cluster
  • Access to the OpenShift CLI (oc)
  • DNS server with the ability to manage zone files (e.g., bind), feel free to use you dns server.
  • libvirt and virsh installed for VM management, this is only for simulation if you have extra baremetal machine you can technically follow the same guide

Step 1: Install Red Hat Advanced Cluster Management (ACM)

To begin, install the ACM operator via the OpenShift Console:

  1. Go to Operators > OperatorHub, then search for “Advanced Cluster Management for Kubernetes”.
Press enter or click to view image in full size

2. Click Install, choose the desired channel (e.g., release-2.13) and version.

Press enter or click to view image in full size

3. Select A specific namespace on the cluster and use the recommended open-cluster-management namespace.

4. Set Update approval to either Automatic or Manual, then click Install.

5. Create the MultiClusterHub resource:

apiVersion: operator.open-cluster-management.io/v1
kind: MultiClusterHub
metadata:
name: multiclusterhub
namespace: open-cluster-management
spec: {}

Apply it using:

oc apply -f multiclusterhub.yaml

Wait until all pods in the open-cluster-management namespace are up and running.

Step 2: Enable the SiteConfig Operator

Check if SiteConfig is already enabled:

oc get multiclusterhubs.operator.open-cluster-management.io multiclusterhub -n open-cluster-management -o yaml | grep siteconfig -B2 -A2

If not enabled, patch it:

oc patch multiclusterhubs.operator.open-cluster-management.io multiclusterhub -n open-cluster-management --type json --patch '[{"op": "add", "path":"/spec/overrides/components/-", "value": {"name":"siteconfig","enabled": true}}]'

Verify the operator pod is running:

oc get po -n open-cluster-management | grep siteconfig

Check for default install templates:

oc get cm -n open-cluster-management | grep templates

Step 3: Configure AgentServiceConfig for Assisted Installer

Before creating the AgentServiceConfig, you also need to configure the Provisioning resource to enable the Bare Metal Operator to function properly across all namespaces.

Check for the Provisioning Resource

oc get provisioning

If it exists, patch it with:

oc patch provisioning provisioning-configuration --type merge -p '{"spec":{"watchAllNamespaces": true }}'

If it does not exist, create it with:

apiVersion: metal3.io/v1alpha1
kind: Provisioning
metadata:
name: provisioning-configuration
spec:
provisioningNetwork: "Disabled"
watchAllNamespaces: true

Apply it:

oc apply -f provisioning.yaml

Then proceed with creating the AgentServiceConfig as shown below:

apiVersion: agent-install.openshift.io/v1beta1
kind: AgentServiceConfig
metadata:
name: agent
spec:
databaseStorage:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
filesystemStorage:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 50Gi
imageStorage:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 50Gi
osImages:
- cpuArchitecture: x86_64
openshiftVersion: '4.17'
rootFSUrl: 'https://mirror.openshift.com/pub/openshift-v4/x86_64/dependencies/rhcos/pre-release/latest-4.17/rhcos-4.17.0-ec.3-x86_64-live-rootfs.x86_64.img'
url: 'https://mirror.openshift.com/pub/openshift-v4/x86_64/dependencies/rhcos/pre-release/latest-4.17/rhcos-4.17.0-ec.3-x86_64-live.x86_64.iso'
version: 417.94.202410090854-0
- cpuArchitecture: x86_64
openshiftVersion: '4.18'
rootFSUrl: 'https://mirror.openshift.com/pub/openshift-v4/x86_64/dependencies/rhcos/pre-release/4.18.0-rc.2/rhcos-4.18.0-rc.2-x86_64-live-rootfs.x86_64.img'
url: 'https://mirror.openshift.com/pub/openshift-v4/x86_64/dependencies/rhcos/pre-release/4.18.0-rc.2/rhcos-4.18.0-rc.2-x86_64-live.x86_64.iso'
version: 418.94.202411221729-0

Apply it using:

oc apply -f agentserviceconfig.yaml

This configures the backend services required for Assisted Installer to function. Once applied, the service will generate Discovery Images and handle provisioning through the ACM console.

Step 4: Configure DNS

Note: Managed cluster should able to communicate with HUB cluster and resolve DNS and vice-versa otherwise installtion will fail.

Create a new zone file: /var/named/ai-sno-cluster001.balk.ocp.local.zone

$TTL 86400
@ IN SOA ns1.balk.ocp.local. admin.balk.ocp.local. (
2025040301 3600 1800 1209600 86400 )

IN NS ns1.balk.ocp.local.

; DNS Server
ns1.balk.ocp.local. IN A 192.168.7.126

; Hub cluster entries
api.hubztp.balk.ocp.local. IN A 192.168.7.219
*.apps.hubztp.balk.ocp.local. IN A 192.168.7.220

; SNO cluster entries
api.ai-sno-cluster001.balk.ocp.local. IN A 192.168.7.10
*.apps.ai-sno-cluster001.balk.ocp.local. IN A 192.168.7.10

Update /etc/named.conf to load the new zone:

zone "balk.ocp.local" IN {
type master;
file "balk.ocp.local.zone";
};

Restart DNS:

systemctl restart named

Step 5: Create a VM to Simulate Bare Metal Using virsh

Note: If you are using Baremetal machine this step is not required, for now I am using sushy tools to simulate the baremetal scenario.

export HUB_CLUSTER_NAME="hubztp"
export CLUSTER_NAME="sno01"
export NAME_BRIDGE="br0"
export UUID="deed1e55-fe11-f0e5-0dd5-babb1ed1a010"
export MAC="00:00:00:00:00:10"

sudo qemu-img create -f qcow2 /opt/ssd/${HUB_CLUSTER_NAME}/${CLUSTER_NAME}.qcow2 200G

sudo virt-install \
--name=${HUB_CLUSTER_NAME}-${CLUSTER_NAME} \
--uuid=${UUID} \
--ram=65536 \
--vcpus=16 \
--cpu host-passthrough \
--os-type linux \
--os-variant rhel8.0 \
--noreboot \
--events on_reboot=restart \
--noautoconsole \
--boot hd,cdrom \
--import \
--disk path=/opt/ssd/${HUB_CLUSTER_NAME}/${CLUSTER_NAME}.qcow2,size=20 \
--network type=direct,source=${NAME_BRIDGE},mac=${MAC},source_mode=bridge,model=virtio

Ensure the VM boots using the Discovery ISO and matches the MAC address and hostname defined in your cluster config.

Step 6: Prepare Namespace, Pull Secret, and BMC Secret

Before creating the ClusterInstance, we need to create the required namespace and secrets:

Create Namespace

oc create ns ai-sno-cluster001

Create Pull Secret

Replace <pull-secret.json> with your actual file path:

oc create secret generic pull-secret \
-n ai-sno-cluster001 \
--from-file=.dockerconfigjson=<pull-secret.json> \
--type=kubernetes.io/dockerconfigjson

Create BMC Credentials Secret

oc create secret generic ai-bmh-secret \
-n ai-sno-cluster001 \
--from-literal=username=admin \
--from-literal=password=your-password

Step 7: Define the ClusterInstance YAML

Note: If you delete the ClusterInstance object, it will also delete the associated namespace. This means you must recreate the namespace and its required secrets (pull secret, BMC credentials, etc.) before applying a new ClusterInstance. Failing to do so will result in errors during provisioning.

apiVersion: siteconfig.open-cluster-management.io/v1alpha1
kind: ClusterInstance
metadata:
name: ai-sno-cluster001
namespace: ai-sno-cluster001
spec:
cpuPartitioningMode: None
clusterName: ai-sno-cluster001
clusterImageSetNameRef: img4.17.4-x86-64-appsub
machineNetwork:
- cidr: 192.168.4.0/22
networkType: OVNKubernetes
sshPublicKey: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCrRj8UgTVFA1/1okryUGAdZ4kKAE0snw4CUp7lhCXAiB3HI2ynIrQQIn4ddzHkUjGU+tojvTmZnDWR5Gfi53BWNsByFUPPziH+XSp+LWWyYRIFPFpSBI22IQknywSaDs+e7KRiM/axFHVfGpuNRxQ9BYh9wO/xOhe4VAqQhs3M1geTiDKvwcaR77b0r2vNNuqD/6YlMaeYKy8rg6875K35BZgn+6RH1lqK/he2/uQWBhneVskncs5EUv9tSvTC4Tpg9F1LPHGB4CZaoOqB/N7Sb9goIRGjZwe9gsijnjuegbAJfuju2MG9AyNaD95zjU2kHB+tZ9SBijjvMvRdUauWj0PFypv3qb5/lUfMN2G4cSFuBktlV5YnfdP4jRCCakzbdedBG8A/711lE5IqUY464bw6M1f3uukSCvGpSEbmvzCrs2E3ZeUzxvdOyw/N5uUElL0Hzu+m5v9PYoh0D1ip7vxeAmOf9kb5aW3cO0Es8hVRD21EZDZmbvB19fdk770= bkpandey@Balkrishnas-MacBook-Pro.local
nodes:
- automatedCleaningMode: disabled
nodeNetwork:
config:
dns-resolver:
config:
search:
- balk.ocp.local
server:
- 192.168.7.126
interfaces:
- ipv4:
dhcp: true
enabled: true
name: ens1s0
state: up
type: ethernet
routes:
config:
- destination: 0.0.0.0/0
next-hop-address: 192.168.4.1
next-hop-interface: ens1s0
table-id: 254
interfaces:
- macAddress: '00:00:00:00:00:10'
name: ens1s0
bmcCredentialsName:
name: ai-bmh-secret
ironicInspect: ''
hostName: ai-sno-cluster001
bootMode: UEFI
role: master
bootMACAddress: '00:00:00:00:00:10'
templateRefs:
- name: ai-node-templates-v1
namespace: open-cluster-management
cpuArchitecture: x86_64
bmcAddress: 'redfish-virtualmedia+http://192.168.7.126:8000/redfish/v1/Systems/deed1e55-fe11-f0e5-0dd5-babb1ed1a010'
baseDomain: balk.ocp.local
holdInstallation: false
templateRefs:
- name: ai-cluster-templates-v1
namespace: open-cluster-management
cpuArchitecture: x86_64
pullSecretRef:
name: pull-secret

Apply the YAML:

oc apply -f clusterinstance.yaml

Monitor the deployment from the ACM console. Once the node reboots and joins, the cluster will be installed and visible in the Clusters tab.

For a full visual walkthrough, check out the video on the Goglides channel.

--

--