First try Vagrant

Users (or future users) of Vagrant, this documentation will allow you to quickly get started with the tool and understand its usefulness.

First try Vagrant
A bunch of boxes on a desk, flat 3d, white background. Généré avec l'IA DALL-E 3.

If you are a sysops or devops, you know how tedious and repetitive creating virtual machines can be. This is where Vagrant comes in, an open-source tool that allows for easy creation and management of development and testing environments.

Usage of Vagrant

The benefit of Vagrant is that it generates reproducible and ephemeral VMs with a configuration specified in a Vagrantfile. This allows developers to quickly test their applications on different environments while ensuring consistency of the VMs used.

As sysops, this tool is particularly useful for testing updates or tools in a pre-production context.

Some words to understand

Some key elements of understanding: "Boxes" are pre-built images that Vagrant uses to create VMs. You can find boxes for many Linux distributions as well as for Windows. It is also possible to create custom boxes.

You can search for images at this address: https://app.vagrantup.com/boxes/search.

To use Vagrant, you must first install prerequisites such as libvirt, VirtualBox, and necessary libraries. You will also need to add your local user to the "libvirt" or "vbox" group (depending on your virtualization tool) to have the rights to create VMs.

To deploy your first VM using Vagrant, you can create a test environment in a folder named "Vagrant". Then, you can edit the Vagrantfile to specify the VM configuration, such as the Linux distribution, the amount of RAM, etc.

💡
Do NOT use Vagrant in your production environments !

In this document, I'll only use Virtualbox.

Requirements for Linux Debian 11

Let install libvirt (with its dependencies), VirtualBox et their libraries. We will add the local user of the machine to the "libvirt" group to have the rights to create VMs.

$ sudo apt update && sudo apt upgrade

$ sudo echo "deb [arch=amd64] https://download.virtualbox.org/virtualbox/debian bullseye contrib" > /etc/apt/sources.list.d/virtualbox.list

$ wget -q https://www.virtualbox.org/download/oracle_vbox_2016.asc -O- | apt-key add -
$ wget -q https://www.virtualbox.org/download/oracle_vbox.asc -O- | apt-key add -

$ sudo apt update && sudo apt install gcc make perl linux-headers-amd64 qemu-kvm libvirt-clients libvirt-daemon-system virtualbox-6.0

$ sudo usermod -aG libvirt <username>

Vagrant test environment

Before diving into generating virtual machines with Vagrant, we will create a first test environment in the local user's directory, in a folder that I will name "Vagrant".

$ mkdir ~/Vagrant
$ touch ~/Vagrant/Vagrantfile

Creation of a virtual machine with Ubuntu 22.04 (Jammy) under VirtualBox

The first (and default) generated network card is a NAT adapter, to permit Vagrant to communicate with the host. The line "config.vm.post_up_message" specify a customized text when the VM will be created and started.

Let's modify the "Vagrantfile" (no file extension) : $ sudo nano Vagrantfile.

ENV['VAGRANT_DEFAULT_PROVIDER'] = 'virtualbox'

Vagrant.configure("2") do |config|
  config.vm.define "vag-ubuntu2204" do |config|
  config.vm.hostname = "vag-ubuntu2204"
  config.vm.box = "generic/ubuntu2204"
  config.vm.post_up_message = "VM Ok"
  end
end

This Vagrantfile is simple : creation of an Ubuntu 22.04 VM (without graphics), displaying a text when it finished initiating.

To have a second network card and connect it to the private host network of VirtualBox, add this line next to "config.vm.define..." :

config.vm.network "private_network", type: "dhcp"

Use libvirt for Vagrant

Install this plugin to permit Vagrant to use libvirt :

$ vagrant plugin install vagrant-libvirt

Create three simultaneously Ubuntu 22.04 VM

Need three VM now ? Simple like this :

# -*- mode: ruby -*-
# vi: set ft=ruby :

ENV['VAGRANT_DEFAULT_PROVIDER'] = 'virtualbox'

Vagrant.configure("2") do |config|
  config.vm.define "vag-ubuntu2204-1" do |config|
  config.vm.hostname = "vag-ubuntu2204-1"
  config.vm.box = "generic/ubuntu2204"
  config.vm.post_up_message = "VM 1 Ok"
  end

  config.vm.define "vag-ubuntu2204-2" do |config|
  config.vm.hostname = "vag-ubuntu2204-2"
  config.vm.box = "generic/ubuntu2204"
  config.vm.post_up_message = "VM 2 Ok"
  end

  config.vm.define "vag-ubuntu2204-3" do |config|
  config.vm.hostname = "vag-ubuntu2204-3"
  config.vm.box = "generic/ubuntu2204"
  config.vm.post_up_message = "VM 3 Ok"
  end
end

By default, virtual machines generated by Vagrant cannot access to the host storage.

Vagrant let you sync files between your host and your virtual machines. It can be useful when you need to share files or resources (like templates or config files). Example : to share the folder "/home/user/shared" from your host with your VM, add this line to the Vagrantfile :

config.vm.synced_folder "/home/user/shared", "/vagrant_data"

This configuration line force Vagrant to sync the folder "/home/user/shared" from your host with the folder "/vagrant_data" from your virtual machine.

Usual CLI with Vagrant

Add a box

$ vagrant box add <fournisseur>/<nomBox>
# e.q. "vagrant box add generic/ubuntu2204"

List boxes

$ vagrant box list

Generate and start VM

$ vagrant up

Log into a VM

$ vagrant ssh <nom-vm.define>

Shutdown gracefully every VM of the project

$ vagrant halt

Destroy every VM of the project

$ vagrant destroy

Some examples of Vagrantfile

I'm using VirtualBox for my tests, because of the wide usage of it and it's cross-platform.

Usage of Vagrant with Docker :

# -*- mode: ruby -*-
# vi: set ft=ruby :

ENV['VAGRANT_DEFAULT_PROVIDER'] = 'virtualbox'

Vagrant.configure("2") do |config|
  config.vm.box = "generic/ubuntu2204"
  config.vm.provision "docker" do |d|
    d.pull_images "nginx", "postgres"
    d.run "web", image: "nginx", ports: ["80:80"]
    d.run "db", image: "postgres", ports: ["5432:5432"]
  end
end

Usage of Ansible provision to configure the VM :

# -*- mode: ruby -*-
# vi: set ft=ruby :

ENV['VAGRANT_DEFAULT_PROVIDER'] = 'virtualbox'

Vagrant.configure("2") do |config|
  config.vm.box = "generic/ubuntu2204"
  config.vm.provision "ansible" do |ansible|
    ansible.playbook = "playbook.yml"
  end
end

The playbook.yml file needs to be in the same folder where is the Vagrantfile.


Generate a web development environment, with a VM that's have nginx, PHP 7.4 and MySQL server :

# -*- mode: ruby -*-
# vi: set ft=ruby :

ENV['VAGRANT_DEFAULT_PROVIDER'] = 'virtualbox'

Vagrant.configure("2") do |config|
  config.vm.box = "generic/ubuntu2204"
  config.vm.provider "virtualbox" do |vb|
    vb.memory = "2048"
    vb.cpus = "2"
  end
  config.vm.provision "shell", inline: <<-SHELL
    sudo apt-get update
    sudo apt-get install -y nginx mysql-server php7.4 php7.4-mysql
  SHELL
end

To be continued...