Automate Single Node OpenShift Deployment Using Red Hat ACM and SiteConfig (Part 1)
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.
This blog is to support this youtube video, it makes easy to copy/paste the content.
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. libvirtandvirshinstalled 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:
- Go to Operators > OperatorHub, then search for “Advanced Cluster Management for Kubernetes”.
2. Click Install, choose the desired channel (e.g., release-2.13) and version.
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.yamlWait 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 -A2If 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 siteconfigCheck for default install templates:
oc get cm -n open-cluster-management | grep templatesStep 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 provisioningIf 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: trueApply it:
oc apply -f provisioning.yamlThen 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-0Apply it using:
oc apply -f agentserviceconfig.yamlThis 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.10Update /etc/named.conf to load the new zone:
zone "balk.ocp.local" IN {
type master;
file "balk.ocp.local.zone";
};Restart DNS:
systemctl restart namedStep 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=virtioEnsure 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-cluster001Create 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/dockerconfigjsonCreate BMC Credentials Secret
oc create secret generic ai-bmh-secret \
-n ai-sno-cluster001 \
--from-literal=username=admin \
--from-literal=password=your-passwordStep 7: Define the ClusterInstance YAML
Note: If you delete the
ClusterInstanceobject, 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 newClusterInstance. 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-secretApply the YAML:
oc apply -f clusterinstance.yamlMonitor 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.
