Table des matières
2022/09/19 (atelier) : Ansible
Météo
Moment informel durant lequel on exprime en peu de mots comment on se sent et si on a une attente forte pour la réunion. Ce n'est pas un moment de discussion mais d'expression individuelle et ce n'est pas obligatoire
Attente(s) forte(s)
Si l'une ou l'autre personne exprime une attente forte, merci de vous en occuper en priorité ou de la noter dans le hub ou dans un point approprié.
- Pouvoir utiliser Ansible et contribuer aux playbooks de l'infra
Configuration de l'espace de travail
Vagrant
Vagrant est une boite à outils pour piloter un hyperviseur local. La différence avec VirtualBox, c'est qu'on peut dire à Vagrant de créer une VM avec tant de CPU, de RAM… tout cela au travers d'un fichier.
Dans le fichier, on a différents paramètres :
Par exemple, la config minimale est la suivante :
- snippet.vagrant
Vagrant.configure("2") do |config| config.vm.box = "debian/bullseye64" end
config.vm.box → indique ce qu'on va utiliser comme OS
Il y a des OS officiel mais aussi des OS qui sont faits par des gens. On peut en voir différents ici :
https://vagrantcloud.com/search
L'image est déployée pour certains providers comme libvirt ou virtualbox.
Grace à vagrant, on va dire sur quelle base on démarre et s'y connecter. Vagrant peut aussi exécuter un playbook ansible.
→ on appelle ça du provisionning.
libvirt vs virtualbox
L'intérêt de vagrant par rapport à Docker : il fait une VM avec un OS complet. Docker ne fait que des conteneurs.
Installation de vagrant
On installe vagrant via le package manager, par ex pour manjaro:
pacman -Syu vagrant
On va vouloir tester libvirt, donc on l'installe aussi:
pacman -Syu libvirt
Ensuite on installe le plugin libvirt pour vagrant:
vagrant plugin install vagrant-libvirt
Initialisation
On va générer un Vagrantfile pour pouvoir un peu comprendre comment fonctionne vagrant.
Pour cela, on crée un dossier vide sur notre ordinateur et on se place dedans:
mkdir vagrant-test cd vagrant-test
Ensuite, on génère le Vagrantfile
avec:
vagrant init debian/bullseye64
Avec un ls, on peut voir que le Vagrantfile a été créé.
Par défaut, la seule configuration active est celle qui indique l'OS utilisé :
- snippet.vagrant
config.vm.box = "debian/bullseye64"
On active le port-fowarding ssh. Cela permet de se connecter depuis localhost à la VM. C'est ce que fait Molecule par défaut, mais on le fait ici manuellement.
On donne aussi une quantité pour la RAM
- snippet.vagrant
config.vm.provider "libvirt" do |libvirt| # Enable forwarding of forwarded_port with id 'ssh'. libvirt.forward_ssh_port = true # Customize the amount of memory on the VM: libvirt.memory = "1024" end
Il y a moyen de configurer le nombre de CPU, etc. mais on ne va pas voir cela en détail, donc cf. la doc https://www.vagrantup.com/docs/vagrantfile
Pour démarrer la machine :
- snippet.sh
vagrant up --provider=libvirt
Ici, on spécifie le provider. Il y a une variable d'environnement qui permet de dire quel est le provider par défaut, ce qui évite de devoir le spécifier par la suite:
- snippet.sh
VAGRANT_DEFAULT_PROVIDER=libvirt
Si libvirt n'est pas démarré, il faut le démarrer :
systemctl start libvirtd systemctl status libvirtd
Pour éviter de devoir taper son mot de passe admin, on peut ajouter son utilisateur au groupe libvirt :
sudo usermod -aG libvirt celo
Libvirt a besoin d'un hyperviseur. Il faut installer QEMU :
sudo pacman -S qemu-full virt-manager
Il y a un outil qui permet d'accélérer la virtualisation sur sa machine, c'est KVM. Mais on en reparlera.
Par défaut, Vagrant fait un partage NFS, un stockage externe de la VM sur le host et partagée avec le host. C'est utile pour les devs mais on n'a pas besoin de ça donc on peut changer son comportement (on pourrait le désactiver, à voir comment faire) :
- snippet.vagrant
config.vm.synced_folder "./", "/vagrant", type: "rsync"
Pour le désactiver, il faut mettre:
- snippet.vagrant
config.vm.synced_folder "./", "/vagrant", disabled: true
En le mettant en rsync, ce sera unidirectionnel, on peut juste déposer des fichiers sur la machine. Mais ça évite d'avoir un serveur NFS qui tourne et de devoir taper son mot de passe.
On va recommencer avec cette nouvelle configuration. Pour détruire la machine, on utilise :
vagrant destroy
Et on crée à nouveau la VM:
vagrant up --provider=libvirt
Et là on voit bien qu'il ne configure plus le serveur NFS, donc c'est chouette:
==> default: Installing rsync to the VM... ==> default: Rsyncing folder: /home/hadrien/Projets/vagrant/ => /vagrant
On peut se connecter à Vagrant en SSH avec :
vagrant ssh
On est connecté en tant qu'utilisateur vagrant
et on peut faire un sudo -i
sans avoir besoin de mot de passe.
Commandes vagrant
En résumé, on a pas besoin d'en connaître beaucoup pour utiliser Vagrant :
vagrant up --provider=libvirt vagrant ssh vagrant destroy
Pour connaître les images qui ont été téléchargées et les mettre à jour :
vagrant box list vagrant box update
Ou pour installer les plugin :
vagrant plugin install <nom du plugin>
Ou encore démarrer un nouveau projet:
vagrant init <nom de la box>
A chaque fois, on a un dossier avec un Vagrantfile par VM.
Fonctionnalités avancées SSH
Depuis le dossier de la machine, si on va dans le dossier :
$ ls .vagrant/machines/default/libvirt/ action_provision created_networks id logs private_key vagrant_cwd box_meta creator_uid index_uuid pids synced_folde
On trouve la clé SSH privée de la machine.
On peut s'y connecter avec directement en SSH en bypassant le fonctionnement de vagrant :
ssh -i .vagrant/machines/default/libvirt/private_key vagrant@192.168.121.141
Ansible
Installation d'Ansible
Soit on installe Ansible dans le package manager, mais alors on a la même version pour tous les projets (qui n'est pas forcément à jour). Le mieux est de l'installer via un Virtualenv de python.
Entre deux virtualenv différents, on peut avoir des paquets qui n'ont pas la même version. Ca assure une compatibilité entre les différents projets auxquels on contribue.
Dans le projet Neutrinet, on a un requirements.txt de tous les paquets nécessaires.
Dans un nouveau dossier Ansible-Test, on va créer un virtualenv.
Pour créer le virtualenv, il suffit de lancer la commande suivante:
python3 -m venv <dossier>
En général, le nom du dossier va être .env
, .venv
, env
, venv
ou encore ve
.
On peut aussi le faire dans le même dossier, mais en général on essaie de se mettre d'accord sur une norme commune. → car dans le fichier .gitignore, on ignore les .venv etc., pour indiquer qu'on ne prend pas ce fichier, mais on ne veut pas 2000 noms
Ensuite, on active le virtualenv avec
source .venv/bin/activate
Ou (cela revient au même):
. .venv/bin/activate
On peut voir qu'on utilise bien le virtualenv : il y a un préfixe avec le nom du virtualenv devant le prompt du terminal.
On peut aussi vérifier la version de pip:
pip --version
Tout ce qu'on installe via pip dans le virtual environnement va s'installer dans le dossier .venv et ne sera pas utilisé ailleurs dans le système.
On peut voir, depuis l'environnement virtuel, d'où sont exécutés les logiciels :
echo $PATH ~/Ateliers-Ansible/Ansible-Test/.venv/bin:~/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl:/var/lib/snapd/snap/bin
Si on une version d'Ansible déjà installée via le package manager, ce n'est pas celle qui sera utilisée lorsqu'on utilise Ansible dans l'environnement virtuel. En revanche, il faut faire attention à certains composants qu'on pourrait ne pas avoir installé dans l'environnement virtuel… le linter (ansible-lint, composant qui vérifie la syntaxe), ou encore molecule, par exemple…
On peut enfin installer Ansible !
pip install ansible
On vérifie que tout est bien installé:
ansible --version
Cette commande permet aussi de vérifier qu'Ansible fonctionne, et montre où sont stockés les différents modules (on peut on créer des custom notamment, même si on n'en a pas créé pour Neutrinet pour l'instant).
Utilisation d'Ansible avec Vagrant
On relance une machine vagrant :
vagrant up --provider=libvirt
On va se baser sur le cours suivant : https://supports.uptime-formation.fr/06-ansible/tp1/
Pour vérifier le fonctionnement, on peut faire une commande pour pinguer toutes les VM actives :
ansible all -m ping
A ce stade, ansible ne trouve pas de VM car l'inventaire n'est pas complété. Par défaut, ansible cherche l'inventaire dans /etc/ansible/hosts mais ne trouve rien.
On peut ajouter l'option -vvv à la commande pour voir plus de déuggage.
On constate en revanche que ansible localhost -m ping
fonctionne.
On va créer un inventaire. Il y a deux formats, yaml et ini. Yaml est plus verbeux. Pour l'inventaire, ini suffit.
Dans un fichier ini, on formule les choses avec des équivalences : clé = valeurs. Et on a des sections entre crochets. Dans le cadre d'un inventaire de machine, les sections sont des groupes de machines, et chaque ligne est un host.
Dans un inventaire, on peut définir des variables propres à la machine ou à un groupe d'hôtes. Ce n'est pas une bonne pratique, parce qu'on utilise plutôt des dossiers en parallèle, ce qui permet de découpler la liste des hosts des variables qui leurs sont associées.
On crée donc le fichier hosts.ini avec :
machine1 ansible_host=192.168.121.217
Maintenant, on peut tester la connexion (il fait plus qu'un ping) avec la VM. Il faut spécifier dans la commande, le fichier d'inventaire que l'on vient de créer :
ansible -m ping all -i hosts.ini
Mais ansible doit connaître les infos de connexions (clé privée et login). Ca nous donne donc au final :
ansible all -m ping -i hosts.ini -u vagrant --private-key ~/Documents/Ateliers-Ansible/Vagrant-test/.vagrant/machines/default/libvirt/private_key
Ca marche… mais c'est long (et on est fainéants). On peut raccourcir en ajoutant la private key au ssh agent.
On vérifie que le ssh-agent tourne:
ssh-add -l
S'il ne tourne pas, on le lance:
eval $(ssh-agent)
Et on ajoute la clé privée de la machine:
ssh-add ~/Documents/Ateliers-Ansible/Vagrant-test/.vagrant/machines/default/libvirt/private_key
On peut retester la connexion sans le paramètre --private-key
ansible all -m ping -i hosts.ini -u vagrant
Pour le user, il y a trois solutions, soit on prod, on a configuré son fichier de config ssh. L'autre solution est le -u. Une troisième solution est de rajouter une variable :
Il y a une préséance des variables: https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#understanding-variable-precedence La doc n'est pas toujours clair, mais on apprend progressivement par essais-erreur en s'arrachant les cheveux
On modifie le fichier hosts.ini pour ajouter une variable pour le user :
machine1 ansible_host=192.168.121.217 ansible_ssh_user=vagrant
Les variables qui commencent par ansible sont des variables d'ansible. Ansible appelle ça des facts car c'est tout ce qui touche à l'environnement ansible. Ca permet de voir toutes les variables qui définissent la machine.
ansible -m gather_facts all -i hosts.ini
On peut définir un inventaire par défaut pour ansible. Pour cela, on doit créer un fichier de config pour Ansible. Par défaut, Ansible va regarder s'il y a un fichier ansible.cfg
qui existe dans le répertoire en cours. On crée ce fichier avec:
[defaults] inventory = hosts.ini
On peut tester sans préciser l'inventaire:
ansible -m ping all
Maintenant, on va créer une deuxième machine avec vagrant. On fait un vagrant destroy
puis on rajoute ceci dans le Vagrantfile:
config.vm.define :ubuntu1 do |ubuntu1| ubuntu1.vm.box = "generic/ubuntu2204" ubuntu1.vm.hostname = "ubuntu1" end config.vm.define :debian1 do |debian1| debian1.vm.box = "debian/bullseye64" debian1.vm.hostname = "debian1" end
On enleve aussi la partie de config config.vm.box = "debian/bullseye64"
.
Dans le fichier inventaire, on va créer deux groupes, un groupe Ubuntu et un autre Debian :
[debian] debian1 ansible_host=192.168.121.26 [ubuntu] ubuntu1 ansible_host=192.168.121.103
Une fois les machines installées (le téléchargement de l'image ubuntu prend du temps…), on peut s'y connecter en SSH. Il faut préciser le nom de la machine à laquelle on veut se connecter :
vagrant ssh debian1 vagrant ssh ubuntu1
Pour utiliser ansible, on rajoute les clés privées des deux machines avec ssh-add, comme fait précédemment, et on fait un test de connexion:
ssh-add ~/Documents/Ateliers-Ansible/Vagrant-test/.vagrant/machines/debian1/libvirt/private_key ssh-add ~/Documents/Ateliers-Ansible/Vagrant-test/.vagrant/machines/ubuntu1/libvirt/private_key ansible -m ping all -u vagrant
On peut pinger les machines individuellement mais aussi en mentionnant le goupe :
ansible -m ping debian -u vagrant ansible -m ping ubuntu -u vagrant
Ici, nos groupes ne sont pas très intéressant, mais en prod ça peut-être intéressant, avec par exemple un groupe postgresql…
On va créer un groupe “labo”, en rajoutant ceci dans l'inventaire:
[labo] debian1 ubuntu1
On n'a pas besoin de remettre leurs IP car elles sont déjà déclarées.
Comme d'hab, on teste sur ce nouveau groupe:
ansible -m ping labo -u vagrant
On va aller plus loin en définissant une hiérarchie des groupes. À la place de ce qu'on venait de rajouter, on met:
[labo:children] debian ubuntu
Ici, on dit que les “enfants” du groupe labo sont les groupes debian et ubuntu (qui pourraient contenir plusieurs machines). On ne spécifie plus les machines elles-mêmes.
On voit qu'on peut commencer à hiérarchiser. Chez Neutrinet, on a par exemple les machines de LouiseDC, les enfants sont les machines baremetal, le réseau et le cluster patata.
Certains vont tirer les machines par datacenter, mettre les proxmox ensembles…
Mettre les variables dans l'inventaire n'est pas une très bonne pratique.
On va créer un dossier d'inventaire qui contiendra notre fichier d'inventaire et toutes les variables pour chaque host:
mkdir inventories mv hosts.ini inventories/hosts.ini mkdir inventories/group_vars inventories/host_vars
On modifie le fichier de config ansible.cfg
pour avoir:
inventory = inventories/hosts.ini
Ansible fonctionne avec une structure prédéfinie.
L'intérêt de faire un dossier inventories est de séparer les variables de l'inventaire des variables des playbook (qui seront dans un dossier séparé après). Cela permet aussi d'avoir une vue claire d'où se trouvent le ou les inventaires, et les playbooks, etc.
Ansible va aller regarder s'il y a des variables définies dans le dossier host_vars
qui se trouve au même niveau que le fichier d'inventaire hosts.ini. S'il ne trouve pas une variable, il va aller chercher dans le dossier group_vars
, etc. Cela nous ramène à la notion de préséance des variables.
Cela permet d'avoir une structure. Molécule va aussi utiliser une structure.
On va créer deux fichiers inventories/host_vars/debian1.yml
et inventories/host_vars/ubuntu1.yml
avec:
ansible_host: <ip>
Et on enlève la variable ansible_host
du hosts.ini pour ces deux machines.
On peut à présent tester la connexion:
ansible -m ping all -u vagrant
Attention de bien lancer la commande depuis la racine du projet (là où se trouve le fichier ansible.cfg
).
On crée enfin un fichier inventories/group_vars/all.yml
dans lequel on va mettre:
ansible_ssh_user: vagrant
Quand on teste la connexion, on ne doit plus mettre le nom d'utilisateur:
ansible -m ping all
On est parvenu à séparer les variables ansible de l'inventaire des hosts, ce qui permet d'avoir une vue clair sur la liste des machines et aussi sur la liste des variables pour telle machine ou groupe de machines.
TODO: création d'un playbook de test pour les VMs
Molecule
pip + virtualenv
plugin molecule-vagrant
Labo
Création d'une VM via molecule
Playbook vs rôle
Keycloak
Prochaine réunion
Prochain atelier Ansible : 24/09 à 14h
Lieu : Chez Célo (métro Crainhem)
Météo de fin
Moment informel durant lequel on exprime en peu de mots comment, à titre personnel, la réunion a été vécue que ce soit positif ou négatif. Si une ou plusieurs tension est née durant la réunion, il est peut-être nécessaire d'envisager l'une ou l'autre réunion pour y remédier.