Installing VMs using virt-install and kickstart

Kickstart installation is an automated method for installing Linux distributions such as Red Hat Enterprise Linux (RHEL), Rocky , AlmaLinux, CentOS, Fedora, or their derivatives. It allows you to predefine installation parameters in a configuration file, making it ideal for deploying systems quickly and consistently without manual intervention.

How Kickstart Works

  • Kickstart File:
    • A plain text file that contains answers to all questions normally asked by the installation program, such as:
      • Disk partitioning
      • Software programs to be installed
      • Network configuration for the server
      • Time zone to be used
      • The root user password
    • Example filename: ks.cfg
  • Installation Process:
    • During the installation, the system reads the Kickstart file and performs all the steps specified within it without prompting the user for input.
  • Deployment:
    • The Kickstart file can be delivered to the target system via:
      • A local storage medium (e.g., USB, CD/DVD, or hard drive).
      • A network server (e.g., HTTP, FTP, or NFS).
🔥 TRENDING - Our #1 Selling eBook

Mastering KVM Virtualization - The Ultimate eBook

From home labs to production clouds - master KVM Host management, automating KVM administration using Terraform, Vagrant, and cloud automation. This eBook will enable you to build scalable virtual infrastructure that works whether you're learning at home or deploying enterprise solutions. Get your full copy today

Only $10 $20
Get Instant Access →

Automate VM installation using Virt-install and kickstart

Let’s consider an example to:

  • Install Enterprise Linux OS from ISO image
  • Use kickstart to automate OS installation

Step 1: Download OS ISO image (DVD)

Download Enterprise Linux DVD iso. This can be RHEL, CentOS Stream, Rocky Linux, AlmaLinux, Oracle Linux, e.t.c.

In this example we are downloading Rocky Linux DVD iso.

wget https://rocky.mirror.liquidtelecom.com/9/isos/x86_64/Rocky-x86_64-dvd.iso

Move the ISO file to the default storage pool directory.

sudo mv Rocky-x86_64-dvd.iso /var/lib/libvirt/images/Rocky-9-x86_64-dvd.iso

Step 2: Create kickstart installation script

We will begin by creating a new file called ks.cfg:

vim ks.cfg

The contents populated to the file are as shared below:

# System language
lang en_US.UTF-8

# Keyboard layout
keyboard us

# Network configuration
network --bootproto=dhcp

# Timezone
timezone America/New_York --utc

# Root password (plain text)
rootpw --plaintext StrongRootPassw0rd

# Skip the GUI installation (remove for desktop installs)
skipx

# Run installer in text mode
text

# Clear the Master Boot Record
zerombr

# Partitioning information
bootloader --timeout=1 --location=mbr --append="net.ifnames=0 biosdevname=0"
clearpart --all --initlabel
part /boot --fstype=ext4 --size=512
part swap --size=1024
part / --fstype=xfs --grow --size=1

# Packages
%packages
@core
@base
openssh-server
openssh-clients
vim
bash-completion
sudo
selinux-policy-devel
net-tools
tar
bzip2
bind-utils
policycoreutils-python-utils
python3
python3-libselinux
tar
yum-utils
firewalld
%end

# Automatically reboot after installation and eject media
reboot --eject

# Post-installation script
%post
echo "Installation complete!" > /root/installation-log.txt
%end

Extra options that you can use in Kickstart:

  • Using encrypted user password
# Generate encrypted passsword
## Python3
python3 -c 'import crypt,getpass;pw=getpass.getpass();print(crypt.crypt(pw) if (pw==getpass.getpass("Confirm: ")) else exit())'
## Python2
python -c 'import crypt,getpass;pw=getpass.getpass();print(crypt.crypt(pw) if (pw==getpass.getpass("Confirm: ")) else exit())'

For root user:

rootpw --iscrypted <encrypted-password-generated>
  • Adding standard user account
# plain text password
user --groups=wheel --name=cloudspinx --plaintext --password=StrongUserPassword --gecos="Cloudspinx User"

# Encrypted password
user --groups=wheel --name=cloudspinx --iscrypted --password=<encrypted-password-generated> --gecos="Cloudspinx User"
  • Setting static IP address
network --bootproto=static --ip=192.168.122.100 --gateway=192.168.122.1  --netmask=255.255.255.0  --noipv6 --device=eth0 --nameserver=192.168.122.1,8.8.8.8 --activate
  • Setting custom partitions with varying sizes
part / --fstype=ext4 --size=10240
part /var --fstype=ext4 --size=20480
part swap --size=2048
  • Using LVM (Logical Volume Manager) with automatic partitioning
zerombr
clearpart --all --initlabel
autopart --type=lvm
  • Using LVM (Logical Volume Manager) with custom partitions
# Clear existing partitions and create a new layout
clearpart --all --initlabel

# Create a standard partition for /boot
part /boot --fstype=ext4 --size=1024

# Create PV for LVM that uses the entire remaining disk space
part pv.01 --grow
## Create a new physical volume of  50GB
#part pv.01 --size=50000

# Create a volume group named "vg_root"
volgroup vg_root --pesize=4096 pv.01

# Create logical volumes within the "vg_root" volume group
logvol / --vgname=vg_root --name=lv_root --size=20000 --fstype=ext4
logvol /home --vgname=vg_root --name=lv_home --size=10000 --fstype=ext4
logvol swap --vgname=vg_root --name=lv_swap --size=4096 --fstype=swap
  • Boot loader configurations like console and changing network card interfaces naming.
bootloader --timeout 1 --append "console=tty0 console=ttyS0,115200 net.ifnames.prefix=net quiet"
  • Sets the state of SELinux on the installed system
# Enforcing
selinux --enforcing

# Permissive
selinux --permissive

# Disabled
selinux --disabled
  • Enable / Disable services
# Comma separated list
services --disabled=auditd,cups,smartd,nfslock
services --enabled=sshd,firewalld,tuned
  • Set NTP servers
timezone America/New_York --ntpservers=time.google.com,time.windows.com
  • VNC installation

To allow the graphical installation to be viewed remotely through VNC. This method is usually preferred over text mode, as there are some size and language limitations in text installations

vnc --host=0.0.0.0 --port=5900 --password=Password01
  • Disable IPv6 (Add inside %post and before its %end)
echo "net.ipv6.conf.all.disable_ipv6 = 1" > /etc/sysctl.d/50-ipv6.conf
echo "net.ipv6.conf.default.disable_ipv6 = 1" >> /etc/sysctl.d/50-ipv6.conf
echo "net.ipv6.conf.lo.disable_ipv6 = 1" >> /etc/sysctl.d/50-ipv6.conf
sed -i -e '/^::1/d' /etc/hosts
sed -i -e 's,^OPTIONS=",OPTIONS="-4 ,g' -e 's, ",",' /etc/sysconfig/chronyd
sed -Ei -e 's,^(#|)AddressFamily .*,AddressFamily inet,' /etc/ssh/sshd_config
sed -i -e 's,^IPv6_rpfilter=yes,IPv6_rpfilter=no,' /etc/firewalld/firewalld.conf
sed -i -e '/dhcpv6-client/d' /etc/firewalld/zones/public.xml

Step 3: Create VM instance using kickstart and virt-install

Define variables used in the installation:

VM_NAME=rocky9      # Name of VM to create
DISK_SIZE=50        # Create 50GB disk size
MEM_SIZE=2048       # Memory setting in MiB
VCPUS=2             # CPU Cores count
BR_NAME=virbr0      # Bridge network name
OS_VARIANT="rhel9.5" # List using osinfo-query  os
INST_GRAPHICS=none  # Install graphics: none, vnc, spice
ISO_FILE=/var/lib/libvirt/images/Rocky-9-x86_64-dvd.iso # Path to ISO file

Create a VM instance using virt-install and kickstart configuration file.

sudo virt-install \
  --name $VM_NAME \
  --memory=$MEM_SIZE \
  --vcpus=$VCPUS \
  --location $ISO_FILE \
  --disk size=${DISK_SIZE}  \
  --network bridge=$BR_NAME \
  --graphics=$INST_GRAPHICS \
  --os-variant=$OS_VARIANT \
  --console pty,target_type=serial \
  --initrd-inject ks.cfg --extra-args "inst.ks=file:/ks.cfg console=tty0 console=ttyS0,115200n8"

The instalallation process should start and progress automatically.

Starting install...
Retrieving 'vmlinuz'                                                                                                                                                                                                  |    0 B  00:00:00 ...
Retrieving 'initrd.img'                                                                                                                                                                                               |    0 B  00:00:00 ...
Allocating 'rocky9.qcow2'                                                                                                                                                                                             |    0 B  00:00:00 ...
WARNING  Overriding memory to 3072 MiB needed for rhel9.5 network install.
Creating domain...                                                                                                                                                                                                    |    0 B  00:00:00
Running text console command: virsh --connect qemu:///system console rocky9
Connected to domain 'rocky9'
Escape character is ^] (Ctrl + ])
....
Starting installer, one moment...
anaconda 34.25.5.9-1.el9.rocky.0.3 for Rocky Linux 9.5 started.
 * installation log files are stored in /tmp during the installation
 * shell is available on TTY2
 * if the graphical installation interface fails to start, try again with the
   inst.text bootoption to start text installation
 * when reporting a bug add logs from /tmp as separate text/plain attachments
18:17:42 Not asking for VNC because of an automated install
18:17:42 Not asking for VNC because text mode was explicitly asked for in kickstart
Starting automated install.Saving storage configuration...
.Checking storage configuration...
...
================================================================================
================================================================================
Installation

1) [x] Language settings                 2) [x] Time settings
       (English (United States))                (America/New_York timezone)
3) [x] Installation source               4) [x] Software selection
       (Local media)                            (Custom software selected)
5) [x] Installation Destination          6) [x] Kdump
       (Custom partitioning selected)           (Kdump is enabled)
7) [x] Network configuration             8) [ ] User creation
       (Connected: enp1s0)                      (No user will be created)

================================================================================
================================================================================
Progress

.
Setting up the installation environment
Configuring storage
Creating disklabel on /dev/vda
Creating xfs on /dev/vda3
Creating swap on /dev/vda2
Creating ext4 on /dev/vda1
...
Running pre-installation scripts
.
Running pre-installation tasks
....
Installing.
Starting package installation process
================================================================================
================================================================================

After the installation you should get a login page:

Rocky Linux 9.5 (Blue Onyx)
Kernel 5.14.0-503.14.1.el9_5.x86_64 on an x86_64

Activate the web console with: systemctl enable --now cockpit.socket

localhost login:

Login as root user with the password set in the ks.cfg file.

localhost login: root
Password:

[root@localhost ~]# cat /etc/redhat-release
Rocky Linux release 9.5 (Blue Onyx)

We can check the IP address assignment and disk partitioning scheme after the OS installation is complete.

[root@localhost ~]# ip ad
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:fa:af:7e brd ff:ff:ff:ff:ff:ff
    altname enp1s0
    inet 192.168.122.226/24 brd 192.168.122.255 scope global dynamic noprefixroute eth0
       valid_lft 2765sec preferred_lft 2765sec
    inet6 fe80::2a46:dfc0:3ef6:b826/64 scope link noprefixroute
       valid_lft forever preferred_lft forever

[root@localhost ~]# df -hT
Filesystem     Type      Size  Used Avail Use% Mounted on
devtmpfs       devtmpfs  4.0M     0  4.0M   0% /dev
tmpfs          tmpfs     888M     0  888M   0% /dev/shm
tmpfs          tmpfs     355M  5.1M  350M   2% /run
/dev/vda3      xfs        49G  1.9G   47G   4% /
/dev/vda1      ext4      488M  260M  192M  58% /boot
tmpfs          tmpfs     178M     0  178M   0% /run/user/0

More guides from the Cloudspinx team:

Join our Linux and open source community. Subscribe to our newsletter for tips, tricks, and collaboration opportunities!

Recent Post

Unlock the Right Solutions with Confidence

At CloudSpinx, we don’t just offer services - we deliver clarity, direction, and results. Whether you're navigating cloud adoption, scaling infrastructure, or solving DevOps challenges, our seasoned experts help you make smart, strategic decisions with total confidence. Let us turn complexity into opportunity and bring your vision to life.

Leave a Comment

Your email address will not be published. Required fields are marked *

Related Post

Preboot Execution Environment (PXE) booting is a network-based boot process that allows a virtual machine to boot an OS or […]

The virt-builder command-line tool simplifies and speed up the process of creating virtual machines (VMs) on kVM. It can be a suitable […]

Installation of Windows operating systems on a KVM hypervisor is a common requirement in varying environments. While the process is […]

Let's Connect

Unleash the full potential of your business with CloudSpinx. Our expert solutions specialists are standing by to answer your questions and tailor a plan that perfectly aligns with your unique needs.
You will get a response from our solutions specialist within 12 hours
We understand emergencies can be stressful. For immediate assistance, chat with us now

Contact CloudSpinx today!

Download CloudSpinx Profile

Discover the full spectrum of our expertise and services by downloading our detailed Company Profile. Simply enter your first name, last name, and email address.