# 2022/09/19 (atelier) : Ansible * [[https://doc.neutrinet.be/atelier-ansible-2022-09-19#|Pad de la réunion]] Présences : - Célo - HgO ## 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 : ```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é : ```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 ```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 : ```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: ```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) : ```vagrant config.vm.synced_folder "./", "/vagrant", type: "rsync" ``` Pour le désactiver, il faut mettre: ```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 ``` Ou encore démarrer un nouveau projet: ``` vagrant init ``` 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 ``` 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: ``` 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.// {{tag>administration infra communication cube}}