Vagrant est un logiciel libre permettant de constuire rapidement des machines virtuelles (et depuis peu des conteneurs Docker) à destination de développeurs. Bien qu’utilisable également avec d’autres solutions de virtualisation, Virtualbox reste la solution privilégiée. Via une syntaxe de type code, il permet de faciliter la génération et la configuration de ces machines ainsi que leur post-configuration.
Les exemples pas à pas sont tous disponibles sur mon Gitlab à l’adresse : https://gitlab.com/julienmorot/vagrant-examples. J’utiliserai pour tous les exemples la « box », c’est à dire l’image système officielle Ubuntu 18.04 de l’équipe Ubuntu.
Je vous propose au travers de cet article, de progresser pas à pas au travers d’exemples de plus en plus fournis.
Commençons par un exemple le plus simple possible, dont le template peut être généré via vagrant init ubuntu/bionic64. On définit un fichier dont le nom s’appelle toujours Vagrantfile avec comme contenu le nom et le modèle de box. Le 2 correspond à la version de Vagrant.
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/bionic64"
config.vm.hostname = "vagrantbox"
end
Une fois notre fichier Vagrantfile, un simple vagrant up lance le build de la VM.

Ensuite, vagrant ssh permet d’accéder à la VM.

Enfin, pour clôturer le cycle de vie de la VM, vagrant destroy détruit celle-ci.

Poursuivons notre exploration en définissant quelques options spécifiques au provider virtualbox pour configurer le dimensionnement de la VM en fonction de nos besoins. Je ne répèterai pas les étapes up/ssh/destroy qui ayant été vues plus haut n’ont pas nécessité à être répétées inutilement.
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/bionic64"
config.vm.hostname = "vagrantbox"
config.vm.network "private_network", ip: "192.168.56.10", virtualbox__intnet: "nat"
config.vm.provider :virtualbox do |vbox|
vbox.gui = false
vbox.linked_clone = true
vbox.memory = 1024
vbox.cpus = 1
end
end
Nous avons définit dans l’exemple précédent une VM mieux dimensionnée, afin de ne pas répéter les étapes de post-configuration dans un vagrant ssh, nous allons indiquer à Vagrant de réaliser ces étapes répétitives pour nous, notamment pour ma part l’enregistrement sur le serveur puppet.
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/bionic64"
config.vm.hostname = "vagrantbox"
config.vm.network "private_network", ip: "192.168.56.10", virtualbox__intnet: "nat"
config.vm.provider :virtualbox do |vbox|
vbox.gui = false
vbox.linked_clone = true
vbox.memory = 1024
vbox.cpus = 1
end
config.vm.provision "shell", inline: <<-SHELL
apt-get update
apt-get -y dist-upgrade
apt-get -y install screen htop puppet nmap
puppet config set server puppet.int.morot.fr --section agent
puppet agent -t
SHELL
end
Passons à quelque chose de plus intéressant. Jusqu’ici nous avons déployé une VM unitairement, mais bien souvent une infra demande plusieurs serveurs, comme un frontal et un serveur de base de données avec des répartiteur de charge. Voyons-donc comment au sein d’un même Vagrantfile comment nous pouvons boucler sur une liste de serveurs et leur attribuer un nom, de la mémoire ou un nombre de vcpu différents au sein d’un même déploiement.
hosts = [
{ :hostname => 'revproxy', :ip => '192.168.56.10', :mem => 512, :cpu => 1 },
{ :hostname => 'www1', :ip => '192.168.56.21', :mem => 1024, :cpu => 2 },
{ :hostname => 'www2', :ip => '192.168.56.22', :mem => 1024, :cpu => 2 },
]
Vagrant.configure("2") do |config|
hosts.each do |host|
config.vm.define host[:hostname] do |hostconfig|
hostconfig.vm.box = "ubuntu/bionic64"
hostconfig.vm.hostname = host[:hostname]
hostconfig.vm.network :private_network, ip: host[:ip]
hostconfig.vm.provider :virtualbox do |vbox|
vbox.gui = false
vbox.linked_clone = true
vbox.memory = host[:mem]
vbox.cpus = host[:cpu]
end
end
end
end
Pour tester notre application depuis l’hôte, nous lui ajoutons une redirection de port, ainsi nous pourrons accéder au serveur apache de notre VM directement depuis http://localhost:8080.
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/bionic64"
config.vm.hostname = "vagrantbox"
config.vm.network "forwarded_port", guest: 80, host: 8080
config.vm.provider :virtualbox do |vbox|
vbox.gui = false
vbox.linked_clone = true
vbox.memory = 1024
vbox.cpus = 1
end
config.vm.provision "shell", inline: <<-SHELL
apt-get update
apt-get -y dist-upgrade
apt-get -y install screen htop nmap apache2
SHELL
end
Jusqu’ici, notre post-install était basée sur le shell ce qui a ses limites et ce n’est plus vraiment dans l’approche devops actuelle. Utilisons à la place Ansible.
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/bionic64"
config.vm.hostname = "vagrantbox"
config.vm.network "private_network", ip: "192.168.56.10", virtualbox__intnet: "nat"
config.vm.provider :virtualbox do |vbox|
vbox.gui = false
vbox.linked_clone = true
vbox.memory = 1024
vbox.cpus = 1
end
config.vm.provision "ansible" do |ansible|
ansible.playbook = "playbook.yml"
ansible.compatibility_mode = "2.0"
#ansible.inventory_path = "inventory"
end
end
Et voici le fichier playbook.yml à placer dans le même répertoire que le fichier Vagrantfile.
---
- hosts: all
become: true
gather_facts: false
pre_tasks:
- name: Install python2 for Ansible
raw: bash -c "test -e /usr/bin/python || (apt -y update && apt install -y python-minimal)"
tasks:
- name: apt upgrade
apt:
upgrade: dist
update_cache: yes
autoclean: yes
autoremove: yes
- name: install apache
apt:
name=apache2
state=present
- name: Enable service Apache2
service:
name: apache2
state: started
enabled: yes
Si vous préférez Puppet, pas de problème, plusieurs provisionner sont supportés.
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/bionic64"
config.vm.hostname = "vagrantbox"
config.vm.network "private_network", ip: "192.168.56.10", virtualbox__intnet: "nat"
config.vm.provider :virtualbox do |vbox|
vbox.gui = false
vbox.linked_clone = true
vbox.memory = 1024
vbox.cpus = 1
end
config.vm.provision "shell", inline: <<-SHELL
apt-get update
apt-get -y install puppet
SHELL
config.vm.provision "puppet" do |puppet|
puppet.manifests_path = "manifests"
end
end
Et le manifest puppet qui va avec dans le dossier manifests/default.pp.
node default {
exec { 'apt_up':
command => 'apt update && apt -y dist-upgrade && apt -y --purge autoremove && touch /root/.firstboot_updates',
path => '/usr/bin:/usr/sbin:/bin:/sbin',
provider => shell,
unless => ['test -f /root/.firstboot_updates'],
}
Package { 'apache2':
ensure => 'present',
}
Service { 'apache2':
ensure => 'running',
enable => 'true',
}
}
Voici pour cette introduction à Vagrant, j’espère que ces quelques exemples vous auront permis appréhender le confort que cet outil fourni.

Super article, ça donne envi d’essayer ..
D’ailleurs je vais essayer.
ಠಿ_ಠ Et pour l’ajout d’un certificat SSL sur la machine déployée afin d’avoir une machine de dev. en SSL ??
Oui, plus on en a plus on en demande .. j’accepte un RTFM !!
RTFM !