This step by step guide explains what is KVM, and how to install and configure KVM in CentOS 8 Linux operating system.
This guide is officially tested in CentOS 8 minimal server edition. However, it should also work in RHEL 8 and its clones like AlmaLinux 8 and Rocky Linux 8.
Table of Contents
What is KVM?
KVM, short for Kernel-based Virtual Machine, is a FreeBSD and Linux kernel module that allows the kernel to act as a hypervisor.
Starting from kernel version 2.6.20, KVM is merged into Linux kernel mainline.
Using KVM, you can easily setup a virtualization environment in a Linux machine and deploy a wide range of guest operating systems including Linux, Windows, BSD, Mac OS and many.
Now let us see how to install and configure KVM in CentOS 8 Linux.
Prerequisites
Before installing KVM, first make sure your system supports hardware virtualization. We have documented a few different ways to identify whether a Linux system supports Virtualization in the following guide.
If your system supports hardware virtualization, continue the following steps.
1. Install And Configure KVM In CentOS 8 Server
For the purpose of this guide, I will be using the following system:
KVM virtualization server:
- OS – CentOS 8 minimal server (No GUI)
- IP Address : 192.168.225.53/24
Even though it is tested on CentOS 8, this guide also should on fine on RHEL 8 as well.
1.1. Install KVM in CentOS 8
Note: All commands given through out this tutorial should be run as root
user. If you've logged in as normal user, add sudo
in-front of all commands give below.
Install Kvm and all required dependencies to setup a virtualization environment on your CentOS 8 sever using command as root
user:
# dnf install qemu-kvm libvirt virt-install
Here,
- emu-kvm - QEMU metapackage for KVM support (i.e. QEMU Full virtualization on x86 hardware),
- libvirt - programs for the libvirt library,
- virt-install - programs to create and clone virtual machines.
Once KVM is installed, enable and start libvertd
service (If it is not started already):
# systemctl enable libvirtd
# systemctl start libvirtd
You can also combine both commands and run them as an one-liner like below:
# systemctl enable --now libvirtd
Check the status of libvirtd service with command:
# systemctl status libvirtd
Sample output:
● libvirtd.service - Virtualization daemon Loaded: loaded (/usr/lib/systemd/system/libvirtd.service; enabled; vendor preset: enable> Active: active (running) since Wed 2020-07-15 14:27:32 IST; 5s ago Docs: man:libvirtd(8) https://libvirt.org Main PID: 1097 (libvirtd) Tasks: 17 (limit: 32768) Memory: 57.0M CGroup: /system.slice/libvirtd.service └─1097 /usr/sbin/libvirtd Jul 15 14:27:28 centos8.ostechnix.lan systemd[1]: Starting Virtualization daemon... Jul 15 14:27:32 centos8.ostechnix.lan systemd[1]: Started Virtualization daemon.
The libvertd service is up and running!
Verify if the KVM modules are loaded:
# lsmod | grep kvm
Sample output:
kvm_intel 294912 0 kvm 786432 1 kvm_intel irqbypass 16384 1 kvm
Great! KVM modules are loaded. Let us create a network bridge now.
1.2. Setup bridge networking with KVM in CentOS
A bridged network shares the real network interface of the host computer with other VMs to connect to the outside network. Therefore each VM can bind directly to any available IPv4
or IPv6
addresses, just like a physical computer.
By default KVM setups a private virtual bridge, so that all VMs can communicate with one another, within the host computer.
It provides its own subnet and DHCP to configure the guest’s network and uses NAT to access the host network.
Have a look at the IP address of the KVM default virtual interfaces using ip
command:
# ip a
Sample output:
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: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 08:00:27:b7:3a:84 brd ff:ff:ff:ff:ff:ff inet 192.168.225.52/24 brd 192.168.225.255 scope global dynamic noprefixroute enp0s3 valid_lft 42217sec preferred_lft 42217sec inet6 2409:4072:918:98cf:ad3b:b969:8ec8:f9c7/64 scope global noprefixroute valid_lft forever preferred_lft forever inet6 fe80::b404:4d52:8bee:18bf/64 scope link noprefixroute valid_lft forever preferred_lft forever 3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 08:00:27:2a:be:53 brd ff:ff:ff:ff:ff:ff 4: enp0s9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 08:00:27:41:91:4d brd ff:ff:ff:ff:ff:ff 5: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000 link/ether 52:54:00:5b:a4:cd brd ff:ff:ff:ff:ff:ff inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0 valid_lft forever preferred_lft forever 6: virbr0-nic: <BROADCAST,MULTICAST> mtu 1500 qdisc fq_codel master virbr0 state DOWN group default qlen 1000 link/ether 52:54:00:5b:a4:cd brd ff:ff:ff:ff:ff:ff
As you can see, KVM default network virbr0
uses 192.168.122.1/24
IP address. All the VMs will use an IP address in the 192.168.122.0/24
IP range and the host OS will be reachable at 192.168.122.1
.
You should be able to ssh into the host OS (at 192.168.122.1
) from inside the guest OS and use scp
to copy files back and forth.
It is OK if you only access the VMs inside from the host itself. However you can’t access the VMs from other remote systems in the network.
Because they use different IP range i.e. 192.168.225.0/24
in my case. In order to access the VMs from other remote hosts, we must setup a public bridge that runs on the host network and uses whatever external DHCP server is on the host network.
To put this in layman terms, we are going to make all VMs to use the same IP series used by the host system.
Before setting up a public bridged network, we should disable Netfilter for performance and security reasons. Netfilter is currently enabled on bridges by default.
To disable netfilter, create a file called /etc/sysctl.d/bridge.conf
:
# vi /etc/sysctl.d/bridge.conf
Add the following lines:
net.bridge.bridge-nf-call-ip6tables=0
net.bridge.bridge-nf-call-iptables=0
net.bridge.bridge-nf-call-arptables=0
Save and close the file.
Then create another file called /etc/udev/rules.d/99-bridge.rules
:
# vi /etc/udev/rules.d/99-bridge.rules
Add the following line:
ACTION=="add", SUBSYSTEM=="module", KERNEL=="br_netfilter", RUN+="/sbin/sysctl -p /etc/sysctl.d/bridge.conf"
This will set the necessary flags to disable netfilter on bridges at the appropriate place in system start-up. Save and close the file. Reboot your system to take effect these changes.
Next, we should disable the default networking that KVM installed for itself.
Find the name of KVM default network interfaces using "ip link" command:
# ip link
Sample output:
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000 link/ether 08:00:27:b7:3a:84 brd ff:ff:ff:ff:ff:ff 3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000 link/ether 08:00:27:2a:be:53 brd ff:ff:ff:ff:ff:ff 4: enp0s9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000 link/ether 08:00:27:41:91:4d brd ff:ff:ff:ff:ff:ff 5: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default qlen 1000 link/ether 52:54:00:5b:a4:cd brd ff:ff:ff:ff:ff:ff 6: virbr0-nic: <BROADCAST,MULTICAST> mtu 1500 qdisc fq_codel master virbr0 state DOWN mode DEFAULT group default qlen 1000 link/ether 52:54:00:5b:a4:cd brd ff:ff:ff:ff:ff:ff
As you see in the above output, the entries virbr0
and virbr0-nic
are the KVM networks.
Let us remove the default KVM network with command:
# virsh net-destroy default
Sample output:
Network default destroyed
Undefine the default network with command:
# virsh net-undefine default
Sample output:
Network default has been undefined
If the above commands doesn't work for any reason, you can use these commands to disable and undefine KVM default network:
# ip link delete virbr0 type bridge
# ip link delete virbr0-nic
Now run ip link
again to verify if the virbr0
and virbr0-nic
interfaces are actually deleted:
# ip link
Sample output:
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000 link/ether 08:00:27:b7:3a:84 brd ff:ff:ff:ff:ff:ff 3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000 link/ether 08:00:27:2a:be:53 brd ff:ff:ff:ff:ff:ff 4: enp0s9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000 link/ether 08:00:27:41:91:4d brd ff:ff:ff:ff:ff:ff
Well, the KVM default networks are gone.
Now, let us setup the KVM public bridge to use when creating a new VM.
Create a new bridged interface named br0
using nmcli
command:
# nmcli connection add type bridge autoconnect yes con-name br0 ifname br0
Set IP address for the bridge interface:
# nmcli connection modify br0 ipv4.addresses 192.168.225.53/24 ipv4.method manual
Set Gateway for the bridge interface:
# nmcli connection modify br0 ipv4.gateway 192.168.225.1
Set DNS for the bridge interface:
# nmcli connection modify br0 ipv4.dns 192.168.225.1
Next we need to remove one of your network interface cards and add it as slave to the bridge.
Please note that if your server has only one NIC and you are accessing the server via SSH, your connection will be terminated after removing the NIC. I suggest you to do the following steps in your server's console.
For example, I am going to add enp0s8
interface as slave to the bridge interface br0
.
To remove the network interface enp0s8
, run:
# nmcli connection del enp0s8
Replace enp0s8
with your own network card.
Note: Do not use wireless network interface cards for bridges. Most wireless interlaces do not support bridging. Always use wired network interfaces for seamless connectivity!
Next, add the enp0s8
to the bridge using command:
# nmcli connection add type bridge-slave autoconnect yes con-name enp0s8 ifname enp0s8 master br0
Here, the bridge network interface br0
is attached to host’s network interface enp0s8
. Replace the above network interfaces' names that matches with your network.
Restart the network manager to take effect the changes:
# systemctl restart NetworkManager
If possible, it is better to restart your system:
# reboot
Login to your server and check if the IP address has been assigned to the bridge interface:
$ ip a
Sample output:
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: enp0s3: <BROADCAST,MULTICAST> mtu 1500 qdisc fq_codel state DOWN group default qlen 1000 link/ether 08:00:27:b7:3a:84 brd ff:ff:ff:ff:ff:ff 3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master br0 state UP group default qlen 1000 link/ether 08:00:27:2a:be:53 brd ff:ff:ff:ff:ff:ff 4: enp0s9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 08:00:27:41:91:4d brd ff:ff:ff:ff:ff:ff 5: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether 08:00:27:2a:be:53 brd ff:ff:ff:ff:ff:ff inet 192.168.225.53/24 brd 192.168.225.255 scope global noprefixroute br0 valid_lft forever preferred_lft forever inet6 2409:4072:6084:198:df03:d9ed:62eb:df34/64 scope global noprefixroute valid_lft forever preferred_lft forever inet6 fe80::e8c8:e98b:7fef:5874/64 scope link noprefixroute valid_lft forever preferred_lft forever
As you see in the above output, the bridged network interface br0
is assigned with IP address 192.168.225.53
and the enp0s8
entry now has master br0
entry. It means that enp0s8
belongs to the bridge.
You can also use bridge
command to show the bridge status:
# bridge link show br0 3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master br0 state forwarding priority 32 cost 100
We have successfully created a bridge interface and it is active. We need to do one last thing.
We should configure KVM to use this bridge interface as default interface. To do so, create an XML
file called host-bridge.xml
:
# vi host-bridge.xml
Add the following lines:
<network>
<name>host-bridge</name>
<forward mode="bridge"/>
<bridge name="br0"/>
</network>
Run the following commands to start the newly created bridge and make it as default bridge for VMs:
# virsh net-define host-bridge.xml
# virsh net-start host-bridge
# virsh net-autostart host-bridge
Verify if the bridge is active and started using command:
# virsh net-list --all
Sample output:
Name State Autostart Persistent ------------------------------------------------ host-bridge active yes yes
Congratulations! We've successful installed and configured KVM in CentOS 8 headless server.
2. Create and manage KVM guest machines
We can create and manage VMs either from command line or using any KVM management tools like Cockpit and Virt-manager. Refer the following guides to for more details.
- How To Manage KVM Virtual Machines With Virsh Program
- Manage KVM Virtual Machines Using Cockpit Web Console
- How To Manage KVM Virtual Machines With Virt-Manager
3. Enable Virsh Console Access For Virtual Machines
After creating the KVM guests, I can be able to access them via SSH, VNC client, Virt-viewer, Virt-manager and Cockpit web console etc. But I couldn't access them using virsh console
command. To access KVM guests using "virsh console", refer the following guide:
Other KVM related guides on this blog
- Install And Configure KVM In Ubuntu 20.04 Headless Server
- Install And Configure KVM In OpenSUSE Tumbleweed
- Create A KVM Virtual Machine Using Qcow2 Image In Linux
- How To Migrate Virtualbox VMs Into KVM VMs In Linux
- Enable UEFI Support For KVM Virtual Machines In Linux
- How To Enable Nested Virtualization In KVM In Linux
- Display Virtualization Systems Stats With Virt-top In Linux
- How To Find The IP Address Of A KVM Virtual Machine
- How To Rename KVM Guest Virtual Machine
- Access And Modify Virtual Machine Disk Images With Libguestfs
- Quickly Build Virtual Machine Images With Virt-builder
- How To Rescue Virtual Machines With Virt-rescue
- How To Extend KVM Virtual Machine Disk Size In Linux
- Setup A Shared Folder Between KVM Host And Guest
- How To Change KVM Libvirt Default Storage Pool Location
- [Solved] Cannot access storage file, Permission denied Error in KVM Libvirt
- How To Export And Import KVM Virtual Machines In Linux
Conclusion
In this guide, we discussed how to install and configure KVM in CentOS 8 server edition.
We also looked at how to create and manage KVM virtual machines from command line using virsh
tool and using GUI tools named Cockpit and Virt-manager.
Finally, we saw how to enable virsh console access for KVM virtual machines.
At this stage, you should have fully working virtualization environment in your CentOS 8 server.
Resource:
4 comments
KVM/QEMU on CentOS?
Every time I tested CentOS as a virtualizor host candidate always run away when I see the versions of Kernel, QEMU & libvirt, they are even older than on Debian stable (which I end up using)!
Or I’m I wrong? Would love to be corrected 🙂
Hello,
Using this document, I’ve configured a total of 5 KVM Hypervisors based on CentOS 7.9 & 8.2.
Now, I want to change the IP Address as those servers are moving to another data center where the IP Address will be different.
So, please guide what changes needs to be done.
Just change the IP address of the servers and recreate the bridge matching to the new IP series.
I succeeded setting up KVM bridge network using this article. Thanks for writing detailed steps!