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 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 use 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.
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
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).
For my test environment, i will use the trusty64 image, i will create a dedicated folder :
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 :
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 :)
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.