I like to use vagrant. It allow me to test a lot of things without messing up my laptop configuration.

This post will describe how-to use the libvirt provider with vagrant.

Vagrant

Vagrant allows to provision easily and automatically VMs(called boxes in vagrant terminology). It’s a great solution for experimenting with operating systems and solutions.

why using libvirt ?

VirtualBox is nice but i have three main issues with it :

  • i cannot use nested virtualization. It’s an really nice feature when playing with openstack for example. And i am missing it.

  • it’s not integrated with linux kernel. I am using Fedora 21 currently and after updates things can be messy.

  • sharing disks is easier to configure with kvm. It’s interesting for when you want to test a cluster for example.

Installing vagrant

It’s better to install vagrant from the official website :

╭─adejoux@feddy ~ ‹2.1.2›
╰─$ sudo yum install https://dl.bintray.com/mitchellh/vagrant/vagrant_1.7.2_x86_64.rpm

Here no need to install VirtualBox. We will use libvirt with kvm as provider.

Installing vagrant plugins

Unfortunately, libvirt is not yet an official provider. We need to install a plugin to have it managed.

The complete documentation is available on the github repository.

You can need to install the prerequisites(here for Fedora) :

╭─adejoux@feddy ~ ‹2.1.2›
╰─$ sudo yum install libxslt-devel libxml2-devel libvirt-devel
╭─adejoux@feddy ~ ‹2.1.2›
╰─$ vagrant plugin install vagrant-libvirt

Another problem with vagrant-libvirt is very few boxes are available for libvirt provider. So another plugin named vagrant-mutate allow to convert the existing boxes to work with libvirt provider.

The conversion consist mainly to move images to qcow2 format.

Prerequisites installation :

╭─adejoux@feddy ~ ‹2.1.2›
╰─$ sudo yum install qemu-img

And plugin installation :

╭─adejoux@feddy ~ ‹2.1.2›
╰─$ vagrant plugin install vagrant-mutate

Adding boxes

One popular box is the Ubuntu 14.04 image named ubuntu/trusty64.

We will convert it to use with libvirt :

vagrant mutate https://vagrantcloud.com/ubuntu/boxes/trusty64/versions/14.04/providers/virtualbox.box libvirt

You can also go directly on ubuntu cloud service to get an official cloud image made for vagrant :

╭─adejoux@feddy  ~/devel/vagrant/ansible_internet ‹2.1.2›
╰─$ vagrant mutate https://cloud-images.ubuntu.com/vagrant/vivid/current/vivid-server-cloudimg-amd64-vagrant-disk1.box libvirt
Downloading box disk1 from https://cloud-images.ubuntu.com/vagrant/vivid/current/vivid-server-cloudimg-amd64-vagrant-disk1.box
Extracting box file to a temporary directory.
Converting disk1 from virtualbox to libvirt.
    (100.00/100%)
Cleaning up temporary files.
The box disk1 (libvirt) is now ready to use.

Fedora is already providing boxes with libvirt provider for Fedora 22 as an Atomic Host. It’s still a alpha release but really interesting to test. And with vagrant it’s easy :).

You only need to use the standard vagrant box add command :

╭─adejoux@feddy  ~/devel/vagrant/ansible_internet ‹2.1.2›
╰─$ vagrant box add f22atomic http://download.fedoraproject.org/pub/fedora/linux/releases/test/22_Beta/Cloud/x86_64/Images/Fedora-Cloud-Atomic-Vagrant-22_Beta-20150415.x86_64.rhevm.ova
==> box: Adding box 'f22atomic' (v0) for provider:
    box: Downloading: http://download.fedoraproject.org/pub/fedora/linux/releases/test/22_Beta/Cloud/x86_64/Images/Fedora-Cloud-Atomic-Vagrant-22_Beta-20150415.x86_64.rhevm.ova
==> box: Successfully added box 'f22atomic' (v0) for 'libvirt'!

Something to note here is the box name. When using directly vagrant mutate, the box name is based on the file name. So we have virtualbox or box1 in the previous examples. It’s not very sexy. The only solution for now if you care about the box name(like me ;) is to use vagrant box add first and convert the box after download.

So it will give :

╭─adejoux@feddy ~/devel/vagrant/ansible_internet ‹2.1.2›
╰─$ vagrant box add vivid64 https://cloud-images.ubuntu.com/vagrant/vivid/current/vivid-server-cloudimg-amd64-vagrant-disk1.box                                                      1 ↵
==> box: Adding box 'vivid64' (v0) for provider:
    box: Downloading: https://cloud-images.ubuntu.com/vagrant/vivid/current/vivid-server-cloudimg-amd64-vagrant-disk1.box
==> box: Successfully added box 'vivid64' (v0) for 'virtualbox'!
╭─adejoux@feddy  ~/devel/vagrant/ansible_internet ‹2.1.2›
╰─$ vagrant mutate vivid64 libvirt
Converting vivid64 from virtualbox to libvirt.
    (100.00/100%)
The box vivid64 (libvirt) is now ready to use.

To list all boxes installed on your system :

╭─adejoux@feddy  ~/devel/vagrant/ansible_internet ‹2.1.2›
╰─$ vagrant box list
centos-6.5-x86_64 (virtualbox, 0)
chef/centos-6.5   (virtualbox, 1.0.0)
f22atomic         (libvirt, 0)
virtualbox        (libvirt, 0)
vivid64           (libvirt, 0)
vivid64           (virtualbox, 0)

You see each box name and the provider used(here either libvirt or virtualbox).

test environment

For my test environment, i will use the trusty64 image, i will create a dedicated folder :

mkdir testlab

In it, i will put this Vagrantfile file :

#use libvirt
ENV['VAGRANT_DEFAULT_PROVIDER'] = 'libvirt'

VAGRANTFILE_API_VERSION = "2"
Vagrant.require_version ">= 1.5.0"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|

  config.vm.box = "virtualbox"

  # Turn off shared folders
  config.vm.synced_folder ".", "/vagrant", id: "vagrant-root", disabled: true

  # Begin testvm
  config.vm.define "vm1" do |config|
    config.vm.hostname = "vm1"

    # eth1
    config.vm.network "private_network", ip: "10.0.0.10"

    config.vm.provider "libvirt" do |libvirt|
      #use the storage pool named external
      #libvirt.storage_pool_name = "external"
      libvirt.driver = "kvm"
      libvirt.memory = 1024
      libvirt.cpus = 1
    end
  end
end

It will create a vm named testvm with 1 VCPU and 1GB of memory.

Normally i use a dedicated storage pool to store my vms named external. It’s commented here in case you want to use my Vagrantfile.

I also added a second network interface on a private network and assigned a fixed ip address.

So after that, the next step is to create the vm with vagrant up:

╭─adejoux@feddy ~/devel/vagrant/testlab ‹2.1.2›
╰─$ vagrant up
Bringing machine 'vm1' up with 'libvirt' provider...
==> vm1: Creating image (snapshot of base box volume).
==> vm1: Creating domain with the following settings...
==> vm1:  -- Name:              testlab_vm1
==> vm1:  -- Domain type:       kvm
==> vm1:  -- Cpus:              1
==> vm1:  -- Memory:            1024M
==> vm1:  -- Base box:          virtualbox
==> vm1:  -- Storage pool:      external
==> vm1:  -- Image:             /disk2/libvirt/testlab_vm1.img
==> vm1:  -- Volume Cache:      default
==> vm1:  -- Kernel:
==> vm1:  -- Initrd:
==> vm1:  -- Graphics Type:     vnc
==> vm1:  -- Graphics Port:     5900
==> vm1:  -- Graphics IP:       127.0.0.1
==> vm1:  -- Graphics Password: Not defined
==> vm1:  -- Video Type:        cirrus
==> vm1:  -- Video VRAM:        9216
==> vm1:  -- Keymap:            en-us
==> vm1:  -- Command line :
==> vm1: Starting domain.
==> vm1: Waiting for domain to get an IP address...
==> vm1: Waiting for SSH to become available...
    vm1:
    vm1: Vagrant insecure key detected. Vagrant will automatically replace
    vm1: this with a newly generated keypair for better security.
    vm1:
    vm1: Inserting generated public key within guest...
    vm1: Removing insecure key from the guest if its present...
    vm1: Key inserted! Disconnecting and reconnecting using new SSH key...
==> vm1: Starting domain.
==> vm1: Waiting for domain to get an IP address...
==> vm1: Waiting for SSH to become available...
==> vm1: Creating shared folders metadata...
==> vm1: Setting hostname...
==> vm1: Configuring and enabling network interfaces...

And the vm is ready. You can access it with vagrant :

vagrant ssh

ssh connection

It’s pretty boring to copy the ssh keys with ssh-copy-id each time you recreate your vm.

You can type vagrant ssh to connect but it’s still better to only do ssh yourvm and not hard to configure.

vagrant ssh-config generate for you the configuration lines to put in your ~/.ssh/config file :

╭─adejoux@feddy  ~/devel/vagrant/testlab ‹2.1.2›
╰─$ vagrant ssh-config
Host vm1
  HostName 192.168.121.54
  User vagrant
  Port 22
  UserKnownHostsFile /dev/null
  StrictHostKeyChecking no
  PasswordAuthentication no
  IdentityFile /home/adejoux/devel/vagrant/testlab/.vagrant/machines/vm1/libvirt/private_key
  IdentitiesOnly yes
  LogLevel FATAL

The only thing I replace is the IP address for Hostname. Here I will use 10.0.0.10 instead like configured in my Vagrantfile.

It’s because the IP address assigned dynamically by vagrant change each time.

So now i can do ssh vm1 each time i want to connect on my vm. Pretty nice :)

the end

And that’s all for now. I shown how to setup an test environment with vagrant. I hope you will find vagrant useful. I like it very much. One of the best solutions i have seen to test quickly things. The other is Docker but the use case are not the sames.

references

vagrant official website

vagrant libvirt plugin

vagrant mutate plugin