Vagrant
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.