The Linux Kernel-based Virtual Machine (KVM) is free and opensource virtualization software for CentOS 8. KVM turn your server into a hypervisor. This page shows how to set up and manage a virtualized environment with KVM in CentOS 8. It also described how to install and administer Virtual Machines (VMs) on a physical server using the command-line. Make sure that Virtualization Technology (VT) is enabled in your server’s BIOS. You can also run the following command to test if CPU Support Intel VT and AMD-V Virtualization tech:
$ lscpu | grep Virtualization
## Test for both Intel/AMD CPU that support KVM ##
$ sort -u
Virtualization: VT-x
The KVM only supports Intel/AMD 64 bit and IBM z13, Power 8/9 CPU, and later architecture of your host VMs.
Steps to install KVM on CentOS 8 headless remote server
Please use the su command or sudo command to become root user:
$ sudo -i
## OR ##
$ su -
Step 1: Installing kvm
Run the following dnf command/yum command:
# dnf module install virt
Then install tools to provision new virtual machines (VMs):
# dnf install virt-install virt-viewer libguestfs-tools
Enable and start the libvirtd service using the systemctl command:
# systemctl enable libvirtd.service
# systemctl start libvirtd.service
# systemctl status libvirtd.service
Step 2: Verify your kvm installation
Make sure KVM Linux kernel module (driver) loaded using lsmod command and grep command:
# lsmod | grep -i kvm
Step 3: Configure bridged networking
By default, dnsmsq based network bridge configured by libvirtd called virbr0. You can verify that with the following simple commands:
# virsh net-info default
# nmcli device
# nmcli connection show
The libvirtd uses a lightweight DHCP and caching DNS server named dnsmasq. We can see config file including IP ranges either using the cat command or grep command/egrep command:
# cat /var/lib/libvirt/dnsmasq/default.conf
# egrep '^(dhcp-range|interface)' /var/lib/libvirt/dnsmasq/default.conf
## use the ip command to verify info about the virbr0 ##
# ip a show virbr0
# ip r
Step 4: Configure bridged networking
If you want your VMs available to other servers on your LAN, set up a network bridge on the server that connected to your LAN. Update your nic config files. Here is my pre-configured br0 interface enslaved with eno1 Ethernet:
# vi /etc/sysconfig/network-scripts/ifcfg-br0
br0 config:
## my lan 192.168.2.0/24 ## ## Bridge br0 config, only IPv4 and no IPv6 here for now ## STP=no TYPE=Bridge PROXY_METHOD=none BROWSER_ONLY=no BOOTPROTO=none DEFROUTE=yes IPV4_FAILURE_FATAL=no IPV6INIT=no IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no IPV6_ADDR_GEN_MODE=stable-privacy NAME=br0 UUID=dd51480e-fbac-41a8-b5e6-ea3d097f5059 DEVICE=br0 ONBOOT=yes IPADDR=192.168.2.19 PREFIX=24 GATEWAY=192.168.2.254 DNS1=192.168.2.254 DOMAIN=sweet.home IPV6_DISABLED=yes
And config for eno1 Ethernet:
# vi /etc/sysconfig/network-scripts/ifcfg-bridge-slave-eno1
eno1 config:
TYPE=Ethernet NAME=bridge-slave-eno1 UUID=f43a8688-81f0-4860-91d4-f8f41efe2d10 DEVICE=eno1 ONBOOT=yes BRIDGE=br0
Restart the networking service (warning ssh command will disconnect, it is better to reboot the Linux box):
# systemctl restart NetworkManager.service
## OR ##
# nmcli con up br0
# nmcli connection delete eno1
Verify it with the nmcli command
# nmcli device
Sample outputs:
DEVICE TYPE STATE CONNECTION br0 bridge connected br0 virbr0 bridge connected virbr0 eno1 ethernet connected bridge-slave-eno1 lo loopback unmanaged -- virbr0-nic tun unmanaged -- wlp1s0 wifi unmanaged --
See “CentOS 8 add network bridge (br0) with nmcli command” for more information.
Step 5: Create your first virtual machine/guest VM
I am going to create a brand new CentOS 8.x VM. First, grab CentOS 8.x latest ISO image using the wget command/lftp command
# cd /var/lib/libvirt/boot/
# wget https://mirrors.edge.kernel.org/centos/8/isos/x86_64/CentOS-8.1.1911-x86_64-boot.iso
Verify the ISO image using the sha256sum command:
# wget https://mirrors.edge.kernel.org/centos/8/isos/x86_64/CHECKSUM
# sha256sum --ignore-missing -c CHECKSUM
Create CentOS 8.x VM
In this following example, I creating CentOS 8.x VM with 1GB RAM, 1 CPU core, 1 nics and 20GB hard disk space, enter:
# virt-install \
--virt-type=kvm \
--name centos8-vm \
--memory 1024 \
--vcpus=1 \
--os-variant=rhel8.1 \
--cdrom=/var/lib/libvirt/boot/CentOS-8.1.1911-x86_64-boot.iso \
--network=bridge=br0,model=virtio \
--graphics vnc \
--disk path=/var/lib/libvirt/images/centos8.qcow2,size=20,bus=virtio,format=qcow2
To configure VNC and complete CentOS 8 VM installation, ssh from another terminal and type:
# virsh dumpxml centos8-vm | grep vnc
<graphics type='vnc' port='5900' autoport='yes' listen='127.0.0.1'>
Then down the port value (i.e. 5900). You need to use an SSH client to set up tunnel and a VNC client to access the remote VM’s VNC display. Type the following SSH port forwarding command from your Linux and Unix client/MacBook pro desktop:
{vivek@linux-desktop:~ }$ ssh vivek@192.168.2.19 -L 5900:127.0.0.1:5900
Now that you have ssh tunnel established, point your VNC client at 127.0.0.1 (localhost) address and port 5900 as follows:
You should see the CentOS Linux 8 guest installation screen as follows:
Now follow on-screen instructions and install CentOS 8. Once installed, go ahead and click the reboot button. The remote server closed the connection to our VNC client. You can reconnect via KVM client to configure the rest of the server, including SSH-based sessions, firewalls, networking, and much more.
How to create RHEL 8.x VM
Make sure you have rhel.iso stored locally. In this example, I am going to create RHEL 8.x VM with 2GB RAM, 2 CPU core, 1 NIC and 40GB disk space, enter:
# virt-install \
--virt-type=kvm \
--name rhe8-server \
--memory 2048 \
--vcpus=2 \
--os-variant=rhel8.1 \
--cdrom=/var/lib/libvirt/boot/rhel-server.iso \
--network=bridge=br0,model=virtio \
--graphics vnc \
--disk path=/var/lib/libvirt/images/rhel8.qcow2,size=40,bus=virtio,format=qcow2
To get vnc port info, login from another terminal over the ssh and type:
$ sudo virsh dumpxml rhel8-server | grep vnc
<graphics type='vnc' port='5906' autoport='yes' listen='127.0.0.1'>
You need to use an SSH client to setup tunnel and a VNC client to access the remote vnc VM display. Type the following SSH port forwarding command from your client/desktop:
$ ssh vivek@192.168.2.19 -L 5906:127.0.0.1:5906
Once ssh tunnel established, point your VNC client at 127.0.0.1 (localhost) address and port 5906 to continue with RHEL 8.x installation.
Step 6: Build guest images using virt-builder
One can build virtual machine quickly on a CentOS 8 using the virt-builder command.
List images
# virt-builder --list
# virt-builder --list | egrep -i 'debian|ubuntu'
# virt-builder --list | egerp -i centos
Build Ubuntu 18.04 LTS vm
First, set shell variables:
vm="ubuntu-vm1" # VM name os="ubuntu-18.04" # OS tz="Asia/Kolkata" # Time zone ram="1024" # VM RAM disk="10G" # VM Disk Size vcpu="1" # Number of Virtual CPUs key=~/.ssh/id_rsa.pub # SSH Pub key pwd="Encrypted_PASSWORD_HERE" # Use 'mkpasswd --method=sha512crypt' to create Encrypted password bridge="br0" # Network bridge name such as 'br0' or 'virbr0' ostype="ubuntu18.04" # Run 'osinfo-query os' to get exact varient
Now build virtual machine images quickly as per variables:
# virt-builder "${os}" \
--hostname "${vm}" \
--network \
--timezone "${tz}" \
--size=${disk} \
--format qcow2 -o /var/lib/libvirt/images/${vm}-disk01.qcow2 \
--update \
--firstboot-command "dpkg-reconfigure openssh-server" \
--firstboot-command "useradd -p ${pwd} -s /bin/bash -m -d /home/vivek -G sudo vivek" \
--edit '/etc/default/grub:s/^GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT="console=tty0 console=ttyS0,115200n8"/' \
--ssh-inject "root:file:${key}" \
--run-command update-grub
Sample outputs:
[ 2.0] Downloading: http://libguestfs.org/download/builder/ubuntu-18.04.xz [ 2.4] Planning how to build this image [ 2.4] Uncompressing [ 7.9] Resizing (using virt-resize) to expand the disk to 10.0G [ 20.8] Opening the new disk [ 24.4] Setting a random seed virt-builder: warning: random seed could not be set for this type of guest [ 24.4] Setting the hostname: ubuntu-vm1 [ 25.1] Setting the timezone: Asia/Kolkata [ 25.2] Updating packages [ 138.7] Installing firstboot command: dpkg-reconfigure openssh-server [ 138.8] Installing firstboot command: useradd -p $6$XoUElABFFfTFr4/f$dGYZ2MCb2QcMuKQ2RmE./U0v7mhr2LFd4rbvOMdbjPCWwiyOMuirQagJ.9hBobz9Dy61AXS8oeTabem/H5YhB1 -s /bin/bash -m -d /home/vivek -G sudo vivek [ 138.8] Editing: /etc/default/grub [ 138.9] SSH key inject: root [ 139.7] Running: update-grub [ 139.9] Setting passwords virt-builder: Setting random password of root to SzzVUrAhaYRUiVJj [ 140.6] Finishing off Output file: /var/lib/libvirt/images/ubuntu-vm1-disk01.qcow2 Output size: 10.0G Output format: qcow2 Total usable space: 9.8G Free space: 7.9G (81%)
Please note down random root passwoed. Now our custom VM image has been built with given options. Let us install VM:
# virt-install --import --name "${vm}" \
--ram "${ram}" \
--vcpu "${vcpu}" \
--disk path=/var/lib/libvirt/images/${vm}-disk01.qcow2,format=qcow2 \
--os-variant "${ostype}" \
--network=bridge=${bridge},model=virtio \
--noautoconsole
List VM:
# virsh list
Log in using console
# virsh console ${vm}
Since we injected the ssh key, enter:
## this will only work if your br0 dhcpd also provide name resoution via dns ##
# host $vm
# ssh root@vm-ip-here
# ssh root@${vm}
We can use virt-builder to build a variety of VMs for local or cloud use, usually within a few minutes or less. Then we use virt-install to install KVM on CentOS 8 headless server.
Step 7: Using cloud images
The manual installation method is okay for learning purposes or for building a single VM. But do you need to deploy lots of VMs? Try cloud images. You can modify pre-built cloud images as per your needs. For example, we can add users, install ssh keys, setup time zone, and more using Cloud-init, which is the defacto multi-distribution package that handles early initialization of a cloud instance. Let us see how to create CentOS 8 VM using cloud images with 1024MB ram, 20GB disk space, and one vCPU.
Download CentOS 8 cloud image
# cd /var/lib/libvirt/boot
# wget https://cloud.centos.org/centos/8/x86_64/images/CentOS-8-GenericCloud-8.1.1911-20200113.3.x86_64.qcow2
# wget https://cloud.centos.org/centos/8/x86_64/images/CHECKSUM
# sha256sum --ignore-missing -c CHECKSUM
Use the mkdir command to create required directories
# D=/var/lib/libvirt/images
# VM=centos8-vm1 ## your vm goes name ##
# mkdir -vp $D/$VM
mkdir: created directory '/var/lib/libvirt/images/centos8-vm1'
Create meta-data file
# cd $D/$VM
# vi meta-data
Append the following config:
instance-id: centos8-vm1 local-hostname: centos8-vm1
Create user-data file
I am going to login into VM using ssh keys. So make sure you have ssh-keys in place:
# ssh-keygen -t ed25519 -C "CentOS 8 host server login ssh key"
See “How To Set up SSH Keys on a Linux / Unix System” for more info. Edit user-data as follows:
# cd $D/$VM
# vi user-data
Add as follows (replace hostname, users, ssh-authorized-keys as per your setup):
#cloud-config # Hostname management preserve_hostname: False hostname: centos8-vm1 fqdn: centos8-vm1.sweet.home # Users users: - default - name: vivek groups: ['wheel'] shell: /bin/bash sudo: ALL=(ALL) NOPASSWD:ALL ssh-authorized-keys: - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO4Owk8inCz5ZnhWSiP2Y5wfVKTFOLTFOJ0K/sC2egDF CentOS 8 host server login ssh key # Configure where output will go output: all: ">> /var/log/cloud-init.log" # configure interaction with ssh server ssh_genkeytypes: ['ed25519', 'rsa'] # Install my public ssh key to the first user-defined user configured # in cloud.cfg in the template (which is centos for CentOS cloud images) ssh_authorized_keys: - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO4Owk8inCz5ZnhWSiP2Y5wfVKTFOLTFOJ0K/sC2egDF CentOS 8 host server login ssh key # set timezone for VM timezone: Asia/Kolkata # Remove cloud-init runcmd: - systemctl stop NetworkManager.service && systemctl start NetworkManager.service - dnf -y remove cloud-init
Validate user-data for syntax errors if any:
# cloud-init devel schema --config-file user-data
Valid cloud-config file user-data
Copy cloud image
# cd $D/$VM
# cp -v /var/lib/libvirt/boot/CentOS-8-GenericCloud-8.1.1911-20200113.3.x86_64.qcow2 $VM.qcow2
'/var/lib/libvirt/boot/CentOS-8-GenericCloud-8.1.1911-20200113.3.x86_64.qcow2' -> 'centos8-vm1.qcow2'
Create 20GB disk image
# cd $D/$VM
# qemu-img create -f qcow2 -o preallocation=metadata $VM.new.image 20G
# virt-resize --quiet --expand /dev/sda1 $VM.qcow2 $VM.new.image
# mv -f $VM.new.image $VM.qcow2
# ls -l
Creating a cloud-init ISO file
# mkisofs -o $VM-cidata.iso -V cidata -J -r user-data meta-data
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)
Creating a pool
# virsh pool-create-as --name $VM --type dir --target $D/$VM
Pool centos8-vm1 created
Installing a CentOS 8 VM via cloud image
# cd $D/$VM
# virt-install --import --name $VM \
--memory 1024 --vcpus 1 --cpu host \
--disk $VM.qcow2,format=qcow2,bus=virtio \
--disk $VM-cidata.iso,device=cdrom \
--network bridge=br0,model=virtio \
--os-variant=rhel8.1 \
--graphics spice \
--noautoconsole
Delete unwanted files:
# cd $D/$VM
# virsh change-media $VM sda --eject --config
Successfully ejected media.
## use the rm command to deleted files ##
# rm -v meta-data user-data $VM-cidata.iso
rm: remove regular file 'meta-data'? y removed 'meta-data' rm: remove regular file 'user-data'? y removed 'user-data' rm: remove regular file 'centos8-vm1-cidata.iso'? y removed 'centos8-vm1-cidata.iso'
Find out an IP address of KVM VM named centos8-vm1
If you are using the ‘br0’ use the host command:
# host $VM
centos8-vm1.sweet.home has address 192.168.2.212
To find out an ip address of Linux KVM guest virtual machine when using the default virbr0 bride interface:
# virsh net-dhcp-leases default
Verification – Log in to centos8-vm
Use the ssh command:
# ssh vivek@$VM
# ssh vivek@192.168.2.212
A note about useful virsh KVM management commands
Let us see some useful commands for managing VMs.
List all VMs
# virsh list --all
Get VM info
# virsh dominfo vmName
# virsh dominfo centos8-vm1
Stop/shutdown a VM
# virsh shutdown centos8-vm1
Start VM
# virsh start centos8-vm1
Mark VM for autostart at CentOS 8 server boot time
# virsh autostart centos8-vm1
Reboot (soft & safe reboot) VM
# virsh reboot ubuntu-vm1
Reset (hard reset/not safe) VM [last resort]
# virsh reset ubuntu-vm1
Delete VM
# virsh shutdown centos8-vm1
# virsh undefine centos8-vm1
# virsh pool-destroy centos8-vm1
# D=/var/lib/libvirt/images
# VM=centos8-vm1.img
# rm -ri $D/$VM
To see a complete list of virsh command type
# virsh help | less
# virsh help | grep reboot
Conclusion
In this tutorial, you learned how to install KVM on CentOS 8 Linux server and provision new gust VM using the virt-install. Further, you learned quickly building new virtual machines using virt-builder. Please libvirt docs here and Linux KVM home docs here. KVM software has many more options. In other words, read the following man pages:
man virt-install
man virt-builder
man nmcli
man ip
man bridge
- How to install KVM on CentOS 7 / RHEL 7 Headless Server
- Install KVM on Ubuntu 16.04 LTS Headless Server
- Debian 9 - install KVM server headless server
- Reset root password for Linux KVM VM
- Clone existing KVM virtual machine images on Linux
- Reset a KVM clone virtual Machines with virt-sysprep on Linux
- KVM forward ports to guests VM with UFW on Linux
- Create VM using the qcow2 image file in KVM
- CentOS 8 KVM installation and configuration
- Ubuntu 20.04 KVM installation and configuration
🐧 Get the latest tutorials on Linux, Open Source & DevOps via:
- RSS feed or Weekly email newsletter
- Share on Twitter • Facebook • 0 comments... add one ↓
Category | List of Unix and Linux commands |
---|---|
File Management | cat |
Firewall | Alpine Awall • CentOS 8 • OpenSUSE • RHEL 8 • Ubuntu 16.04 • Ubuntu 18.04 • Ubuntu 20.04 |
Network Utilities | dig • host • ip • nmap |
OpenVPN | CentOS 7 • CentOS 8 • Debian 10 • Debian 8/9 • Ubuntu 18.04 • Ubuntu 20.04 |
Package Manager | apk • apt |
Processes Management | bg • chroot • cron • disown • fg • jobs • killall • kill • pidof • pstree • pwdx • time |
Searching | grep • whereis • which |
User Information | groups • id • lastcomm • last • lid/libuser-lid • logname • members • users • whoami • who • w |
WireGuard VPN | Alpine • CentOS 8 • Debian 10 • Firewall • Ubuntu 20.04 |