If you need Ubuntu Vagrant boxes but are working on a Red Hat-based Linux distribution (RHEL, CentOS, Fedora, ArchLinux etc.) then you are faced with a dilemma. All of the official Ubuntu Vagrant boxes available in the Vagrant Cloud are in Virtualbox format but this format has no built-in support on Red Hat etc. Yes, you could install Virtualbox directly from the Oracle website but this is a one-off event and doesn't allow you to get automatic updates etc. In addition, Red Hat has an excellent (the best?) hypervisor in the form of KVM which is also available from the official repositories on CentOS, Fedora etc.
Security Aside: The Vagrant Cloud website has many Ubuntu boxes, some with convenient applications already installed so you don't have to waste time doing this yourself. But think twice before you grab one of those: do you know who created it? do you trust them? are they really who they claim to be? what else did they install on that box? As convenient as these pre-prepared boxes are, they are an easy way to sneak nasty things onto your network. So to be safe, only use the official boxes from Canonical, CentOS etc.
OK, back to the task at hand - how to convert an Ubuntu Vagrant box (designed for the virtualbox provider ) to a box that can be used on RHEL/CentOS/Fedora (with KVM/libvirt provider)? The basic process is
- Get the Vagrant box file
- Unbundle this Vagrant box file
- Convert the disk image to a format libvirt can understand
- Create config files for your new box
- Bundle together your new config files and disk image into a new box
- Add to Vagrant
Download the box
The first hurdle in the road is simply finding what you want to download! Even though you can see all these boxes on the Vagrant Cloud site, they are not actually directly downloadable from Vagrant. However, on the more detailed page for each box, like this one for Ubuntu Bionic 18.04, you will see next to each provider-specific box that these boxes are actually hosted on an Ubuntu site. Going there you can navigate to "daily vagrant builds" and here you will find the most up-to-date Vagrant box of Ubuntu 18.04.
Unbundle the box
The Vagrant box file is nothing but a *.tar file (but has a .box extension). Looking at the contents you will see one very large file (the actual disk image) and some small metadata and config files.
$ tar tvf bionic-server-cloudimg-amd64-vagrant.box
-rw-r--r-- root/root 11061 2018-12-05 09:08 box.ovf
-rw-r--r-- root/root 478 2018-12-05 09:08 Vagrantfile
-rw-r--r-- root/root 31 2018-12-05 09:08 metadata.json
-rw-r--r-- root/root 310 2018-12-05 09:08 ubuntu-bionic-18.04-cloudimg.mf
-rw-r--r-- root/root 316687872 2018-12-05 09:08 ubuntu-bionic-18.04-cloudimg.vmdk
-rw-r--r-- root/root 72192 2018-12-05 09:08 ubuntu-bionic-18.04-cloudimg-configdrive.vmdk
Now we can extract this box with
$ tar xvf bionic-server-cloudimg-amd64-vagrant.box
Convert the disk image
We now need to convert the disk image to *.qcow2 format, which is native to KVM. To do this we will use a great little tool from the libvirt suit, qemu-img. The command line options are pretty straightforward, you need to tell it what in input format to expect, what output format to produce and the names of the input and output files.
qemu-img convert -f vmdk -O qcow2 ubuntu-bionic-18.04-cloudimg.vmdk box.img
$ qemu-img info box.img
image: box.img
file format: qcow2
virtual size: 10G (10737418240 bytes)
disk size: 1.0G
cluster_size: 65536
Format specific information:
compat: 1.1
lazy refcounts: false
refcount bits: 16
corrupt: false
Modify the Vagrantfile to be as follows
$ cat Vagrantfile
Vagrant.configure("2") do |config|
config.vm.provider :libvirt do |libvirt|
libvirt.driver = "kvm"
libvirt.host = ""
libvirt.connect_via_ssh = false
libvirt.storage_pool_name = "default"
end
end
$ qemu-img info box.img
image: box.img
file format: qcow2
virtual size: 10G (10737418240 bytes)
disk size: 1.0G
cluster_size: 65536
Format specific information:
compat: 1.1
lazy refcounts: false
refcount bits: 16
corrupt: false
Create config files
According to the docs of vagrant-libvirt provider, the box tarball consists of only three items
- A *.qcow2 image that is named box.img
- A metadata.json file describing box image. This file must have the following three pieces of information
- Provider (libvirt in our case)
- Disk image format (qcow2 in our case)
- Virtual_size (the size in GB to which the qcow2 image can grow, this will not be the actual size of the file created in the disk conversion step above)
- A Vagrantfile that defines default settings for the libvirt provider (all of these defaults can be over-written by a project-specific Vagrantfile
Modify the metadata.json file so that it looks like this (customize the disk size if you wish)
$ cat metadata.json
{
"provider": "libvirt",
"format": "qcow2",
"virtual_size": 16
}
$ cat Vagrantfile
Vagrant.configure("2") do |config|
config.vm.provider :libvirt do |libvirt|
libvirt.driver = "kvm"
libvirt.host = ""
libvirt.connect_via_ssh = false
libvirt.storage_pool_name = "default"
end
end
Create new box
Rename the qcow2 image to box.img and then tar up the three parts into a new box called ubuntu-1804.box
$ mv ubuntu-1804.qcow2 box.img
tar cvzf ubuntu-1804.box -S --totals ./metadata.json ./Vagrantfile ./box.img
Add new box to Vagrant
When adding the box it to vagrant it will unbundle it again and store the disk image and config & metadata files in the correct locations (default location is ~/.vagrant.d/)
$ vagrant box add ubuntu-1804.box --name ubuntu-1804 --provider libvirt
==> box: Box file was not detected as metadata. Adding it directly...
==> box: Adding box 'ubuntu-1804' (v0) for provider: libvirt
box: Unpacking necessary files from: file:///home/brett/tmp/ubuntu-1804.box
==> box: Successfully added box 'ubuntu-1804' (v0) for 'libvirt'!
You can see all the boxes installed (along with the provider and box version number) in Vagrant by doing
$ vagrant box list
centos/7 (libvirt, 1809.01)
ubuntu-1804 (libvirt, 0)
How to use this new Ubuntu-under-libvirt box
Now just create a simple Vagrantfile and point it to your new Ubuntu/KVM box
Vagrant.configure("2") do |config|
config.vm.box = "centos/7"
config.vm.provider :libvirt do |libvirt|
libvirt.memory = 1024
end
Vagrant.configure("2") do |config|
config.vm.box = "centos/7"
config.vm.provider :libvirt do |libvirt|
libvirt.memory = 1024
end
And now all you have to do is vagrant up and you'll be running an Ubuntu Vagrant VM on Centos!