Create a KVM virtual machine template
Today we will see how to create a KVM virtual machine template. A template is essentially a copy of the installed virtual machine that comes in handy when you want to deploy multiple instances of virtual machines.
Information and requirements
These elements are to be taken into consideration to follow this article:
- You have installed KVM, QEMU and Libvirt as described here.
Update the system
yay -Syyuu --noconfirm
Create a hard disk image
To run QEMU you will need a hard disk image, unless you are booting a live system from CD-ROM or the network (and not doing so to install an operating system to a hard disk image). A hard disk image is a file which stores the contents of the emulated hard disk.
A hard disk image can be raw, so that it is literally byte-by-byte the same as what the guest sees, and will always use the full capacity of the guest hard drive on the host. This method provides the least I/O overhead, but can waste a lot of space, as not-used space on the guest cannot be used on the host.
Alternatively, the hard disk image can be in a format such as qcow2
which only allocates space to the image file when the guest operating system writes to those sectors on its virtual hard disk. The image appears as the full size to the guest operating system, even though it may take up only a very small amount of space on the host system.
sudo qemu-img create -o preallocation=metadata -f qcow2 /var/lib/libvirt/images/rl85.qcow2 15G
Formatting '/var/lib/libvirt/images/rl85.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off preallocation=metadata compression_type=zlib size=16106127360 lazy_refcounts=off refcount_bits=16
By executing this command, you create an image in qcow2
format with a size of 15 gigabytes. A note about the preallocation=metada
option: an image with preallocated metadata is initially larger but can improve performance when the image needs to grow.
Display attributes of an image
qemu-img info /var/lib/libvirt/images/rl85.qcow2
image: /var/lib/libvirt/images/rl85.qcow2
file format: qcow2
virtual size: 15 GiB (16106127360 bytes)
disk size: 2.51 MiB
cluster_size: 65536
Format specific information:
compat: 1.1
compression type: zlib
lazy refcounts: false
refcount bits: 16
corrupt: false
extended l2: false
Resize an image
sudo qemu-img resize /var/lib/libvirt/images/rl85.qcow2 20G
Image resized.
Enable default network
If you want to have access to the internet, you must activate the default network. By default it is not activated and does not start automatically as you can see with this command.
sudo virsh net-list --all
Name State Autostart Persistent
----------------------------------------------
default inactive no yes
Start the default network.
sudo virsh net-start default
Network default started
Autostart the default network.
sudo virsh net-autostart default
Network default marked as autostarted
And verify again.
sudo virsh net-list --all
Name State Autostart Persistent
--------------------------------------------
default active yes yes
Create the virtual machine
As you may have noticed previously via the name of the image we instantiated, we will create a virtual machine under Rocky Linux 8.5.
sudo virt-install --name rl85 --memory 4096 \
--disk /var/lib/libvirt/images/rl85.qcow2,format=qcow2 --vcpus 4 \
--os-variant rocky8.5 --network default --graphics none --console pty,target_type=serial \
--location "https://download.rockylinux.org/pub/rocky/8.5/BaseOS/x86_64/os/" \
--extra-args "console=ttyS0,115200n8 serial"
Starting install...
Retrieving file vmlinuz... | 9.6 MB 00:00:00
Retrieving file initrd.img... | 72 MB 00:00:04
Running text console command: virsh --connect qemu:///system console rl85
Connected to domain 'rl85'
Escape character is ^] (Ctrl + ])
[ 0.172004] pci 0000:04:00.0: reg 0x14: [mem 0xfd400000-0xfd400fff]
[ 0.183006] pci 0000:04:00.0: reg 0x20: [mem 0xfe400000-0xfe403fff 64bit pref]
[ 0.198441] pci 0000:00:01.3: PCI bridge to [bus 04]
[ 0.200017] pci 0000:00:01.3: bridge window [io 0x4000-0x4fff]
[ 0.201009] pci 0000:00:01.3: bridge window [mem 0xfd400000-0xfd5fffff]
[ 0.202031] pci 0000:00:01.3: bridge window [mem 0xfe400000-0xfe5fffff 64bit pref]
[ 0.203641] acpiphp: Slot [0-5] registered
[...]
Let’s review all the arguments used with the virt-install
command:
--name
: name of the new guest virtual machine instance. This must be unique amongst all guests known to the hypervisor on the connection, including those not currently active.--memory
: memory to allocate for the guest, in MiB.--disk
: specifies media to use as storage for the guest, with various options likeformat
to specify disk image format.--vcpus
: number of virtual CPUs to configure for the guest.--os-type
: optimizes the guest configuration for a type of operating system. This will attempt to pick the most suitable ACPI & APIC settings, optimally supported mouse drivers, virtio, and generally accommodate other operating system quirks.--os-variant
: further optimizes the guest configuration for a specific operating system variant. This parameter is optional, and does not require an--os-type
to be specified.--network
: connects the guest to the host network.--graphics
: specifies the graphical display configuration. Here,none
means that no graphical console will be allocated for the guest. Guest will likely need to have a text console configured on the first serial port in the guest (this can be done via the--extra-args
option).--console
: connects a text console between the guest and host.--location
: distribution tree installation source.virt-install
can recognize certain distribution trees and fetches a bootable kernel/initrd pair to launch the install.--extra-args
: additional kernel command line arguments to pass to the installer when performing a guest install from--location
.
As explained, we are going to get the Rocky Linux 8.5 source over the network. You will find here the list of mirrors, select one according to your location.
Moreover, I do this way because my connection permits me, for people who do not have a decent bandwidth, it is better to download an ISO image and put the path of the latter in place of the URL.
Start installation
Once the kernel has loaded, you reach the Anaconda installer. We want to install Rocky Linux 8.5 in text mode, so we have to choose option 2
.
Starting installer, one moment...
anaconda 33.16.5.6-1.el8.rocky.1 for Rocky Linux 8 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
================================================================================
================================================================================
Text mode provides a limited set of installation options. It does not offer
custom partitioning for full control over the disk layout. Would you like to use
VNC mode instead?
1) Start VNC
2) Use text mode
Please make a selection from the above ['c' to continue, 'q' to quit, 'r' to
refresh]: 2
Configurations
Now you can configure your server as you like: language settings, time settings, installation source, software selection, installation destination, Kdump, network configuration and root password.
Installation
1) [x] Language settings 2) [x] Time settings
(English (United States)) (America/New_York timezone)
3) [x] Installation source 4) [x] Software selection
(https://download.rockylinux.org/ (Server with GUI)
pub/rocky/8.5/BaseOS/x86_64/os/)
5) [!] Installation Destination 6) [x] Kdump
(Automatic partitioning (Kdump is enabled)
selected)
7) [x] Network configuration 8) [!] Root password
(Wired (enp1s0) connected) (Root account is disabled.)
9) [!] User creation
(No user will be created)
Please make a selection from the above ['b' to begin installation, 'q' to quit,
'r' to refresh]:
Language settings
I want to keep the language settings (English (United States)) so I don’t change anything. However, I send 2
to change time settings.
Time settings
I want to change the timezone so I send 1
.
Time settings
Timezone: America/New_York
NTP servers:not configured
1) Change timezone
2) Configure NTP servers
Please make a selection from the above ['c' to continue, 'q' to quit, 'r' to
refresh]: 1
I choose my region.
Timezone settings
Available regions
1) Europe 5) Antarctica 9) Indian
2) Asia 6) Pacific 10) Arctic
3) America 7) Australia 11) US
4) Africa 8) Atlantic 12) Etc
Please select the timezone. Use numbers or type names directly ['b' back to
region list, 'c' to continue, 'q' to quit, 'r' to refresh]: 1
Then, Paris.
Timezone settings
Available timezones in region Europe
1) Amsterdam 21) Kaliningrad 41) San_Marino
2) Andorra 22) Kiev 42) Sarajevo
3) Astrakhan 23) Kirov 43) Saratov
4) Athens 24) Lisbon 44) Simferopol
5) Belgrade 25) Ljubljana 45) Skopje
6) Berlin 26) London 46) Sofia
7) Bratislava 27) Luxembourg 47) Stockholm
8) Brussels 28) Madrid 48) Tallinn
9) Bucharest 29) Malta 49) Tirane
10) Budapest 30) Mariehamn 50) Ulyanovsk
11) Busingen 31) Minsk 51) Uzhgorod
12) Chisinau 32) Monaco 52) Vaduz
13) Copenhagen 33) Moscow 53) Vatican
14) Dublin 34) Oslo 54) Vienna
15) Gibraltar 35) Paris 55) Vilnius
16) Guernsey 36) Podgorica 56) Volgograd
17) Helsinki 37) Prague 57) Warsaw
18) Isle_of_Man 38) Riga 58) Zagreb
19) Istanbul 39) Rome 59) Zaporozhye
20) Jersey 40) Samara 60) Zurich
Please select the timezone. Use numbers or type names directly ['b' back to
region list, 'c' to continue, 'q' to quit, 'r' to refresh]: 35
Installation source
I want to keep the installation source settings (https://download.rockylinux.org/pub/rocky/8.5/BaseOS/x86_64/os/
) so I do not change anything.
Software selection
I want to change the software selection so I send 4
.
Installation
1) [x] Language settings 2) [x] Time settings
(English (United States)) (Europe/Paris timezone)
3) [x] Installation source 4) [x] Software selection
(https://download.rockylinux.org/ (Server with GUI)
pub/rocky/8.5/BaseOS/x86_64/os/)
5) [!] Installation Destination 6) [x] Kdump
(Automatic partitioning (Kdump is enabled)
selected)
7) [x] Network configuration 8) [!] Root password
(Wired (enp1s0) connected) (Root account is disabled.)
9) [!] User creation
(No user will be created)
Please make a selection from the above ['b' to begin installation, 'q' to quit,
'r' to refresh]: 4
I choose Minimal Install
to install only the necessary packages.
Software selection
Base environment
1) [x] Server with GUI 4) [ ] Workstation
2) [ ] Server 5) [ ] Custom Operating System
3) [ ] Minimal Install 6) [ ] Virtualization Host
Please make a selection from the above ['c' to continue, 'q' to quit, 'r' to
refresh]: 3
Continue.
Software selection
Base environment
1) [ ] Server with GUI 4) [ ] Workstation
2) [ ] Server 5) [ ] Custom Operating System
3) [x] Minimal Install 6) [ ] Virtualization Host
Please make a selection from the above ['c' to continue, 'q' to quit, 'r' to
refresh]: c
I don’t want any additional softwares, continue.
Software selection
Additional software for selected environment
1) [ ] Guest Agents 8) [ ] Headless Management
2) [ ] Standard 9) [ ] Network Servers
3) [ ] Legacy UNIX Compatibility 10) [ ] RPM Development Tools
4) [ ] Container Management 11) [ ] Scientific Support
5) [ ] Development Tools 12) [ ] Security Tools
6) [ ] .NET Core Development 13) [ ] Smart Card Support
7) [ ] Graphical Administration Tools 14) [ ] System Tools
Please make a selection from the above ['c' to continue, 'q' to quit, 'r' to
refresh]: c
Installation destination
I want to change the installation destination so I send 5
.
nstallation
1) [x] Language settings 2) [x] Time settings
(English (United States)) (Europe/Paris timezone)
3) [x] Installation source 4) [x] Software selection
(https://download.rockylinux.org/ (Minimal Install)
pub/rocky/8.5/BaseOS/x86_64/os/)
5) [!] Installation Destination 6) [x] Kdump
(Automatic partitioning (Kdump is enabled)
selected)
7) [x] Network configuration 8) [!] Root password
(Wired (enp1s0) connected) (Root account is disabled.)
9) [!] User creation
(No user will be created)
Please make a selection from the above ['b' to begin installation, 'q' to quit,
'r' to refresh]: 5
I confirm the installation destination, continue.
Installation Destination
1) [x] DISK: 20 GiB (vda)
1 disk selected; 20 GiB capacity; 20 GiB free
Please make a selection from the above ['c' to continue, 'q' to quit, 'r' to
refresh]: c
I want to use all space, continue.
Partitioning Options
1) [ ] Replace Existing Linux system(s)
2) [x] Use All Space
3) [ ] Use Free Space
4) [ ] Manually assign mount points
Installation requires partitioning of your hard drive. Select what space to use
for the install target or manually assign mount points.
Please make a selection from the above ['c' to continue, 'q' to quit, 'r' to
refresh]: c
I want to use LVM, continue.
Partition Scheme Options
1) [ ] Standard Partition
2) [x] LVM
3) [ ] LVM Thin Provisioning
Select a partition scheme configuration.
Please make a selection from the above ['c' to continue, 'q' to quit, 'r' to
refresh]: c
Kdump
I want to disable Kdump so I send 6
.
Installation
1) [x] Language settings 2) [x] Time settings
(English (United States)) (Europe/Paris timezone)
3) [x] Installation source 4) [x] Software selection
(https://download.rockylinux.org/ (Minimal Install)
pub/rocky/8.5/BaseOS/x86_64/os/)
5) [x] Installation Destination 6) [x] Kdump
(Automatic partitioning (Kdump is enabled)
selected)
7) [x] Network configuration 8) [!] Root password
(Wired (enp1s0) connected) (Root account is disabled.)
9) [!] User creation
(No user will be created)
Please make a selection from the above ['b' to begin installation, 'q' to quit,
'r' to refresh]: 6
I deselect Enable kdump
.
Kdump
1) [x] Enable kdump
2) Reserve amount (160 - 3416 MB)
auto
Please make a selection from the above ['c' to continue, 'q' to quit, 'r' to
refresh]: 1
Continue.
Kdump
1) [ ] Enable kdump
Please make a selection from the above ['c' to continue, 'q' to quit, 'r' to
refresh]: c
Network configuration
I don’t want to change network configuration so I don’t send 7
. Regarding the IP address, for simplicity reasons, I will let the local DHCP server of Libvirt assign me one. We’ll see later how to take control over this setting.
Root password
I want to change the root password so I send 8
Installation
1) [x] Language settings 2) [x] Time settings
(English (United States)) (Europe/Paris timezone)
3) [x] Installation source 4) [x] Software selection
(https://download.rockylinux.org/ (Minimal Install)
pub/rocky/8.5/BaseOS/x86_64/os/)
5) [x] Installation Destination 6) [x] Kdump
(Automatic partitioning (Kdump is disabled)
selected)
7) [x] Network configuration 8) [!] Root password
(Wired (enp1s0) connected) (Root account is disabled.)
9) [!] User creation
(No user will be created)
Please make a selection from the above ['b' to begin installation, 'q' to quit,
'r' to refresh]: 8
================================================================================
================================================================================
Root password
Please select new root password. You will have to type it twice.
Password:
Password (confirm):
User creation
I let you create a user if you need to. Don’t forget to add it in the wheel group if you want to use sudo.
Usually, it’s supposed to look like this.
User creation
1) [x] Create user
2) Full name
John Doe
3) User name
jdoe
4) [x] Use password
5) Password
Password set.
6) [x] Administrator
7) Groups
wheel
Launch the installation
All items are checked, I send b
to begin installation.
Installation
1) [x] Language settings 2) [x] Time settings
(English (United States)) (Europe/Paris timezone)
3) [x] Installation source 4) [x] Software selection
(https://download.rockylinux.org/ (Minimal Install)
pub/rocky/8.5/BaseOS/x86_64/os/)
5) [x] Installation Destination 6) [x] Kdump
(Automatic partitioning (Kdump is disabled)
selected)
7) [x] Network configuration 8) [x] Root password
(Wired (enp1s0) connected) (Password is set.)
9) [x] User creation
(Administrator jdoe will be
created)
Please make a selection from the above ['b' to begin installation, 'q' to quit,
'r' to refresh]: b
================================================================================
================================================================================
Progress
.
Setting up the installation environment
Setting up com_redhat_kdump addon
Setting up org_fedora_oscap addon
..
Configuring storage
Creating disklabel on /dev/vda
Creating xfs on /dev/vda1
Creating lvmpv on /dev/vda2
Creating swap on /dev/mapper/rl-swap
Creating xfs on /dev/mapper/rl-root
...
Running pre-installation scripts
.
Running pre-installation tasks
...
Installing.
Starting package installation process
[...]
The installation progresses and a couple of minutes later you have to press ENTER
to exit Anaconda.
[...]
Executing com_redhat_kdump addon
Executing org_fedora_oscap addon
..
Generating initramfs
...
Storing configuration files and kickstarts
.
Running post-installation scripts
.
Installation complete
Use of this product is subject to the license agreement found at:
/usr/share/rocky-release/EULA
Installation complete. Press ENTER to quit:
The virtual machine restarts and we are ready to connect as root user.
[ OK ] Started Login Service.
[ OK ] Started firewalld - dynamic firewall daemon.
[ OK ] Reached target Network (Pre).
Starting Network Manager...
[ OK ] Started Network Manager.
[ OK ] Reached target Network.
Starting Permit User Sessions...
Starting OpenSSH server daemon...
Starting Dynamic System Tuning Daemon...
Starting Network Manager Wait Online...
[ OK ] Started Permit User Sessions.
Starting Hold until boot process finishes up...
[ OK ] Started Command Scheduler.
Starting Terminate Plymouth Boot Screen...
Starting Hostname Service...
[ OK ] Started OpenSSH server daemon.
[ 4.283140] IPv6: ADDRCONF(NETDEV_UP): enp1s0: link is not ready
Rocky Linux 8.5 (Green Obsidian)
Kernel 4.18.0-348.12.2.el8_5.x86_64 on an x86_64
localhost login: root
Password:
Create the KVM virtual machine template
Update the system packages
Log into the brand new virtual machine and update all the system packages.
[root@localhost ~]# dnf -y update
Rocky Linux 8 - AppStream 6.0 MB/s | 6.3 MB 00:01
Rocky Linux 8 - BaseOS 7.1 MB/s | 2.3 MB 00:00
Rocky Linux 8 - Extras 28 kB/s | 9.6 kB 00:00
Dependencies resolved.
Nothing to do.
Complete!
Install packages
At this point, it can be useful to install standard tools (to avoid installing them every time), for example: vim
, wget
, cURL
… This is totally optional.
[root@localhost ~]# dnf -y install vim
Clean the virtual machine
To create a clone of a virtual machine, it must be cleaned. To do this, the virt-sysprep
tool helps us greatly. Steps in this process include removing SSH host keys, persistent network MAC configuration, and user accounts.
The virtual machine must be shut down before you use this command, and disk images must not be edited concurrently.
Shutdown the virtual machine
sudo virsh shutdown rl85
Domain 'rl85' is being shutdown
Install virt-sysprep
yay -S --mflags --nocheck guestfs-tools
sudo virt-sysprep --domain rl85 --selinux-relabel --root-password file:/tmp/root-password.txt
[ 0.0] Examining the guest ...
[ 3.7] Performing "abrt-data" ...
[ 3.7] Performing "backup-files" ...
[ 4.1] Performing "bash-history" ...
[ 4.1] Performing "blkid-tab" ...
[ 4.2] Performing "crash-data" ...
[ 4.2] Performing "cron-spool" ...
[ 4.2] Performing "dhcp-client-state" ...
[ 4.2] Performing "dhcp-server-state" ...
[ 4.2] Performing "dovecot-data" ...
[ 4.3] Performing "ipa-client" ...
[ 4.3] Performing "kerberos-hostkeytab" ...
[ 4.3] Performing "logfiles" ...
[ 4.4] Performing "machine-id" ...
[ 4.4] Performing "mail-spool" ...
[ 4.4] Performing "net-hostname" ...
[ 4.5] Performing "net-hwaddr" ...
[ 4.6] Performing "net-nmconn" ...
[ 4.7] Performing "pacct-log" ...
[ 4.7] Performing "package-manager-cache" ...
[ 4.8] Performing "pam-data" ...
[ 4.8] Performing "passwd-backups" ...
[ 4.8] Performing "puppet-data-log" ...
[ 4.9] Performing "rh-subscription-manager" ...
[ 4.9] Performing "rhn-systemid" ...
[ 5.0] Performing "rpm-db" ...
[ 5.0] Performing "samba-db-log" ...
[ 5.0] Performing "script" ...
[ 5.0] Performing "smolt-uuid" ...
[ 5.0] Performing "ssh-hostkeys" ...
[ 5.1] Performing "ssh-userdir" ...
[ 5.1] Performing "sssd-db-log" ...
[ 5.1] Performing "tmp-files" ...
[ 5.1] Performing "udev-persistent-net" ...
[ 5.2] Performing "utmp" ...
[ 5.2] Performing "yum-uuid" ...
[ 5.2] Performing "customize" ...
[ 5.3] Setting a random seed
[ 5.3] Setting the machine ID in /etc/machine-id
[ 5.3] Setting passwords
[ 6.2] SELinux relabelling
[ 6.3] Performing "lvm-uuids" ...
Many flags and options are available with the virt-sysprep
utility, the ones I used are the following:
--domain
: set libvirt guest name.--hostname
: set the hostname.--selinux-relabel
: relabel files with correct SELinux labels.--root-password
: set root password.
As you can see, the root password can be set (via --root-password file:/tmp/root-password.txt
). You should provide a file containing the cleartext password, ensuring that it is not readable by other users on the system.
chmod 600 /tmp/root-password.txt
Clone the virtual machine
sudo virt-clone --original rl85 --name server.local --file /var/lib/libvirt/images/server.local.qcow2
Allocating 'server.local.qcow2' | 20 GB 00:00:01
Clone 'server.local' created successfully.
Start the cloned virtual machine
If like me you used the --selinux-relabel
flag, the startup will take a bit longer (between 20 and 30 seconds depending on your system performance).
sudo virsh start server.local
Domain 'server.local' started
Generate a SSH key pair
On your local machine, generate a SSH key pair for easy access to the virtual machine.
ssh-keygen -t ed25519 -a 100 -f ~/.ssh/<key pair name> -C <comment>
<passphrase>
<confirm>
Copy the public key to the virtual machine
First, you must know the virtual machine’s IP address.
sudo virsh domifaddr server.local
Name MAC address Protocol Address
-------------------------------------------------------------------------------
vnet0 52:54:00:81:61:4e ipv4 192.168.122.238/24
ssh-copy-id -i ~/.ssh/<key pair name>.pub jdoe@192.168.122.238
<jdoe's password>
Add the server’s information inside your SSH config file (as described here) and connect to your virtual machine.
ssh server.local
You have just created a template of a Rocky Linux 8.5 system. Now, if you want to create a new machine, you just have to use the virt-clone
utility and you will save a lot of time.