Vagrant

Posted by

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.

3 comments

  1. 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 !!

Leave a Reply

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *