vagrant-libvirt

repository·main·Indexed 25 days ago

https://github.com/vagrant-libvirt/vagrant-libvirt

A Vagrant plugin that enables the Libvirt provider, allowing users to manage and provision virtual machines using the Libvirt toolkit instead of the default VirtualBox provider. It supports hypervisor control for KVM and QEMU, lifecycle management, qcow2 image handling, and various synced folder methods including rsync, nfs, 9p, and virtiofs.

Tokens
22.5K
Snippets
61
Records
88
Agent score
81%

What's inside vagrant-libvirt

  1. Overview of Vagrant-libvirt features

    main

    Vagrant-libvirt is a plugin that adds a Libvirt provider to Vagrant. It allows Vagrant to control and provision machines via the Libvirt toolkit.

    Key capabilities include:

    • Hypervisor Control: Control local Libvirt hypervisors and manage Libvirt domains (create, boot, halt, etc.).
    • Lifecycle Management: Supports standard Vagrant commands: up, destroy, suspend, resume, halt, ssh, reload, package, and provision.
    • Storage & Networking: Uploads qcow2 box images to Libvirt storage pools, creates COW (Copy-on-Write) diff images for domains, creates private networks, and sets up hostnames and network interfaces.
    • Provisioning & Syncing: Supports all built-in Vagrant provisioners. Synced folders are supported via rsync, nfs, 9p, or virtiofs.
    • Advanced Features: Supports snapshots, package caching (via vagrant-cachier), and using boxes from other providers (via vagrant-mutate). It also supports VMs with no box for PXE boot purposes (requires Vagrant 1.6+).
  2. Understand Box Formats: Version 1 and Version 2

    main

    Version 1 (Standard)

    The standard format used by most boxes. It is a tarball containing:

    • box.img: The qcow2 image file.
    • metadata.json: Describes the box (provider, virtual_size, format).
    • Vagrantfile: Contains default provider-specific configuration.

    Version 2 (Experimental)

    Version 2 supports boxes with multiple disks. It is currently experimental and not the default. To use it for verification, export VAGRANT_LIBVIRT_BOX_FORMAT_VERSION=v2 before running vagrant package.

    In Version 2, format and virtual_size are automatically retrieved via qemu-img info, so they are no longer required in metadata.json. The metadata focuses on a disks array where each disk requires a path (relative to the box base). You can optionally provide a name to override the target volume name in the libvirt storage pool (though vagrant-libvirt will still prefix it to avoid clashes).

    {
      "disks": [
          {
              "path": "disk1.img"
          },
          {
              "path": "disk2.img",
              "name": "secondary_disk"
          },
          {
              "path": "disk3.img"
          }
      ],
      "provider": "libvirt"
    }
  3. Configure Private Networks

    main

    Private networks in vagrant-libvirt support virtual network switching or point-to-point Guest OS to Guest OS connections using UDP, Multicast, or TCP tunnels.

    When using virtual network switching, the provider can automatically create networks if they do not exist. By default, these networks are NATed to the outside world and provide DHCP.

    Note that private network addresses are only visible to the Libvirt host and are not accessible from outside the hypervisor box.

    # Private network using virtual network switching
      config.vm.define :test_vm1 do |test_vm1|
        test_vm1.vm.network :private_network, :ip => "10.20.30.40"
      end
    
      # Private network using DHCP and a custom network
      config.vm.define :test_vm1 do |test_vm1|
        test_vm1.vm.network :private_network,
          :type => "dhcp",
          :libvirt__network_address => '10.20.30.0'
      end
    
      # Private network using a domain name
      config.vm.define :test_vm1 do |test_vm1|
        test_vm1.vm.network :private_network,
          :ip => "10.20.30.40",
          :libvirt__domain_name => "test.local"
      end
  4. How a machine is created in Vagrant-libvirt

    main

    When you run vagrant up with the libvirt provider, the plugin follows these steps to create a new machine:

    1. Connection: Connects to Libvirt locally or remotely via SSH.
    2. Image Management: Checks if the box image exists in the Libvirt storage pool. If missing, it uploads the image to the remote Libvirt storage pool as a new volume.
    3. Volume Creation: Creates a COW (Copy-on-Write) diff image of the base box image specifically for the new Libvirt domain.
    4. Domain Lifecycle: Creates and starts the new domain on the Libvirt host.
    5. Network Discovery: Checks for a DHCP lease from the dnsmasq server.
    6. Availability Check: Waits until SSH is available on the domain.
    7. Finalization: Performs folder syncing and executes any Vagrant provisioners defined in the Vagrantfile.
  5. Understand which Libvirt attributes update on `vagrant reload`

    main

    When running vagrant reload, the following domain-specific attributes are automatically updated in the defined domain:

    • disk_bus (updated only on disks; skips CDROMs)
    • nic_model_type
    • memory
    • cpus
    • nested
    • cpu_mode (Note: custom mode is not supported for reload)
    • graphics_type
    • graphics_port
    • graphics_websocket
    • graphics_ip
    • graphics_passwd
    • graphics_autoport
    • keymap
    • video_type
    • video_vram
    • tpm_model
    • tpm_type
    • tpm_path
    • tpm_version
  6. Install vagrant-libvirt on Arch Linux

    main

    Since Arch is a rolling release, use the distribution's latest version of Vagrant. Note that ruby-libvirt is no longer available via AUR, so you must install the necessary build tools and system packages manually.

    sudo pacman --sync --sysupgrade --refresh
    sudo pacman --query --search 'iptables' | grep "local" | grep "iptables " && \
        sudo pacman --remove --nodeps --nodeps --noconfirm iptables
    sudo pacman --sync --needed --noprogressbar --noconfirm \
        iptables-nft libvirt qemu openbsd-netcat bridge-utils dnsmasq vagrant \
            pkg-config gcc make ruby
    vagrant plugin install vagrant-libvirt
  7. Install vagrant-libvirt on Ubuntu / Debian

    main

    Installation steps vary depending on your Ubuntu/Debian version. For modern versions (Ubuntu 18.10+, Debian 9+), it is recommended to use the distro-provided Vagrant and then install the remaining dependencies and the plugin manually.

    ### Ubuntu 18.10, Debian 9 and up
    
    # Install distro Vagrant and base deps
    sudo apt-get purge vagrant-libvirt
    sudo apt-mark hold vagrant-libvirt
    sudo apt-get install -y qemu libvirt-daemon-system libvirt-dev ebtables libguestfs-tools
    sudo apt-get install -y vagrant ruby-fog-libvirt
    vagrant plugin install vagrant-libvirt
    
    # Install build dependencies and plugin
    sudo apt-get build-dep vagrant ruby-libvirt
    sudo apt-get install -y qemu libvirt-daemon-system ebtables libguestfs-tools \
        libxslt-dev libxml2-dev zlib1g-dev ruby-dev
    vagrant plugin install vagrant-libvirt
    
    ### Ubuntu 18.04, Debian 8 and older
    
    # Install remaining dependencies and plugin
    sudo apt-get build-dep vagrant ruby-libvirt
    sudo apt-get install -y qemu libvirt-bin ebtables libguestfs-tools \
        libxslt-dev libxml2-dev zlib1g-dev ruby-dev
    vagrant plugin install vagrant-libvirt
    
    # Install distro Vagrant
    sudo apt-get purge vagrant-libvirt
    sudo apt-mark hold vagrant-libvirt
    sudo apt-get install -y qemu libvirt-bin ebtables libguestfs-tools \
        sudo apt-get install -y vagrant ruby-fog-libvirt
    vagrant plugin install vagrant-libvirt
  8. Enable Secure Encryption Virtualization (SEV)

    main

    To use SEV, you must use a q35 machine type with UEFI boot.

    Key Requirements:

    1. Use an UEFI base box.
    2. Configure loader and nvram (OVMF files).
    3. Set machine_type to a q35 variant.
    4. Call launchsecurity with the appropriate parameters.
    5. Set memtune with a hard_limit in kB (this value must be higher than the libvirt.memory value, which is in MB).
    6. Explicitly enable memballoon to allow the iommu flag.
    7. Set management_network_driver_iommu = true for the management network.
    8. For public networks, use the driver_iommu => true flag.
    Vagrant.configure("2") do |config|
      config.vm.provider :libvirt do |libvirt|
        libvirt.loader = "/usr/share/OVMF/OVMF_CODE.fd"
        libvirt.nvram = "/path/to/ovmf/OVMF_VARS.fd"
        libvirt.machine_type = 'pc-q35-focal'
        
        libvirt.launchsecurity :type => 'sev', :cbitpos => 47, :reducedPhysBits => 1, :policy => "0x0003"
        libvirt.memtune :type => "hard_limit", :value => 2500000 # Value in kB
        
        libvirt.memballoon_enabled = true
        libvirt.memballoon_model = 'virtio'
        libvirt.memballoon_pci_bus = '0x07'
        libvirt.memballoon_pci_slot = '0x00'
        
        libvirt.management_network_driver_iommu = true
      end
    
      config.vm.network :public_network, :dev => "br0", :bridge => "br0", :mode => "bridge", :type => "bridge", :driver_iommu => true
    end
  9. Start a VM using the Libvirt provider

    main

    When running Vagrant commands, you must explicitly tell Vagrant to use the libvirt provider, as it may default to VirtualBox.

    Using the CLI flag

    Run the following command in your project directory:

    vagrant up --provider=libvirt

    Using an environment variable

    To avoid specifying the provider flag every time, set the VAGRANT_DEFAULT_PROVIDER environment variable:

    export VAGRANT_DEFAULT_PROVIDER=libvirt
    vagrant up --provider=libvirt
  10. Install the latest development version of vagrant-libvirt

    main

    You can install the latest development version by providing a .gem file directly to the Vagrant plugin install command.

    Alternatively, you can install directly from the GitHub rubygems package repository. Warning: This method will embed your GitHub token directly into your ~/.vagrant.d/plugins.json file. It is recommended to use a classic token limited to read:packages only.

    # Install from a local gem file
    vagrant plugin install ./vagrant-libvirt-<version>.gem
    
    # Install from GitHub rubygems package repository
    vagrant plugin install vagrant-libvirt \
      --plugin-source https://${USERNAME}:${GITHUB_TOKEN}@rubygems.pkg.github.com/vagrant-libvirt \
      --plugin-version "0.10.9.pre.62"
  11. Use Docker or Podman to run Vagrant with Libvirt

    main

    To avoid compatibility issues between the Vagrant Ruby runtime and libvirt dependencies, you can use a pre-built Docker/Podman image.

    • Full image: Contains the toolchain to build and install vagrant-libvirt and its dependencies.
    • Slim image (-slim suffix): Contains only vagrant-libvirt for environments where you don't need to install additional plugins.

    Key Configuration:

    • If connecting to a remote libvirt system, you can omit the -v /var/run/libvirt/:/var/run/libvirt/ mount.
    • If your distribution uses qemu:///session by default, set the LIBVIRT_DEFAULT_URI environment variable.

    Podman Users: When using Podman (especially in rootless mode), you must include --entrypoint /bin/bash and --security-opt label=disable to bypass the default entrypoint.sh.

    ### Using Docker
    
    # Pull the latest release
    docker pull vagrantlibvirt/vagrant-libvirt:latest
    
    # Or pull the absolute latest code
    docker pull vagrantlibvirt/vagrant-libvirt:edge
    
    # Run a command (e.g., vagrant status)
    docker run -it --rm \
      -e LIBVIRT_DEFAULT_URI \
      -v /var/run/libvirt/:/var/run/libvirt/ \
      -v ~/.vagrant.d:/.vagrant.d \
      -v $(realpath "${PWD}"):${PWD} \
      -w "${PWD}" \
      --network host \
      vagrantlibvirt/vagrant-libvirt:latest \
        vagrant status
    
    ### Using Podman
    
    podman run -it --rm \
      -e LIBVIRT_DEFAULT_URI \
      -v /var/run/libvirt/:/var/run/libvirt/ \
      -v ~/.vagrant.d:/.vagrant.d \
      -v $(realpath "${PWD}"):${PWD} \
      -w "${PWD}" \
      --network host \
      --entrypoint /bin/bash \
      --security-opt label=disable \
      docker.io/vagrantlibvirt/vagrant-libvirt:latest \
        vagrant $@