RHEL 8 golden image: VM template, Oracle kernel parameters and clone-safe cleanup
Build a repeatable RHEL 8 VM template for enterprise middleware and Oracle-dependent workloads: users, packages, sysctl, mounts, SELinux and cleanup before cloning.
What this guide covers
- What this solves
- Build a repeatable RHEL 8 VM template for enterprise middleware and Oracle-dependent workloads: users, packages, sysctl, mounts, SELinux and cleanup before cloning.
- Applies to
- Linux / RHEL · RHEL 8 · VM template · golden image · Oracle
- Prerequisites
- Review the guide's prerequisites, architecture, and decision sections before execution.
- Risk
- Follow every warning and validate environment-specific commands before a change window.
- Expected result
- A good template means the thirteenth VM is identical to the first, and a bad one quietly multiplies mistakes. This article describes a baseline RHEL 8 image for enterprise middleware and Oracle-dependent workloads, how to set kernel parameters, and the cleanup that makes a clone safe.
- How to verify
- Use the guide's validation, test, acceptance, or handover steps.
- Last verified
- 2026-10-04
A good template means the thirteenth VM is identical to the first, and a bad one quietly multiplies mistakes. This article describes a baseline RHEL 8 image for enterprise middleware and Oracle-dependent workloads, how to set kernel parameters, and the cleanup that makes a clone safe.
The script is a starting point. Adapt it to your standards, and review every line before running it as root.
1. Create the VM#
- Install RHEL 8 from the ISO with a partition plan that matches your inventory (for example 150 GB for
/and a separate 250 GB data disk for/u01). - Update with the organisation's approved RHEL repositories and errata process. Install only packages required by the certified application stack.
- Complete the baseline, data-disk policy and clone-safe cleanup below. Validate a test clone before shutting down the source VM and converting it to a template.
2. Baseline configuration script#
#!/bin/bash
set -euo pipefail
# 1. Oracle-style user and group
getent group oinstall >/dev/null || groupadd oinstall
id oracle &>/dev/null || useradd -g oinstall oracle
echo "Set the oracle password separately (do not store it in the script)."
# 2. Packages: export APPROVED_PACKAGES from the reviewed application and
# Oracle certification/preinstallation record before running this block.
: "${APPROVED_PACKAGES:?set the approved space-separated package list}"
read -r -a packages <<< "$APPROVED_PACKAGES"
for package in "${packages[@]}"; do
[[ "$package" =~ ^[A-Za-z0-9][A-Za-z0-9+_.:-]*$ ]] || exit 2
done
dnf install -y -- "${packages[@]}"
# 3. Non-filesystem-specific directories only. Create /u01 children after
# the separately managed /u01 filesystem is mounted.
install -d -o oracle -g oinstall -m 0770 /logsData disk and mount#
Disk preparation does not belong in a reusable baseline script unless the target is selected from inventory and independently verified. Creating a filesystem destroys existing data. Confirm the disk's by-ID path, serial, size, partition table, signatures and mount state, then require the normal destructive-change approval. Mount by UUID rather than /dev/sdX, because kernel device names can change.
# Run only after the separately reviewed partition/filesystem procedure has
# succeeded. Export DEVICE as the approved stable by-id path.
: "${DEVICE:?set the approved /dev/disk/by-id path}"
case "$DEVICE" in /dev/disk/by-id/*) ;; *) exit 2 ;; esac
test -b "$DEVICE"
UUID=$(blkid -s UUID -o value "$DEVICE")
test -n "$UUID"
install -d -o root -g root -m 0000 /u01
# Export reviewed mount options, then add exactly one UUID entry.
: "${U01_MOUNT_OPTIONS:?set reviewed filesystem mount options}"
[[ "$U01_MOUNT_OPTIONS" =~ ^[A-Za-z0-9,._=-]+$ ]] || exit 2
awk '$2 == "/u01" { found=1 } END { exit found ? 0 : 1 }' /etc/fstab && exit 2
cp --preserve=all /etc/fstab "/etc/fstab.before-u01.$(date +%Y%m%d%H%M%S)"
printf 'UUID=%s /u01 auto %s 0 2\n' "$UUID" "$U01_MOUNT_OPTIONS" >> /etc/fstab
findmnt --verify --verbose
mount /u01
mountpoint -q /u01
install -d -o oracle -g oinstall -m 0770 /u01/app/oracleCreating /u01/app/oracle before mounting /u01 hides the directory under the later mount and can put data on the root filesystem. Do not use mkfs -f to suppress evidence that the wrong device was selected, do not append repeatedly to /etc/fstab, and do not recursively change ownership or mode across a mounted filesystem. Set ownership and restrictive modes on each required application path. Test mount -a in the build and verify the clone with the final virtual-disk layout.
Firewall and SELinux#
Do not add a generic "Oracle port" to the template. Keep the default firewall policy and add only application-specific services, ports, sources and zones after the clone has an approved role. Check the support note for the exact Oracle product and operating-system combination before changing SELinux; preserve enforcing mode unless that certified combination explicitly requires an exception. Record and time-bound any exception rather than disabling SELinux or the firewall globally.
3. Kernel parameters#
There is no safe generic Oracle sysctl profile. Values depend on the certified Oracle product/release, RHEL minor release, memory and workload. Use Oracle's supported preinstallation RPM when the certification matrix calls for it, or transcribe the exact values from the applicable Oracle installation guide into a managed drop-in. Do not combine values copied from unrelated releases.
: "${REVIEWED_ORACLE_SYSCTL_FILE:?set the reviewed sysctl file path}"
test -f "$REVIEWED_ORACLE_SYSCTL_FILE"
install -o root -g root -m 0644 "$REVIEWED_ORACLE_SYSCTL_FILE" /etc/sysctl.d/90-oracle.conf
sysctl --systemReview the resulting effective values and any conflicts from other drop-ins. A file under /etc/sysctl.d/ is easier to audit than appending to /etc/sysctl.conf.
Also set the oracle user's limits (nofile, nproc, stack) in /etc/security/limits.d/ to the values your Oracle guide requires.
4. Network configuration pattern#
For VMs with two NICs, one for management with a gateway and one for internal traffic without, manage existing profiles by a verified connection UUID. Do not repeatedly run nmcli con add: duplicate profiles can race for the same interface. The example addresses are documentation-only.
: "${MGMT_UUID:?set the verified management connection UUID}"
: "${INTERNAL_UUID:?set the verified internal connection UUID}"
test -n "$MGMT_UUID" && test -n "$INTERNAL_UUID" && test "$MGMT_UUID" != "$INTERNAL_UUID"
nmcli connection modify uuid "$MGMT_UUID" \
connection.id mgmt connection.interface-name ens192 \
ipv4.method manual ipv4.addresses 10.60.1.11/26 \
ipv4.gateway 10.60.1.1 ipv4.never-default no
nmcli connection modify uuid "$INTERNAL_UUID" \
connection.id internal connection.interface-name ens224 \
ipv4.method manual ipv4.addresses 10.60.2.11/26 \
ipv4.gateway '' ipv4.never-default yes
nmcli connection up uuid "$MGMT_UUID"
nmcli connection up uuid "$INTERNAL_UUID"
ip -4 route show defaultConfirm interface names and permanent MAC addresses on each VM (ip -br link and nmcli -f GENERAL.CONNECTION,GENERAL.DEVICES device show). Take console access and export each original profile by its verified UUID, including secrets only into protected storage, before a remote network change. Only the management NIC should carry a default gateway. If validation fails, reactivate the exported profile from the console rather than layering another connection over it.
5. Clone-safe cleanup#
Run the platform-supported image-sealing procedure last, then shut down and template. Prefer the hypervisor customization workflow or virt-sysprep when it is supported by the image pipeline; select and review its operations explicitly. Blanket deletion or truncation of logs destroys audit evidence and is not a sealing method.
Define ownership boundaries before sealing:
- RHSM: use the approved subscription/image workflow. If the source was directly registered, unregister and remove its consumer identity using Red Hat's documented commands; never clone its entitlement identity. Do not unregister images whose registration is intentionally managed by RHUI or another cloud image service.
- cloud-init: do not run
cloud-init cleanunless cloud-init is the selected first-boot owner for hostname, networking, machine identity and SSH-key regeneration. Review datasource and network-renderer behavior first, then use the release-supported clean options. - Guest customization: do not let cloud-init, NetworkManager profiles and the hypervisor customization specification all own the same hostname or network fields. Pick one authority and test it.
- Identity: remove machine identity and host keys only through the chosen supported sealing workflow, immediately before shutdown. Preserve logs required by security and audit policy, and ensure no secrets, shell history, temporary credentials or application data remain.
Check on an isolated test clone that machine ID, SSH host keys, DHCP identifiers, hostname, network addresses and RHSM consumer identity are unique. If the workflow does not regenerate a required identity, fix the image pipeline before releasing the template.
6. Per-clone configuration#
Do not hand-edit each VM. Use one of:
- A hypervisor guest customisation specification.
- Ansible, with an inventory that holds the IPs and hostnames.
- A PowerCLI or API script driven from the same inventory.
Whichever you use, never store guest passwords in plain text in scripts. Use a vault, and rotate the template's initial credentials after cloning. At minimum, per clone: hostname (hostnamectl set-hostname), IP addresses, /etc/hosts entry, NTP, and registration with your patching system.
7. Validation#
/u01mounted by UUID and writable byoracle:oinstallsysctl -a | grep -E 'shm|sem|aio|file-max'shows the expected values- Firewall rules limited to required ports
chronyc sourceshealthy- Unique machine ID and SSH host keys on each clone
8. Rollback and recovery#
- Snapshot or clone the powered-off build VM before sealing, according to platform policy; do not retain a snapshot as a long-term backup.
- Keep protected copies of the previous NetworkManager profiles,
/etc/fstab, sysctl drop-ins and limits files. Restore the specific file and reload only its owning subsystem if validation fails. - A filesystem creation is not reversible. If the wrong device was formatted, stop writes and invoke the storage/data-recovery procedure; do not attempt an improvised rollback.
- If a test clone fails first boot, preserve its console and journal evidence, discard that clone, repair the source image or automation, and repeat validation. Do not convert an unvalidated source into the production template.
Vendor references#
- Red Hat Enterprise Linux 8 documentation
- Red Hat Image Builder documentation
- cloud-init documentation
- Oracle Database documentation
Parameters vary by Oracle and RHEL release. Verify against the vendor documentation for your versions.
Standardising your Linux builds? See Managed Infrastructure Operations, or start a project.