How to Install a KVM Guest OS from the Command-Line

How to Install a KVM Guest OS from the Command-Line Feature Image

In KVM, you can install a guest virtual machine using the graphical or command-line interface. If you are running a minimally configured Linux distribution as a KVM host, the only interface available to you will be a command-line interface.

Even if your KVM host has a graphical user interface, you may prefer to install a guest virtual machine using only the command-line interface. So, the way to install a guest virtual machine from the command line is through a serial console using the virt-install tool.

Interacting with a serial console is similar to using a text terminal without a graphical interface or a mouse. It provides an alternative way of accessing your host by replacing the default graphical consoles. Generally, the first serial port on the guest VM (/dev/ttyS0) is used for the serial console.

Once you have finished installing the operating system on a guest virtual machine with a serial console, you can use SSH to connect to it. The serial console comes in handy if you are unable to ssh into your virtual machine due to connectivity issues, or if you need to provide a LUKS passphrase during boot if you have encrypted your virtual machine disks with LUKS encryption.

In this blog, I’ll show you how to use the virt-install tool to install a KVM guest virtual machine from the command line. While virt-install also supports graphical installations via SPICE or VNC, this article will only focus on text-mode installations via the serial console.

I’ll be using Fedora 37 Workstation as the host machine and Debian 11 as an example of a guest virtual machine.

If you prefer to install a guest virtual machine through a graphical interface with Virtual Machine Manager, see my other blog “How to Install Guest OS in Virt-Manager: A Quick Intro“.

If you haven’t already installed KVM virtualization on your Linux distribution, please see my other blog “How Do I Properly Install KVM on Linux“.

So, let’s begin.

Table of Contents

1. Using the virt-install Command-Line Tool

To create a virtual machine and begin the installation of its operating system, you must first provide some basic information.

The following command, for example, will create a Debian 11 guest virtual machine named debian11-default with 2 GiB of RAM, 1 virtual CPU, and a 20 GiB qcow2 virtual disk, with all options required.

$ sudo virt-install \
    --name debian11-default \
    --memory 2048 \
    --vcpus 1 \
    --cdrom /Data/ISO/debian-11.6.0-amd64-DVD-1.iso \
    --disk size=20 \
    --os-variant debian11

Since you have not specified the type of console to use for the installation, the hypervisor default will be used, in this case, a graphical console (virt-viewer) using the SPICE client.

If you attempt to run the same command on a Linux distribution with only a command-line interface (no desktop environment), you will get an error. It will throw an error message something like “No console to launch for the guest.” You will be unable to continue with the installation.

Moreover, the preceding example is very simple. To properly configure a guest virtual machine, much more detailed options are required.

The following command will create a Debian 11 guest virtual machine named debian11-minimal, but with a few additional options. It will also have 2 GiB of RAM, 1 virtual CPU, and a 20 GiB qcow2 virtual disk. This, on the other hand, will make use of the serial console.

$ sudo virt-install \
    --name debian11-minimal \
    --memory memory=4096,currentMemory=2048 \
    --vcpus maxvcpus=4,vcpus=1 \
    --cpu mode=host-passthrough \
    --network network=default \
    --location /Data/ISO/debian-11.6.0-amd64-DVD-1.iso \
    --os-variant debian11 \
    --disk size=20,format=qcow2,cache=none,discard=unmap \
    --tpm model='tpm-tis',type=emulator,version='2.0' \
    --graphics none \
    --extra-args 'console=tty0 console=ttyS0,115200n8 --- console=tty0 console=ttyS0,115200n8' \
    --boot uefi

While there are numerous other settings to tweak, I believe this will be sufficient to get you started with your virtual machine. For more information, see the manual page man virt-install.

Before you press the [ENTER] key and begin the installation process, let me explain all of the options.

--name debian11-minimal

Name of the guest virtual machine. It must be unique among all known guests of the hypervisor on the connection, including those not currently active.

--memory memory=4096,currentMemory=2048

The amount of host memory (in MiB) that will be allocated to the guest. The element ‘memory=4096’ (4 GiB) specifies the maximum amount of memory that can be hotplugged into the running guest. However, ‘currentMemory=2048‘ (2 GiB) specifies the guest’s actual memory allocation at boot.

If you just want a fixed memory of 2 GiB and no hot plugging, use ‘--memory 2048‘ instead.

To find out how much total memory is available and how much is free on your host, use the following command.

$ sudo virsh nodememstats
--vcpus maxvcpus=4,vcpus=1

The number of virtual CPUs to assign to the guest virtual machine. The ‘maxvcpus=4‘ element specifies the maximum number of virtual CPUs that can be hotplugged to the running guest. The ‘vcpus=1‘ element, on the other hand, specifies the actual number of virtual CPUs assigned to the guest at boot.

If you only want a fixed number of virtual CPUs, say two, use ‘--vcpus 2‘ instead.

Run the following command to find out how many CPUs the host has.

$ sudo virsh nodeinfo
--cpu mode=host-passthrough

Sets the CPU model for the guest. The mode attribute allows you to configure a guest CPU to be as close as possible to the host CPU.

When the mode is set to ‘mode=host-passthrough‘, the model and features of the host CPU are exactly passed on to the guest virtual machine. This is also the recommended option. The downside is that live migration to other hosts with different hardware is not possible.

You can also set the mode to ‘mode=host-model‘. In this mode, a CPU model similar to the host CPU is first chosen from the “CPU models” list. Then, to get as close as possible to the host CPU, additional features are added. This will not exactly match the host CPU like ‘host-passthrough‘, but it will provide many of the benefits of host-passthrough while also making live migration safe.

To find out which CPU model and features will be assigned to the guest virtual machine if the mode is set to ‘host-model‘, run the following command on your host.

$ sudo virsh capabilities | xmllint --xpath '//cpu' -

To see a list of all the “CPU models” you can use, run the following command on your host.

$ sudo virsh domcapabilities --arch $(uname -m) | grep "model usable='yes'"
--network network=default

Connects the guest virtual machine to the host network. The ‘network=default‘ element indicates that you want to connect to the virtual NAT network named ‘default‘ that was created by default when you installed KVM virtualization.

If you have set up a network bridge, you can also connect to it. Check out my other blog “How Do I Properly Install KVM on Linux” if you want to configure a network bridge.

To see a list of available networks for you, run the following command.

$ sudo virsh net-list
--location /Data/ISO/debian-11.6.0-amd64-DVD-1.iso

The location of the installer image. Here, I’ve specified a local ISO installer image. If you want to do a net install, use the installation tree’s URL instead, such as ‘--location http://ftp.nl.debian.org/debian/dists/Debian11.6/main/installer-amd64/

To find out if the ISO file is an operating system installation image, use the following command.

$ osinfo-detect /Data/ISO/debian-11.6.0-amd64-DVD-1.iso
Media is bootable.
Media is an installer for OS 'Debian 11 (x86_64)'
--os-variant debian11

Indicate which operating system the guest virtual machine should be optimized for. To get a list of the accepted operating system variant names, run the following command.

$ osinfo-query os
--disk size=20,format=qcow2,cache=none,discard=unmap

Specifies the media to be used as the guest virtual machine storage, with various options.

  • size=20: Sets the disk size to 20 GiB.
  • format=qcow2: Sets the disk format to qcow2. Other options may include ‘raw‘, ‘vdi‘, ‘vmdk‘, and so on. Please keep in mind that internal snapshots are only available for the qcow2 type.
  • cache=none: This indicates that the host cache must be bypassed. Reads and writes take place directly between the hypervisor and the storage device. This is also the recommended one. Other options include writebackwritethroughunsafe, and directsync. For more information on these caching strategies, visit this page.
  • discard=unmap: The type of discard mode you want to use for the qcow2 virtual disk. There are two modes available here: ignore and unmap. When you delete files in the guest, the changes are immediately reflected in the guest’s file system. However, the qcow2 disk image file associated with the guest on the host does not shrink to reflect the newly freed space. With the unmap option selected, you can reclaim that free space. To reclaim the free space, run the following command on the host while the guest is still running.
$ sudo virsh domfstrim <guest name> --minimum 0
--tpm model='tpm-tis',type=emulator,version='2.0'

This enables the guest to have access to TPM functionality. KVM supports two models: TPM Interface Specification (TIS) and Command-Response Buffer (CRB). TIS (tpm-tis) supports both version 1.2 and version 2.0. CRB (tpm-crb) however, only supports version 2.0.

The element model='tpm-tis' sets the TPM to the TIS. When type=emulator is used, each guest gets its own private emulated TPM. The element version='2.0' indicates that TPM version 2.0 is to be used.

--graphics none

The guest virtual machine will not be assigned a graphical console. As a result, the guest virtual machine must be explicitly configured with a text console on the guest virtual machine’s first serial port. The option --extra-args is used to accomplish this.

--extra-args 'console=tty0 console=ttyS0,115200n8 --- console=tty0 console=ttyS0,115200n8'

I’ve specified two consoles here: a virtual console and a serial console. The console=tty0 denotes the first VGA console, while the console=ttyS0 denotes the first serial port. The output will be displayed on both of them.

The first ‘console=tty0 console=ttyS0,115200n8‘ element instructs virt-install to install the guest virtual machine using the VGA console or the serial console /dev/ttyS0 at 115200 bits per second speed, with no parity bit and 8 data bits.

Following a triple dash (---), the same second element instructs the virt-install to permanently copy it into the bootloader of the installed guest virtual machine.

As a result, on subsequent boots, the kernel boot messages are sent to both consoles of the guest virtual machine. This will come in handy if you decide to add a VGA console to the virtual machine later.

The changes are made to the GRUB_CMDLINE_LINUX line in the guest virtual machine’s /etc/default/grub file.

--boot uefi

Use UEFI firmware for the guest. When using UEFI firmware, internal snapshots can be taken only when the guest is offline and not online.

If you want BIOS firmware instead, simply ignore the ‘--boot‘ option. With the BIOS firmware, you can take internal snapshots when the guest is offline as well as online.

2. Install KVM Guest OS from the Command-Line

Now that you know the options, let’s proceed with the installation of the Debian 11 Linux operating system. When you press the [ENTER] key, a text-based installation process begins in the serial console.

How to Install a KVM Guest OS from the Command-Line virt-install

Follow the standard installation procedure for the guest operating system. Complete the installation process by selecting a language, keyboard, location, creating partitions, configuring user and password, and so on.

When it comes to software, uncheck any GUI desktop environment. Only a text interface is permitted in the serial console. You can, however, install the GUI desktop environment if you intend to use it later when you add a graphical display to the guest virtual machine. I’ll show you how to add a graphical display later in this tutorial.

Also, make sure the SSH server is installed. You’ll need it to connect to the virtual machine.

How to Install a KVM Guest OS from the Command-Line Software Selection

When the installation is complete, press the [Continue] button to reboot the system to a text-mode login page.

How to Install a KVM Guest OS from the Command-Line Installation Complete

Type in your username and password and you will be logged into a command-line interface within a virtual serial console.

How to Install a KVM Guest OS from the Command-Line Debian 11 Serial Console Login

If you want to exit the serial console, press the Ctrl + ] keys. You will be returned to the host terminal.

Now that I’m in the host terminal, let me connect to the guest via SSH. First, find the IP address of the guest.

$ sudo virsh domifaddr debian11-minimal
 Name       MAC address          Protocol     Address
----------------------------------------------------------------
 vnet0      52:54:00:46:ac:dd    ipv4         192.168.122.209/24

The guest’s IP address is 192.168.122.209. So connect the guest to this address using SSH.

$ ssh [email protected]
...
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
[email protected]'s password: 
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Thu Mar 16 18:19:33 2023

madhu@debian:~$

You have now established an SSH connection to the guest virtual machine. To disconnect from the SSH connection, type exit or press the Ctrl + d keys.

And, to reconnect the guest virtual machine via serial console again, enter the following command into the host and press the [Enter] key.

$ sudo virsh console debian11-minimal
Connected to domain 'debian11-minimal'
Escape character is ^] (Ctrl + ])

madhu@debian:~$

3. Set the Terminal Type and Console Window Size

When you connect a remote device via SSH, the terminal type and host screen size are automatically sent to the remote device. This does not occur when connecting via a serial connection. As a result, you may notice a reduced screen size, visual anomalies, and scrolling that isn’t working properly.

By default, the serial console will have a terminal type vt220 (or, vt100) and a size of 24x80.

madhu@debian:~$ echo $TERM
vt220

madhu@debian:~$ stty size
24 80

You might want to switch to xterm-256color as the terminal type.

madhu@debian:~$ export TERM=xterm-256color

madhu@debian:~$ echo $TERM
xterm-256color

Also, manually increase the size of the console window.

madhu@debian:~$ stty rows 40 cols 150

madhu@debian:~$ stty size
40 150

There is one other tool called resize that comes with the package xterm in Ubuntu/Debian. In Fedora/Rocky the package is known as xterm-resize. It adjusts the size of the serial console using the settings from the host terminal window.

madhu@debian:~$ sudo apt install xterm

madhu@debian:~$ resize
COLUMNS=172;
LINES=43;
export COLUMNS LINES;

madhu@debian:~$ stty size
43 172

If, after changing the screen size, the serial console still crops the text, exit the serial console by pressing the Ctrl + ] keys. And then enter the command reset in the host terminal. Reconnect to the serial console with the command sudo virsh console debian11-minimal.

4. Check and Set the Baud Speed of the Serial Port

In a real-world situation, the baud speed setting of the RS-232 connection is affected by the length of the cable. The higher the baud rate, the shorter the cable should be. Otherwise, the communication will be unreliable. So most of the Linux distributions set the baud speed to 9600, which is considered a reliable and safe baud speed. The Linux kernel supports a serial console speed of 1200240048009600192003840057600, and 115200 bits per second.

Since we are using a virtual serial console, a much higher baud rate of 115200 is recommended.

I’ve already set the baud speed to 115200 bits per second. Verify the serial port baud speed is the same as specified.

madhu@debian:~$ stty speed
115200

If you want to change the serial port speed, for example, to 9600 bps, do the following.

madhu@debian:~$ stty -F /dev/ttyS0 speed 9600
115200

madhu@debian:~$ stty speed
9600

To know which TTY you are attached to, run the tty command.

madhu@debian:~$ tty
/dev/ttyS0

5. Hot Plug/Unplug Memory and CPU

You can dynamically increase or decrease the memory and CPU while the guest virtual machine is running.

This enables you to improve a virtual machine’s performance by allocating more resources to it only when critical applications are running and you cannot afford to shut down the virtual machine and face downtime.

Similarly, you can also free up the resources from the virtual machine to the host so that they can be used elsewhere.

To manage the resources of the virtual machine, first exit the serial console by pressing Ctrl + ]. If you used SSH to connect to the virtual machine, press Ctrl + d to disconnect.

Adding and removing memory:

First, determine the maximum memory and the memory currently in use in a virtual machine. This will serve as a baseline for your changes as well as verification.

$ sudo virsh dominfo debian11-minimal | grep memory
Max memory:     4194304 KiB
Used memory:    2097152 KiB

As you can see, the maximum memory is set to 4 GiB, while the memory currently in use is 2 GiB.

To dynamically increase the memory of a running virtual machine, for example, to 3 GiB, use the following command.

$ sudo virsh setmem debian11-minimal 3G --current

Verify the changes again.

$ sudo virsh dominfo debian11-minimal | grep memory
Max memory:     4194304 KiB
Used memory:    3145728 KiB

As you can see, the current memory is set to 3 GiB. You can also use the same method to decrease memory.

When the guest is restarted, the memory will be reset back to 2 GiB. If you want the memory to be configured to 3 GiB upon boot permanently, you can use the following command on the host.

$ sudo virsh setmem debian11-minimal 3G --config

Adding and removing virtual CPU:

Similar to memory, you can increase or decrease the virtual CPU count.

View the current state of the virtual CPUs in the targeted virtual machine.

$ sudo virsh vcpucount debian11-minimal
maximum      config         4
maximum      live           4
current      config         1
current      live           1

As you can see, the current CPU count is 1 and the maximum is 4.

To dynamically increase the virtual CPU count of a running virtual machine, for example, to 2, use the following command.

$ sudo virsh setvcpus debian11-minimal 2 --live

Verify the changes again.

$ sudo virsh vcpucount debian11-minimal
maximum      config         4
maximum      live           4
current      config         1
current      live           2

As you can see, the current CPU count is set to 2. You can also use the same method to decrease the CPU count.

When the virtual machine is restarted, the CPU count is reset to 1. If you want the CPU to be permanently configured to 2 upon boot, run the following command on the host.

$ sudo virsh setvcpus debian11-minimal 2 --config

You can now reconnect to the virtual machine and continue to use it with its newly optimized resource.

$ sudo virsh console debian11-minimal

6. Add a Graphical Display for the Guest

A graphical display can also be added to the guest virtual machine. This allows you to use a graphical desktop environment in the guest virtual machine. For this, the host must also have some kind of desktop environment. The host in my case is a Fedora Linux 37 (Workstation Edition) with the GNOME 43 desktop environment.

I’ll add the SPICE protocol in conjunction with the VirtIO driver to provide remote access to the debian11-minimal guest virtual machine via the VGA console (tty1). SPICE supports advanced features such as audio and USB device streaming, as well as enhanced graphics performance.

On the host, execute the following commands.

$ sudo virt-xml debian11-minimal --add-device --graphics spice
$ sudo virt-xml debian11-minimal --add-device --channel spicevmc
$ sudo virt-xml debian11-minimal --edit --video model.type=virtio,clearxml=yes
$ sudo virt-xml debian11-minimal --add-device --sound model=default

The following screenshots show the debian11-minimal guest virtual machine in the VGA and Serial consoles displayed side by side. The output is shown on both consoles, with the VGA console on the left and the Serial console on the right.

How to Install a KVM Guest OS from the Command-Line Serial Console 1/2
How to Install a KVM Guest OS from the Command-Line Serial Console 2/2

Now that you’ve added SPICE and VirtIO, you might want to install spice-vdagent, a SPICE agent for Linux. This enables automatic adjustment of the X-session resolution as well as copy-and-paste support between the guest and host. This will only work if the active X-session is active.

Install spice-vdagent and reboot your Debian 11 guest virtual machine.

madhu@debian:~$ sudo apt update
madhu@debian:~$ sudo apt install spice-vdagent
madhu@debian:~$ sudo reboot

Assuming that you also installed the desktop graphical environment, here’s how it would appear. The guest in the following screenshot is also running Debian 11, but with the GNOME desktop installed. The VGA console is on the left, and the Serial console is on the right.

How to Install a KVM Guest OS from the Command-Line VGA Console 1/2
How to Install a KVM Guest OS from the Command-Line VGA Console 2/2

The command-line installation of a KVM Guest virtual machine is now complete. You can now shut down the Debian 11 guest.

From inside that guest.

madhu@debian:~$ sudo poweroff

Alternatively, from the host hypervisor.

$ sudo virsh shutdown debian11-minimal
Domain 'debian11-minimal' is being shutdown

7. Conclusion

In this blog, you learned how to install a KVM guest OS from the command-line using the virt-install tool. Once the installation is complete, the next step is to learn how to administer KVM virtual machine using the virsh command-line tool.

Going forward, I will be writing articles on how to use the virsh command-line tool and also on how to take snapshots of virtual machines.

Tags:

Comments

Leave a Reply

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