Creating virtual machines is one of the few things in my personal computer infrastructure I don't configure directly with Ansible. However, I have tried to make the process as fast and simple as possible. For generic Debian based virtual machines, I base new virtual machines off a base disk image.
I shell into the hypervisor to copy the base image.
tarn@hypervisor:~# cp /var/kvm/images/{debian-12-base.qcow2,demo.qcow2}
I then create a new virtual machine with the new disk image.
tarn@thinkpad:~# virt-install \
--name demo \
--network bridge=virbr0 \
--network bridge=br0 \
--disk /var/kvm/images/demo.qcow2 \
--vcpu 4 \
--memory 4096 \
--os-variant debian11 \
--console pty,target_type=virtio \
--serial pty \
--graphics none \
--noautoconsole \
--import
This will create a headless virtual machine with 4 vCPUs and 4GB RAM. On my
host a standard virtual machine gets two network interfaces. The virbr0
interface is a virtual IPv4 bridge with DHCP support, this network will be
allocated an IP address on an internal network and have a route to the Internet
when the machine starts. The br0
inferface is a IPv6 bridge provided by the
host system, the network doesn't have DHCP and will need to be configured. The
--serial
and --console
options allow access to the machine via a serial
console, the --noautoconsole
prevents virt-install
automatically connecting
to serial console after creating the virtual machine.
The next step is to work out what IP address was assigned to the NIC in the
virtual machine. This can be found by looking the DHCP leases, but its made a
bit more complicated because every new virtual machine will initially request a
lease with the hostname debian-12-base
.
tarn@thinkpad:~# virsh net-dhcp-leases default
Expiry Time MAC address Protocol IP address Hostname Client ID or DUID
-----------------------------------------------------------------------------------------------------------------------------------------------------
2023-10-22 22:26:12 52:54:00:16:b6:7e ipv4 192.168.122.34/24 debian-12-base ff:00:16:b6:7e:00:01:00:01:2c:c1:6b:25:52:54:00:16:b6:7e
2023-10-22 22:33:44 52:54:00:b6:9d:8a ipv4 192.168.122.66/24 debian-12-base ff:00:b6:9d:8a:00:01:00:01:2c:c1:6b:25:52:54:00:16:b6:7e
To workout which is the correct IP address
, the MAC addresses assigned to the
new virtual machine networks can be used.
tarn@thinkpad:~# virsh domiflist demo
Interface Type Source Model MAC
-----------------------------------------------------------
vnet85 bridge virbr0 virtio 52:54:00:b6:9d:8a
vnet86 bridge br0 virtio 52:54:00:07:91:8f
This IP isn't is not directly accessable from over the Internet and I don't
have a VPN setup with the hypervisor, however I do have an sshd
daemon on it
and I can use that as jump-host.
tarn@thinkpad:~# ssh -J hypervisor.tarnbarford.net 192.168.122.66
I wouldn't usually SSH directly in at this point, but rather have Ansible use
SSH to configure the system from here, including the networking
where I configure static IPv4 and IPv6 addresses. This means on the first run I
use the DHCP assigned address as the ansible_host
subsequently the staticly
configured address.
hosts:
demo:
ansible_user: tarn
ansible_host: 192.168.122.66
ansible_ssh_common_args: "-o ProxyCommand='ssh -q -W %h:%p tarn@hypervisor.tarnbarford.net'"
The virtual machine can then be accessed from the Internet via its static IPv6
address. To make it accessable via IPv4 I use iptables
rules to route a
specific port to a specific virtual machine address. All HTTP/HTTPS traffic is
routed to load balancer running HAProxy which uses the Host
header or Server
Name Indication (SNI) to route traffic to a specific VMs.
The process is pretty quick but it is still significantly more fiddly than starting a virtual machine with a cloud provider.