Setting up Vagrant with libvirt (Fedora 40)

Hi! This is personal documentation (also known as ‘my notes.’) Quality is.. not guaranteed. WIP as of 6/10/24. I keep getting distracted by PowerShell and SQL

Adapted on 6/5/24 from:

Quickstart

Install packages

# dnf install qemu-kvm libvirt libguestfs-tools virt-install rsync vagrant
# systemctl enable libvirtd && sudo systemctl start libvirtd
# vagrant plugin install vagrant-libvirt

Download a box

$ vagrant box add fedora/40-cloud-base --provider=libvirt

Hey! Are you from the future? Is Fedora 40 old now?

Write a Vagrantfile

$ mkdir vagrant-demo && cd vagrant-demo
[user:~/vagrant-demo]$ touch Vagrantfile
Vagrant.configure("2") do |config|
  
  # image to use
  config.vm.box = "fedora/40-cloud-base"

  config.vm.provider :libvirt do |libvirt|

    libvirt.cpus = 2
    libvirt.memory = 2048

    # the default qemu session connection cannot create networks
    # either disable it, like so:
    libvirt.qemu_use_session = false
    # or specify the connection uri:
    # libvirt.uri = 'qemu:///system'

  end

  config.vm.hostname = "localhost"

  # Mounting directories
  # (this is the implicit default, manually disabled)
  config.vm.synced_folder "./", "/vagrant", disabled: true

  # Networking
  # VAGRANT GUESTS ARE INSECURE BY DEFAULT
  # DO NOT EXPOSE THEM TO UNSECURED NETWORKS

  # config.vm.network "forwarded_port", guest: 443, host: 4433
  #
  # config.vm.network "public_network", ip: "192.168.1.1", hostname: true
  # hostname: true adds the hostname and interface IP to /etc/hosts
  #
  # config.vm.network "public_network"
  # no IP specified? DHCP will be used.
  #
  # By default, public networks will bridge to the
  # network interface on the host machine. If more
  # than one exists, Vagrant will ask which to use.
  # Or specify the interface like so:
  #
  # config.vm.network "public_network", bridge: "eno1"

end

Define multiple VMs in a Vagrantfile

VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
    config.vm.box = "generic/rocky9"
    config.ssh.insert_key = false
    config.vm.synced_folder ".", "/vagrant", disabled: true
    config.vm.provider :libvirt do |lv|
        lv.cpus = 1
        lv.memory = 1024
        lv.qemu_use_session = false
    end

    config.vm.define "app1" do |app|
        app.vm.hostname = "app1.test"
        app.vm.network :private_network, ip: "192.168.99.10"
    end

    config.vm.define "app2" do |app|
        app.vm.hostname = "app2.test"
        app.vm.network :private_network, ip: "192.168.99.11"
    end

    config.vm.define "db" do |db|
        db.vm.hostname = "db1.test"
        db.vm.network :private_network, ip: "192.168.99.15"
    end
end

Worth noting that Fedora cloud guest images do not take assigned IPs. Known issue, open since Fedora 36, as of 6/8/24

Start a VM with Vagrant

[root:~/vagrant-demo]# vagrant up

Connect to a Vagrant-managed VM (default)

[root:~/vagrant-demo]# vagrant ssh

Further Configuration & Behavior

Make files accessible to the VM

Vagrant docs

By default, Vagrant syncs the directory containing the Vagrantfile on the host with the /vagrant directory in the guest.

Below is the implicit default behavior explicitly specified:

  # "source" on host, "destination" on guest
  config.vm.synced_folder ".", "/vagrant"

Other quick examples:

  config.vm.synced_folder "data/", "/mnt/data"
  config.vm.synced_folder "src/", "/srv/website"

Configure networking

Vagrant docs

Vagrant is intentionally NOT secure by default. EXERCISE CAUTION.

Vagrant assumes that the first network device is NAT, so the host (and Vagrant) can always talk to the guest directly.

Private networks should never allow the general public to access your guest

Public networks can allow the general public to access your guest