On Linux, Kernel-based Virtual Machine (KVM) together with the libvirt virtualization API provides an easy way to run virtual machines (VMs).
You can download KVM images for Oracle Linux 7 and 8 from the Oracle Linux VM Templates page.
These images are in compressed QCOW2 format. They are small in size (about 600MB) with a minimal install base environment which allows you to only install what you really need.
There is one caveat though: like most cloud images, there is no pre-created user and the root account is locked; you will not be able to login…
One option is to use virt-customize to set a password for the super user, but a better way to initialize your VM is to use cloud-init.
This blog post will show you how to easily create virtual machines using Oracle Linux templates for KVM using simple cloud-init configuration files.
Requirements
Obviously you will need a host system with KVM/libvirt installed and configured. The host hardware must support the virtualization extensions (Intel VT or AMD-V); if your host is a virtual machine, nested virtualization must be enabled.
Oracle Linux 8 host
On Oracle Linux 8, install the virt module as well as the virt-install package:
sudo dnf module install -y virt sudo dnf install -y virt-install sudo systemctl enable --now libvirtd
Oracle Linux 7 host
Oracle Linux 7 is similar, the ol7_kvm_utils repository must be enabled, which provides more recent version for the packages.
sudo yum-config-manager --enable ol7_kvm_utils sudo yum group install -y "Virtualization Host" sudo yum install -y virt-install sudo systemctl enable --now libvirtd
Oracle Cloud Infrastructure (OCI)
The above instructions are valid for OCI instances, however for VM shapes, only Intel based shapes (VM.Standard2.X / VM.DenseIO2.X) support nested virtualization.
Alternatively the Oracle Linux KVM Image and Oracle Linux KVM Image (Autonomous Linux) images have everything installed!
Creating a VM
Download the Oracle Linux VM templates
E.g:
cd /var/lib/libvirt/images/ sudo curl -O https://yum.oracle.com/templates/OracleLinux/OL8/u4/x86_64/OL8U4_x86_64-olvm-b85.qcow2
Cloud-init
The cloud-init package is installed in the Oracle Linux KVM templates and is responsible for the initial setup of the image using instance data.
Instance data is mainly composed of:
- cloud provided metadata: metadata for the cloud environment
- user data: configuration provided by the user
For the KVM environment the NoCloud datasource is used to provide the metadata and user data. We need to create an ISO image with two YAML files: meta-data and user-data
The meta-data file contains an instance id and the hostname of of the VM. E.g.:
instance-id: iid-local01 local-hostname: vm-01
The instance id can be anything, and is used to determine if it is the first boot. If you change the instance id, cloud-init will attempt to re-provision the image.
Although the hostname could alternatively be specified in the user data, it is better to have it in the metadata as it is set earlier in the boot process.
The user-data file allows you to customize the instance to great extends – see Cloud config examples. The file must start with the #cloud-config stanza.
As minimal configuration we need to be able to login to new instance. By default cloud-init will create a user named cloud-user.
We can set a password for this user:
#cloud-config
password: <enter your password here>
chpasswd: { expire: False }
ssh_pwauth: True
or preferably add an ssh public key:
#cloud-config
ssh_authorized_keys:
- ssh-rsa
user@host
We can specify a different user name for the default user:
#cloud-config
system_info:
default_user:
name: opc
Last step: generate an ISO image with these 2 files:
genisoimage -output /var/lib/libvirt/images/vm-01.iso -volid cidata -joliet -rock user-data meta-data
Creating the instance
Copy the the template and launch virt-install passing both disks as parameter: the actual image and the cloud-init iso.
sudo cp /var/lib/libvirt/images/OL8U4_x86_64-olvm-b85.qcow2 /var/lib/libvirt/images/vm-01.qcow2
sudo virt-install --name vm-01 \
--memory 2048 \
--vcpus 2 \
--disk /var/lib/libvirt/images/vm-01.qcow2,device=disk,bus=virtio \
--disk /var/lib/libvirt/images/vm-01.iso,device=cdrom \
--os-type linux --os-variant ol8.4 \
--virt-type kvm --graphics none \
--network network=default,model=virtio \
--noautoconsole \
--import
You can get the list of available os variants with:
osinfo-query os vendor="Oracle America"
Depending of the version of the virt-install package you might not find an exact match for the guest os; in that case, simply pick the closest one.
Retrieving IP address
The IP address can easily be retrieved with virsh. Look for the hostname set in the meta-data file:
$ sudo virsh net-dhcp-leases --network default Expiry Time MAC address Protocol IP address Hostname Client ID or DUID ----------------------------------------------------------------------------------------------------------- 2021-08-03 14:14:22 52:54:00:19:36:6f ipv4 192.168.122.40/24 vm-01 01:52:54:00:19:36:6f
Alternatively you can filter based on the MAC address:
$ sudo virsh domiflist vm-01 Interface Type Source Model MAC ------------------------------------------------------------- vnet0 network default virtio 52:54:00:19:36:6f $ sudo virsh net-dhcp-leases --network default --mac 52:54:00:19:36:6f Expiry Time MAC address Protocol IP address Hostname Client ID or DUID ----------------------------------------------------------------------------------------------------------- 2021-08-03 14:14:22 52:54:00:19:36:6f ipv4 192.168.122.40/24 vm-01 01:52:54:00:19:36:6f
Console access
Should you need console access, you can use --graphics vnc instead of --graphics none when you create the instance. The VNC port can be retrieved with virsh:
$ sudo virsh vncdisplay vm-01 127.0.0.1:0
You can then connect with your preferred VNC client, using the --via option if your KVM host is remote. E.g.:
vncviewer -via opc@<kvm host> 127.0.0.1:0
Image size considerations
To minimize the download size, the KVM templates are in compressed QCOW2 format. This format is read-only, any change to the image will be written in non-compressed format.
If performance is an important factor you may consider using different formats for your VM image. Hereunder is a summary, from small to big in term of size.
1. Copy On Write (COW) linked file
For a quick and simple provisioning we can create a COW file using the template as backing file.
# qemu-img create -f qcow2 -F qcow2 -b OL8U4_x86_64-olvm-b85.qcow2 vm-01.qcow2 Formatting 'vm-01.qcow2', fmt=qcow2 size=39728447488 backing_file=OL8U4_x86_64-olvm-b85.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 [root@kvm-al images]# ls -lh -rw-r--r--. 1 qemu qemu 617M Aug 2 16:23 OL8U4_x86_64-olvm-b85.qcow2 -rw-r--r--. 1 root root 193K Aug 3 14:10 vm-01.qcow2
The vm-01.qcow2 file is (almost) empty at start and will hold the changes for the VM.
2. Compressed QCOW2 format
Simple copy of the template as illustrated above. Data will be uncompressed when accessed.
3. Uncompressed QCOW2 format
This is a good tradeoff: no decompression is needed and the QCOW2 format is quite efficient:
# qemu-img convert -O qcow2 OL8U4_x86_64-olvm-b85.qcow2 vm-01.qcow2 # ls -lh -rw-r--r-- 1 qemu qemu 617M Aug 2 10:00 OL8U4_x86_64-olvm-b85.qcow2 -rw-r--r-- 1 root root 1.3G Aug 3 14:29 vm-01.qcow2
4. Raw disk image
This is the actual disk image, it will be as big as disk itself (37GB for the Oracle Linux Templates)
# qemu-img convert -O raw OL8U4_x86_64-olvm-b85.qcow2 vm-01.img # ls -lh -rw-r--r-- 1 qemu qemu 617M Aug 2 10:00 OL8U4_x86_64-olvm-b85.qcow2 -rw-r--r-- 1 root root 37G Aug 3 14:31 vm-01.img
Note that if your filesystem supports sparse files it won’t allocate all the space:
# ls -1sh 617M OL8U4_x86_64-olvm-b85.qcow2 1.3G vm-01.img
Putting everything together
The above steps can be easily scripted – the following sample script can be used to quickly spawn VMs:
#!/usr/bin/bash
# Some constants
TEMPLATE=OL8U4_x86_64-olvm-b85.qcow2
VCPUS=2
MEMORY=2048
PUB_KEY="${HOME}/.ssh/id_rsa.pub"
[[ $# -ne 1 ]] && echo "Usage: $0 VM_NAME" && exit 1
DOMAIN="$1"
echo "$0: Building cloud-init image"
CI_DIR=$(mktemp -d)
cat > "${CI_DIR}/meta-data" <<EOF
instance-id: iid-local01
local-hostname: ${DOMAIN}
EOF
cat > "${CI_DIR}/user-data" <<EOF
#cloud-config
system_info:
default_user:
name: opc
ssh_authorized_keys:
- $(cat ${PUB_KEY})
EOF
(
cd "${CI_DIR}"
sudo genisoimage -output "/var/lib/libvirt/images/${DOMAIN}.iso" -volid cidata -joliet -rock user-data meta-data
)
rm -rf "${CI_DIR}"
echo "$0: copying disk image"
sudo qemu-img create -f qcow2 -F qcow2 -b "/var/lib/libvirt/images/${TEMPLATE}" "/var/lib/libvirt/images/${DOMAIN}.qcow2"
echo "$0: creating VM"
sudo virt-install --name "${DOMAIN}" \
--memory ${MEMORY} \
--vcpus ${VCPUS} \
--disk "/var/lib/libvirt/images/${DOMAIN}.qcow2,device=disk,bus=virtio" \
--disk "/var/lib/libvirt/images/${DOMAIN}.iso,device=cdrom" \
--os-type linux --os-variant ol8.4 \
--virt-type kvm --graphics none \
--network network=default,model=virtio \
--noautoconsole \
--import
echo "$0: waiting for IP"
while ! sudo virsh net-dhcp-leases --network default | grep "${DOMAIN}"; do
sleep 5
done
echo "$0: Your vm is ready to use!"
Sample session:
$ ./create-vm.sh vm-01 ./create-vm.sh: Building cloud-init image I: -input-charset not specified, using utf-8 (detected in locale settings) Total translation table size: 0 Total rockridge attributes bytes: 331 Total directory bytes: 0 Path table size(bytes): 10 Max brk space used 0 183 extents written (0 MB) ./create-vm.sh: copying disk image Formatting '/var/lib/libvirt/images/vm-01.qcow2', fmt=qcow2 size=39728447488 backing_file=/var/lib/libvirt/images/OL8U4_x86_64-olvm-b85.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 ./create-vm.sh: creating VM Starting install... Domain creation completed. ./create-vm.sh: waiting for IP 2021-08-03 17:01:50 52:54:00:f7:af:10 ipv4 192.168.122.240/24 vm-01 01:52:54:00:f7:af:10 ./create-vm.sh: Your vm is ready to use! $ ssh opc@192.168.122.240 The authenticity of host '192.168.122.240 (192.168.122.240)' can't be established. ECDSA key fingerprint is SHA256:RB0p2TbgZRDAprOw+1JQbok0Hb3yUwsElW2BXSgn8cE. Are you sure you want to continue connecting (yes/no/[fingerprint])? yes Warning: Permanently added '192.168.122.240' (ECDSA) to the list of known hosts. [opc@vm-01 ~]$ uname -a Linux vm-01 5.4.17-2102.201.3.el8uek.x86_64 #2 SMP Fri Apr 23 09:05:57 PDT 2021 x86_64 x86_64 x86_64 GNU/Linux [opc@vm-01 ~]$ logout Connection to 192.168.122.240 closed. $ sudo virsh destroy vm-01 Domain vm-01 destroyed $ sudo virsh undefine vm-01 Domain vm-01 has been undefined
Summary
In this blog post, I explained how you can easily create Oracle Linux KVM virtual machines using the latest Oracle Linux VM Templates.
