Last active
March 28, 2025 12:30
-
-
Save dmccuk/b1bd2de49442e8b54b2530f69bfa8aac to your computer and use it in GitHub Desktop.
Packer_stuff.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Building a RHEL 9 ISO image using Packer 1.12 on RHEL 8 requires multiple steps. This guide will take you from installing dependencies to creating the ISO with Packer. | |
--- | |
Step 1: Install Required Packages | |
Ensure your RHEL 8 system has the necessary tools installed. | |
# Enable required repositories | |
sudo subscription-manager repos --enable=rhel-8-server-rpms \ | |
--enable=rhel-8-server-extras-rpms \ | |
--enable=rhel-8-server-optional-rpms | |
# Update system and install dependencies | |
sudo dnf update -y | |
sudo dnf install -y wget curl unzip git qemu-kvm virt-install libvirt libvirt-devel libvirt-daemon-kvm virt-manager jq | |
# Start and enable libvirt | |
sudo systemctl start libvirtd | |
sudo systemctl enable libvirtd | |
--- | |
Step 2: Install Packer 1.12 | |
HashiCorp distributes Packer as a standalone binary. | |
# Download Packer 1.12 | |
wget https://releases.hashicorp.com/packer/1.12.0/packer_1.12.0_linux_amd64.zip | |
# Unzip and move to a system-wide path | |
unzip packer_1.12.0_linux_amd64.zip | |
sudo mv packer /usr/local/bin/ | |
# Verify installation | |
packer version | |
--- | |
Step 3: Download the RHEL 9 ISO | |
You'll need an official RHEL 9 ISO from Red Hat. | |
# Create an ISO storage directory | |
mkdir -p ~/iso | |
# Download the RHEL 9 ISO (replace with the correct URL) | |
wget -O ~/iso/rhel-9.iso "https://access.redhat.com/downloads/content/479/ver=/rhel---9/9.0/x86_64/product-software" | |
If you don’t have a Red Hat subscription, you can use the developer edition from Red Hat Developer. | |
--- | |
Step 4: Configure Packer Template | |
Create a new directory for your Packer build. | |
mkdir -p ~/packer-rhel9 | |
cd ~/packer-rhel9 | |
Create a Packer JSON file: rhel9.json | |
{ | |
"variables": { | |
"iso_url": "~/iso/rhel-9.iso", | |
"iso_checksum": "sha256:PUT_THE_CHECKSUM_HERE" | |
}, | |
"builders": [ | |
{ | |
"type": "vmware-iso", | |
"iso_url": "{{user `iso_url`}}", | |
"iso_checksum": "{{user `iso_checksum`}}", | |
"iso_checksum_type": "sha256", | |
"vm_name": "rhel9-vmware", | |
"disk_size": 20000, | |
"format": "vmx", | |
"cpus": 2, | |
"memory": 4096, | |
"headless": false, | |
"http_directory": "http", | |
"boot_wait": "5s", | |
"boot_command": [ | |
"<esc><wait>", | |
" linux inst.ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/ks.cfg<enter>" | |
], | |
"ssh_username": "root", | |
"ssh_password": "password", | |
"ssh_wait_timeout": "30m", | |
"shutdown_command": "shutdown -h now" | |
} | |
], | |
"provisioners": [ | |
{ | |
"type": "shell", | |
"inline": [ | |
"dnf update -y", | |
"dnf install -y open-vm-tools" | |
] | |
} | |
] | |
} | |
Replace "sha256:PUT_THE_CHECKSUM_HERE" with the actual SHA256 checksum of your ISO. You can get it using: | |
sha256sum ~/iso/rhel-9.iso | |
--- | |
Step 5: Create a Kickstart File | |
Packer needs a kickstart file to automate installation. | |
Create the directory for HTTP serving: | |
mkdir -p ~/packer-rhel9/http | |
Create ks.cfg inside http/: | |
cat <<EOF > ~/packer-rhel9/http/ks.cfg | |
#version=RHEL9 | |
text | |
install | |
cdrom | |
keyboard us | |
lang en_US | |
network --bootproto=dhcp | |
rootpw --plaintext password | |
firewall --disabled | |
services --disabled=chronyd | |
timezone America/New_York --utc | |
bootloader --location=mbr | |
autopart --type=lvm | |
clearpart --all --initlabel | |
zerombr | |
reboot | |
EOF | |
--- | |
Step 6: Build the Image | |
Run Packer build command: | |
cd ~/packer-rhel9 | |
packer build rhel9.json | |
This will: | |
1. Boot a QEMU VM. | |
2. Install RHEL 9 using Kickstart. | |
3. Run post-installation scripts. | |
4. Output a QCOW2 disk image of RHEL 9. | |
--- | |
Step 7: Convert to an ISO (Optional) | |
If you need an installable ISO, you’ll have to package the modified filesystem. | |
Extract the Image | |
mkdir ~/rhel9-custom | |
virt-copy-out -a output-qemu/rhel9.qcow2 / ~/rhel9-custom/ | |
Create a Bootable ISO | |
mkisofs -o ~/rhel9-custom.iso \ | |
-b isolinux.bin -c boot.cat \ | |
-no-emul-boot -boot-load-size 4 -boot-info-table \ | |
~/rhel9-custom | |
--- | |
Step 8: Verify and Deploy | |
Run the image in a virtual machine: | |
virt-install --name rhel9-test \ | |
--memory 4096 --vcpus 2 \ | |
--disk path=~/packer-rhel9/output-qemu/rhel9.qcow2,format=qcow2 \ | |
--os-variant rhel9.0 \ | |
--network bridge=virbr0 \ | |
--graphics vnc | |
--- | |
Step 9: Clean Up | |
After testing, clean unnecessary files: | |
rm -rf ~/packer-rhel9/output-qemu | |
rm ~/iso/rhel-9.iso | |
--- | |
Step 4: Create the Kickstart File (Partition Layout) | |
The Kickstart (ks.cfg) file defines the partitioning scheme. | |
mkdir -p ~/packer-rhel9/http | |
cat <<EOF > ~/packer-rhel9/http/ks.cfg | |
#version=RHEL9 | |
text | |
install | |
cdrom | |
keyboard us | |
lang en_US | |
network --bootproto=dhcp | |
rootpw --plaintext password | |
firewall --disabled | |
services --disabled=chronyd | |
timezone America/New_York --utc | |
bootloader --location=mbr | |
zerombr | |
clearpart --all --initlabel | |
# Partition layout | |
part /boot --fstype=xfs --size=1024 | |
part / --fstype=xfs --size=8000 | |
part /home --fstype=xfs --size=2048 | |
part /opt --fstype=xfs --size=2048 | |
part /var/log --fstype=xfs --size=2048 | |
part swap --size=2048 | |
reboot | |
EOF | |
--- | |
Conclusion | |
You’ve successfully created a RHEL 9 image using Packer 1.12 on RHEL 8. Now, you can use the QCOW2 image in virtualization platforms or convert it into an installable ISO. | |
Let me know if you need refinements! | |
--- | |
# Define variables | |
variable "iso_url" { | |
default = "~/iso/rhel-9.iso" | |
} | |
variable "iso_checksum" { | |
default = "sha256:PUT_THE_CHECKSUM_HERE" | |
} | |
# Define the builder | |
source "vmware-iso" "rhel9" { | |
iso_url = var.iso_url | |
iso_checksum = var.iso_checksum | |
iso_checksum_type = "sha256" | |
vm_name = "rhel9-vmware" | |
format = "vmx" | |
disk_size = 20000 | |
cpus = 2 | |
memory = 4096 | |
headless = false | |
http_directory = "http" | |
boot_wait = "5s" | |
boot_command = [ | |
"<esc><wait>", | |
" linux inst.ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/ks.cfg<enter>" | |
] | |
shutdown_command = "shutdown -h now" | |
communicator = "ssh" | |
ssh_username = "root" | |
ssh_password = "password" | |
ssh_timeout = "30m" | |
} | |
# Define the provisioner | |
build { | |
sources = ["source.vmware-iso.rhel9"] | |
provisioner "shell" { | |
inline = [ | |
"dnf update -y", | |
"dnf install -y open-vm-tools" | |
] | |
} | |
} | |
--- | |
```ansible -i inventory all -m shell -a 'if grep -q "release 6" /etc/redhat-release; then grep SINGLE /etc/sysconfig/init | grep -q "sulogin" && echo "RHEL6: Secure" || echo "RHEL6: Insecure"; elif grep -q "release 7" /etc/redhat-release; then grep ExecStart /usr/lib/systemd/system/rescue.service | grep -q "sulogin" && echo "RHEL7: Secure" || echo "RHEL7: Insecure"; elif grep -q "release 8" /etc/redhat-release; then grep ExecStart /usr/lib/systemd/system/rescue.service | grep -q "sulogin" && echo "RHEL8: Secure" || echo "RHEL8: Insecure"; else echo "Unknown OS"; fi' -u your_user --become``` | |
--- | |
ansible -i inventory all -m shell -a 'if [[ -f /etc/os-release ]] && grep -qE "Oracle Linux Server (7|8|9)" /etc/os-release; then echo -n "$(hostname): "; rpm -q vasclnt || echo "vasclnt not installed"; fi' -u your_user --become | |
ansible -i inventory all -m shell -a 'echo -n "$(hostname): "; os_ver=$(cat /etc/os-release | grep -E "PRETTY_NAME" | cut -d= -f2 | tr -d \" ); echo -n "$os_ver, "; rpm -q vasclnt || echo "vasclnt not installed"' -u your_user --become | |
---- | |
ansible all -i hosts.txt -m shell -a "\ | |
echo CPUs:\$(nproc) \ | |
Memory_MB: \$(free -m | awk '/^Mem:/ {print \$2}') \ | |
Load: \$(uptime | awk -F'load average: ' '{print \$2}') \ | |
Disk_Usage: \$(df -h / | awk 'NR==2 {print \$5}') \ | |
Mem_Used: \$(free -m | awk '/^Mem:/ {print \$3}') \ | |
Top_Proc: \$(ps -eo comm,%cpu --sort=-%cpu \ | |
Uptime_days: \$(uptime -p | sed 's/up //') \ | |
Top_Proc: \$(ps -eo comm,%cpu --sort=-%cpu | head -n 2 | tail -n 1) \ | |
Zombie_Procs: \$(ps aux | awk '\$8 ~ /Z/ { count++ } END { print count+0 }')" -k -o | |
--- | |
ansible all -i hosts.txt -m shell -a "\ | |
echo CPUs: \$(nproc) \ | |
Memory_MB: \$(free -m | awk '/^Mem:/ {print \$2}') \ | |
Mem_Used: \$(free -m | awk '/^Mem:/ {print \$3}') \ | |
Swap_Used_MB: \$(free -m | awk '/^Swap:/ {print \$3}') \ | |
Load: \$(uptime | awk -F'load average: ' '{print \$2}') \ | |
Disk_Usage: \$(df -h / | awk 'NR==2 {print \$5}') \ | |
Uptime: \$(uptime -p | sed 's/up //') \ | |
Top_Proc: \$(ps -eo comm,%cpu --sort=-%cpu | head -n 2 | tail -n 1) \ | |
Zombie_Procs: \$(ps aux | awk '\$8 ~ /Z/ { count++ } END { print count+0 }')" -o | |
--- | |
ansible all -i hosts.txt -m shell -a "\ | |
echo CPUs: \$(nproc) \ | |
Memory_MB: \$(free -m | awk '/^Mem:/ {print \$2}') \ | |
Mem_Used: \$(free -m | awk '/^Mem:/ {print \$3}') \ | |
Swap_Used_MB: \$(free -m | awk '/^Swap:/ {print \$3}') \ | |
Load: \$(uptime | awk -F'load average: ' '{print \$2}') \ | |
Disk_Usage: \$(df -h / | awk 'NR==2 {print \$5}') \ | |
Uptime: \$(uptime -p | sed 's/up //') \ | |
Top_Proc: \$(ps -eo comm,%cpu --sort=-%cpu | head -n 2 | tail -n 1) \ | |
Zombie_Procs: \$(ps aux | awk '\$8 ~ /Z/ { count++ } END { print count+0 }') \ | |
Kernel: \$(uname -r) \ | |
Java_Version: \$(java -version 2>&1 | head -n 1) \ | |
JVM_Opts: \$(ps -eo args | grep '[j]ava' | grep --color=never '\-X')" \ | |
echo THP: \$(cat /sys/kernel/mm/transparent_hugepage/enabled 2>/dev/null | tr -d '\n') \ | |
NUMA_Balancing: \$(cat /proc/sys/kernel/numa_balancing 2>/dev/null) \ | |
NTP_Sync: \$(timedatectl 2>/dev/null | grep 'System clock synchronized' | awk '{print \$4}') \ | |
Ulimit_Open_Files: \$(ulimit -n)" -o | |
ansible all -i hosts.txt -m shell -a "\ | |
echo THP:\$(cat /sys/kernel/mm/transparent_hugepage/enabled 2>/dev/null | tr -d '\n') \ | |
NUMA_Balancing:\$(cat /proc/sys/kernel/numa_balancing 2>/dev/null) \ | |
NTP_Sync:\$(timedatectl 2>/dev/null | grep 'System clock synchronized' | awk '{print \$4}') \ | |
Ulimit_Open_Files:\$(ulimit -n)" -o | |
CPU_Loop:\$(start=\$(date +%s); for i in {1..1000000}; do let j=i*i; done; end=\$(date +%s); echo \$((end - start)) sec) | |
--- | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment