+ Erreur + 404 +
+La page que vous recherchez n'existe pas ou a été supprimée.
+Que voulez-vous faire ?
+ +diff --git a/pr/131/.well-known/mta-sts.txt b/pr/131/.well-known/mta-sts.txt new file mode 100644 index 00000000..740174fd --- /dev/null +++ b/pr/131/.well-known/mta-sts.txt @@ -0,0 +1,6 @@ + +version: STSv1 +mode: enforce +mx: mail.protonmail.ch +mx: mailsec.protonmail.ch +max_age: 1209600 \ No newline at end of file diff --git a/pr/131/.well-known/security.txt b/pr/131/.well-known/security.txt new file mode 100644 index 00000000..6a418ea6 --- /dev/null +++ b/pr/131/.well-known/security.txt @@ -0,0 +1,3 @@ +Contact: security@rix.fr +Expires: Wed, 1 Jan 2030 00:00 +0200 +Encryption: https://keys.openpgp.org/vks/v1/by-fingerprint/67B08D2BE9C8ACC2C40D28F1F69D39C94B03BD79 diff --git a/pr/131/404.html b/pr/131/404.html new file mode 100644 index 00000000..d1d824c7 --- /dev/null +++ b/pr/131/404.html @@ -0,0 +1,270 @@ + + +
+ + + +La page que vous recherchez n'existe pas ou a été supprimée.
+Que voulez-vous faire ?
+ +Parce que nous avons évolué au plus près des équipes de développement, nous savons qu'il est essentiel de bien comprendre le métier et d'assimiler ses contraintes.
+Parce que nous sommes issus de l’exploitation nous avons la prétention d’avoir une bonne vision des problématiques de mise en oeuvre d’une application web moderne. Et bien évidemment de son maintien en conditions opérationnelles.
+Spécialistes de l’hébergement des applications PHP/ Symfony métier sur-mesure nous avons au cours de notre expérience été confrontés à beaucoup des situations que vous rencontrez peut-être aujourd’hui.
+«Profile, don't assume !»+
Nous sommes soudés et fiers de l'être depuis de nombreuses années.
+Utilisation de la recipe Lazy Ansible du projet Manala pour mettre en oeuvre un environnement de travail dédié Ansible.
+Les environnements dits « lazy » issus du projet Manala sont des outils destinés à mettre en oeuvre de manière rapide des environnements de travail.
+Leur finalité étant multiple:
+Dans le cadre de travaux autour d'Ansible ou si vous suivez la partie « cours » nous utiliserons la « recipe » qui lui est dédiée (https://github.com/manala/manala-recipes/tree/master/lazy.ansible), son utilisation nécessite l'installation de Manala.
+La mise en place d'un nouvel environnement en utilisant Manala est relativement simple, il nous suffit de l'initialiser dans un répertoire dédié (cela peut-être un projet existant) à l'aide de la commande manala init
.
Démonstration ci-dessous:
+ +Nous disposons ainsi d'un environnement Ansible « conteneurisé » utilisable en quelques secondes sans n'avoir rien à installer sur nos postes (à l'exception de docker bien évidemment). +Et pour ceux et celles qui doivent faire avec plusieurs versions d'Ansible dans leur quotidien, cela permet d'avoir des environnements isolés et dédiés à certaines versions de l'outils.
+Il est bien évidemment possible à partir des fichiers de configuration Manala, d'agir sur les configurations d'ansible mais également la configuration SSH.
+Pour cela il faudra modifier le fichier .manala.yaml
qui doit, après la manipulation précédente, se trouver à la racine de votre répertoire de travail.
Prendre en compte vos modifications
+
+ Si vous modifiez les fichiers de configuration comme indiqué ci-dessous il faudra penser à utiliser la commande manala up
afin que vos modifications soient bien prises en compte.
+
Il est possible d'interagir sur la configuration Ansible à partir de la section suivante:
+system:
+ ansible:
+ version: 2.15.5
+ config: |
+ [defaults]
+ control_path_dir = /tmp/ansible/cp
+ [privilege_escalation]
+ become = True
+ become_flags = -H -S
+ [ssh_connection]
+ control_path = /tmp/%%h-%%r
+On notera qu'il est possible d'agir sur la version d'ansible utilisée dans notre conteneur Docker mais également sur les directives de configuration propres à Ansible (https://docs.ansible.com/ansible/latest/reference_appendices/config.html).
+Le fichier ansible.cfg
+
+ Les modifications de configuration comme ci-dessus se traduisent par l'ajout de directives dans le fichier /etc/ansible/ansible.cfg
. Il est possible de surcharger ce fichier en placant un fichier du même nom à la racine des répertoires de travail de vos projets permettant ainsi l'introduction de directives spécifiques à chacun d'entre eux.
+
Concernant SSH le fonctionnement est le même, on retrouve une section dédiée au sein du fichier .manala.yaml
qui nous permettra de jouer sur les directives de configuration SSH:
ssh:
+ config: |
+ Host *
+ User debian
+ ForwardAgent yes
+Et vous voilà en quelques lignes en capacité d'utiliser un environnement Ansible.
+Toujours dans le même fichier, la section cette fois-ci sera la suivante:
+git:
+ config: |
+ # Silence false positive dubious ownership errors
+ #[safe]
+ #directory = *
+Vous voilà prêt à attaquer Ansible ;)
+Première étape vers l'utilisation d'Ansible, les inventaires. Ils sont le point d'entrée vers vos infras et sont donc central au pilotage de vos instances / serveurs.
+Ce cours est utilisé dans le cadre de TP au sein de l'IUT Lyon 1. Il est notamment dispensé à des étudiants peu ou pas familiers avec les stratégies d'automatisation et de déploiement des infrastructures. +Bien que très axé débutants il peut également représenté une possibilité de monter « rapidement » pour certaines équipes sur les principes fondamentaux d'Ansible afin de disposer du bagage minimal nécessaire à son utilisation.
+Il s'agit bien évidemment de supports à vocation pédagogique qui ne sont pas toujours transposables à une activité professionnelle.
+Disposer d'un environnement de travail Ansible fonctionnel, si ça n'est pas encore le cas vous pouvez jeter un oeil ici !
+Afin de pouvoir attaquer nos différentes machines, Ansible a besoin d'un référentiel de celles-ci avec un minimum d'informations les concernants (histoire de savoir comment s'y connecter par exemple ;)).
+C'est là qu'entre en jeu les inventaires. Il existe deux façons de constituer des inventaires, la première est manuelle, et consiste à écrire ni plus ni moins la liste des machines que l'on souhaites manager on parle dans ce cas d'inventaire statique.
+La deuxième méthode introduit un principe de « reconnaissance » des machines disponibles, dans ce cas de figure on constituera nos inventaires de manière automatique, on parle dans ce cas d'inventaires dynamiques que nous verrons plus tard.
+Les inventaires permettent également de structurer / hiérarchiser nos machines en utilisant une notion de groupe. +Ansible propose plusieurs plugins capablent de gérer des inventaires de machines, ils sont consultables à l'aide de la commande:
+ansible-doc -t inventory -l
+Qui devrait vous renvoyer la liste suivante:
+02:48:02 lazy@ansible_env lazy → ansible-doc -t inventory -l
+ansible.builtin.advanced_host_list Parses a 'host list' with ranges
+ansible.builtin.auto Loads and executes an inventory plugin specified in a YAML config
+ansible.builtin.constructed Uses Jinja2 to construct vars and groups based on existing inventory
+ansible.builtin.generator Uses Jinja2 to construct hosts and groups from patterns
+ansible.builtin.host_list Parses a 'host list' string
+ansible.builtin.ini Uses an Ansible INI file as inventory source
+ansible.builtin.script Executes an inventory script that returns JSON
+ansible.builtin.toml Uses a specific TOML file as an inventory source
+ansible.builtin.yaml Uses a specific YAML file as an inventory source
+Dans notre cas nous nous appuyerons essentiellement sur le plugin yaml
.
Un inventaire n'est en fait ni plus ni moins qu'un ou plusieurs fichiers contenant des informations concernant le parc de machines que l'on souhaite piloter.
+En terme de structure vous rencontrerez énormément de façons de faire, celles-ci étant bien évidemment guider par le besoin métier, on pourra citer comme contraintes par exemple:
+Bref tout est imaginable à ce niveau. +En ce qui nous concerne nous interviendrons sur un parc plutôt modeste puisque pour nos travaux nous utiliserons au maximum 4 machines.
+Nous allons donc commencer par créer un répertoire qui leur sera dédié appelé inventories
nous déplacerons ensuite le fichier hosts.yml
que nous avions créé précédemment.
Vous devriez donc disposer d'une arborence similaire à la suivante:
+ansible/
+├── inventories
+│ └── hosts.yml
+└── Makefile
+Pour rappel le contenu de votre fichier hosts.yml
doit pour l'heure être le suivant:
all:
+ hosts:
+ vm-web-prod-01:
+ ansible_host: XXX.XXX.XXX.XXX
+ ansible_user: debian
+La structure du fichier nous permet de mettre en évidence deux clés essentielles:
+ansible_host
: Le nom résolvable ou l'adresse IP de la machine distante;ansible_user
: L'utilisateur à utiliser pour ouvrir une session sur cette même machine.Il est toutefois possible d'utiliser d'autres clés de configuration pour enrichir la définition de notre machine comme:
+ansible_port
: Permet de spécifier le port de connexion SSH (si différent du port standard, pour rappel le port par défaut est 22)ansible_ssh_pass
: Le mot de passe du compte SSH utilisé (on lui préferera une authentification par clés);ansible_ssh_private_key_file
: Le chemin vers la clé à utiliser pour se connecter au compte SSH;ansible_ssh_extra_args
: Permet d'ajouter des options supplémentaires à la ligne de commande SSH utilisée par Ansible.ansible_become
: Permet de forcer l'escalade de privilèges;ansible_become_method
: Permet de spécifier la méthode d'escalade des privilèges;ansible_become_user
: Permet de spécifier l'utilisateur cible de l'escalade de privilèges;ansible_become_pass
: Permet de spécifier le mot de passe de l'utilisateur cible de l'escalade de privilèges (encore une fois, on préfera la méthode par clés SSH).À présent que nous avons effectuer un petit tour rapide du propriétaire, nous allons « étoffer » notre inventaire initial en ajoutant une deuxième machine comme ci-dessous:
+# Fichier hosts.yml
+all:
+ hosts:
+ vm-web-prod-01:
+ ansible_host: XXX.XXX.XXX.XXX
+ ansible_user: debian
+ vm-web-staging-01:
+ ansible_host: XXX.XXX.XXX.XXX
+ ansible_user: debian
+En ajoutant une machine et en jouant la commande ansible -i inventories/hosts.yml all -m ping
nous devrions voir qu'ansible considère bien nos deux machines:
Hôte local
++ Il est bien évidemment possible d'interroger notre propre machine à l'aide d'Ansible, en modifiant relativement simplement notre fichier d'inventaire. Attention toutefois à ce que vous faites puisque vous pouvez directement impacter la configuration et donc le fonctionnement de votre machine. +
+Exemple de fichier d'inventaire pour piloter une machine locale:
+all:
+ hosts:
+ localhost:
+ ansible_host: 127.0.0.1
+ ansible_connection: local
+Pour l'exemple nous allons créer un fichier groups.yml
(toujours dans inventories
) contenant:
all:
+ children:
+ webservers:
+ hosts:
+ vm-web-prod-01: ~
+ vm-web-staging-01: ~
+ATTENTION: children
est une sous clé de all
;)
Ansible propose différentes commandes parfois très spécifiques, l'occasion de tester notre configuration d'inventaire !
+Testons: ansible-inventory --list -i inventories
On notera que cette fois-ci nous donnons le répertoire inventories
en paramètre.
Cette commande devrait vous afficher la sortie suivante (format json):
+{
+ "_meta": {
+ "hostvars": {
+ "vm-web-prod-01": {
+ "ansible_host": "192.168.140.XXX",
+ "ansible_user": "debian"
+ },
+ "vm-web-staging-01": {
+ "ansible_host": "192.168.140.XXX",
+ "ansible_user": "debian"
+ }
+ }
+ },
+ "all": {
+ "children": [
+ "ungrouped",
+ "webservers"
+ ]
+ },
+ "webservers": {
+ "hosts": [
+ "vm-web-prod-01",
+ "vm-web-staging-01"
+ ]
+ }
+}
+ou encore avec l'option --graph
en lieu et place de --list
qui est plus parlante visuellement ansible-inventory --graph -i inventories
:
@all:
+ |--@ungrouped:
+ |--@webservers:
+ | |--vm-web-prod-01
+ | |--vm-web-staging-01
+À retenir: +Ansible utilise une arborescence ou figurera toujours:
+all
: C'est le groupe racine auquel appartiendra toutes vos machines sans exception (On remarquera avec cette information que lorsque nous avons utilisé la commande ansible -i inventories/hosts.yml all -m ping
, all indiquait donc le groupe cible).ungrouped
: Groupe auquel sera affectée toute machine n'appartenant à aucun groupe (exception faites de all bien évidemment);Dans notre exemple ci-dessus on voit donc bien que nos deux machines font bien partie du groupe webservers
.
Fichiers d'inventaire multiples
+
+ Si l'option -i
d'Ansible prend un fichier d'inventaire en paramètre elle peut également prendre un répertoire et dans ce cas Ansible considérera l'ensemble des fichiers présents dans le répertoire.
+ Ce fonctionnement offre la possibilité avec des infrastructures composées de nombreuses machines de pouvoir les séparer dans plusieurs fichiers en fonction de différents critères.
+
Vous aurez compris que si l'on aborde le sujet c'est qu'il est d'importance... pour l'illustrer créons un nouveau fichier d'inventaire que l'on nommera misc.yml
contenant:
all:
+ hosts:
+ vm-web-prod-01:
+ ansible_host: XXX.XXX.XXX.XXX
+ ansible_user: debian
+ ansible_port: 22
+ vm-web-staging-01:
+ ansible_host: XXX.XXX.XXX.YYY
+Une fois ces modifications faites, rejouez la commande ansible-inventory --list -i inventories
vous devriez constater de subtils changements au niveau des informations que vous affiche Ansible.
{
+ "_meta": {
+ "hostvars": {
+ "vm-web-prod-01": {
+ "ansible_host": "192.168.140.12",
+ "ansible_port": 22,
+ "ansible_user": "debian"
+ },
+ "vm-web-staging-01": {
+ "ansible_host": "192.168.140.10",
+ "ansible_user": "debian"
+ }
+ }
+ },
+ "all": {
+ "children": [
+ "ungrouped",
+ "webservers"
+ ]
+ },
+ "webservers": {
+ "hosts": [
+ "vm-web-prod-01",
+ "vm-web-staging-01"
+ ]
+ }
+}
+On constatera ainsi:
+ansible_port
sur notre première instance;Qu'en retenir ?
+L'utilisation du Yaml comme langage de définition introduit une notion d'arborescence au niveau de vos clés, il faut ainsi voir la définition de votre machine comme un tableau multidimensionnel indexé.
+array (
+ 'vm-web-prod-01' =>
+ array (
+ 'ansible_host' => '192.168.140.12',
+ 'ansible_port' => 22,
+ 'ansible_user' => 'debian',
+ ),
+)
+On comprendra donc facilement:
+ansible_port
);Conclusion: Lorsque l'on utilise des fichiers d'inventaire multiples il vaut bien prendre en compte leur ordonnancement, la dernière valeur déclarée pour une clé étant celle qui sera retenu dans notre tableau final.
+Groupes de groupes
++ La hiérarchie de groupe d'un inventaire peut avoir plusieurs niveaux. Il est donc possible d'avoir de l'imbrication de groupes. Attention toutefois à ne pas en abuser afin de ne vous perdre dans des arborescence trop complexes. +
+Complétons pour finir notre inventaire groups.yml
afin d'obtenir le contenu suivant:
all:
+ children:
+ webservers:
+ hosts:
+ vm-web-prod-01: ~
+ vm-web-staging-01: ~
+ staging:
+ hosts:
+ vm-web-staging-01: ~
+ production:
+ hosts:
+ vm-web-prod-01: ~
+Rapide mise en pratique des inventaires.
+Reprendre les différents fichiers contenu dans notre répertoire inventories
et les compiler en un seul et même fichier hosts.yml
, les autres fichiers ne sont finalement plus utiles et peuvent être supprimés.
Nous compléterons notre inventaire avec deux machines supplémentaires vm-db-prod-01
et vm-db-staging-01
appartenant toutes deux au groupe dbservers
(Attention à les affecter également à leurs groupes d'environnements respectifs).
Souvenez-vous vous pouvez tester un fichier d'inventaire en particulier en le passant en paramètre de la commande ansible-inventory
: ansible-inventory --list -i inventories/hosts.yml
.
Nous avons vu qu'il existait différent plugin permettant de « lire » un inventaire (si,si au tout début), essayez d'écrire le même inventaire mais à un format différent (format ini par exemple).
+Revenons à notre fichier hosts.yml
séparez son contenu en fonction des environnements que nous avons définis (staging et production)
Notre infrastructure est modeste, mais vous serez parfois amenés à travailler avec des infrastructures d'envergure et serez dans l'obligation de « cibler » certaines machines ou groupes de machines. +Il est ainsi possible d'indiquer explicitement à Ansible quelles sont les machines à considérer pour une action donnée.
+Certains « patterns » sont très simple et vous devriez en reconnaitre certains:
+Le « wildcard » *
par exemple qui désignera n'importe quelle valeur et qui est utilisable au sein d'une valeur de clé ip
ou hostname
(192.168.140.*
ou encore *.example.com
).
Ceux que vous rencontrerez le plus souvent: :
, :&
ou encore :!
.
L'opérateur :
signifiera qu'une machine peut-être dans un groupe OU dans un autre, par exemple staging ou production.
Essayons toujours avec notre module ping: ansible -i inventories/hosts.yml 'staging:production' -m ping
Avec la commande ansible-inventory
+
+ ansible-inventory -i inventories/hosts.yml --host='webservers:production'
+
L'opérateur :&
signifiera qu'une machine peut-être dans un groupe ET dans un autre, par exemple webservers et production.
ansible -i inventories/hosts.yml 'webservers:&production' -m ping
Cette fois-ci vous ne devriez avoir que la machine vm-web-prod-01
qui est solicité par Ansible.
Avec la commande ansible-inventory
+
+ ansible-inventory -i inventories/hosts.yml --host='webservers:&production'
+
L'opérateur :!
permettra de cibler une machine qui est dans un groupe mais pas dans un autre par exemple membre du groupe webservers mais non présente dans le groupe production.
ansible -i inventories/hosts.yml 'webservers:!production' -m ping
Vous devriez ne soliciter cette fois que vm-web-staging-01
.
Avec la commande ansible-inventory
+
+ ansible-inventory -i inventories/hosts.yml --host='webservers:!production'
+
Il est bien évidemment possible de combiner les opérateurs prenez toutefois garde aux expressions trop complexes qui gêneront à la compréhension et pourront être source d'erreur !
+On peut donc imaginer des choses comme cibler les machines du groupe webservers OU staging mais qui ne sont pas dans production (On est d'accord, ça n'a aucune sens c'est pour l'exemple ;)).
+ansible -i inventories/hosts.yml 'webservers:staging:!production' -m ping
Il est également possible de mixer nom de groupe et nom de machine: ansible -i inventories/hosts.yml 'webservers:staging:!vm-web-staging-01' -m ping
Avec la commande ansible-inventory
+
+ ansible-inventory -i inventories/hosts.yml --host='webservers:staging:!vm-web-staging-01'
+
Nous aurons donc vu que les inventaires bien qu'à priori relativement simples, peuvent amener une forme de complexité sur des infrastructures volumineuses, leur organisation peut donc vite devenir stratégique notamment dans l'optique de faciliter la maintenance du parc piloté par Ansible.
+Dans la prochaine étape nous aborderons une nouvelle notion d'Ansible, les playbooks qui nous permettront d'écrire nos première tâches !
++ Une typo ? + Modifier cet article sur Github +
+Découverte des playbooks, élément essentiel d'Ansible qui va nous permettre d'organiser et structurer nos tâches !
+Ce cours est utilisé dans le cadre de TP au sein de l'IUT Lyon 1. Il est notamment dispensé à des étudiants peu ou pas familiers avec les stratégies d'automatisation et de déploiement des infrastructures. +Bien que très axé débutants il peut également représenté une possibilité de monter « rapidement » pour certaines équipes sur les principes fondamentaux d'Ansible afin de disposer du bagage minimal nécessaire à son utilisation.
+Il s'agit bien évidemment de supports à vocation pédagogique qui ne sont pas toujours transposables à une activité professionnelle.
+Disposer d'un environnement de travail Ansible fonctionnel, si ça n'est pas encore le cas vous pouvez jeter un oeil ici !
+Un playbook est un élément central pour Ansible puisque c'est dans ce fichier de configuration (écrit en YAML toujours), que l'on va organiser et indiquer quelles actions nous souhaitons déclencher.
+Les playbooks décrivent des « tâches » à exécuter sur des groupes de machines identifiés dans les inventaires, ils sont écrits à l'aide du format YAML.
+La syntaxe Yaml
++ Yaml est un langage ou plutôt un format, qui permet de sérialiser des données afin qu'elles restent lisiblent pour nous. Les données sont organisées sous la forme de paire clé/valeur dans des listes ordonnées, il est de plus en plus utilisé notamment pour les fichiers de configuration. +
+Afin de rentrer dans le vif du sujet nous allons écrire un playbook relativement simple utilisant un module que nous avons vu précédemment, le module ping. Nous avons vu que les modules Ansible peuvent être utilisés en ligne de commande pour exécuter une tâche ponctuelle mais rappelons que le but d'Ansible est en premier lieu, d'automatiser les choses et donc de les rendre réutilisables !
+Créons un nouveau fichier que nous appellerons example.yml
dans notre répertoire de travail (pour rappel de mon côté workspace/ansible
) contenant:
---
+- hosts: web
+
+ tasks:
+ - name: Check if host is alive # Description of the task
+ ansible.builtin.ping: ~
+La structure YAML permet une compréhension relativement aisée du contenu, on identifiera ainsi:
+hosts
permettant de définir les « hôtes », les machines concernées par les tâches qui vont suivre (identifiées par leur groupe d'appartenance);tasks
permettant de définir les différentes « tâches » ou actions que nous souhaitons déclencher sur nos machines.Un bloc ainsi défini est appelé un « play ».
+---
+
+ Vous l'aurez noté, les playbooks que nous rédigeons commencent tous avec trois tirets ---
, ceux-ci marquent en effet en syntaxe Yaml, le début du document, ils sont donc indispensables à l'interprétation du fichier.
+ Ils permettent entre autres d'utiliser des directives en entêtes de fichier ou de disposer de plusieurs flux yaml dans un même fichier (le début de chaque flux étant indiqué par ces trois tirets).
+
Rappelez-vous nous pouvons traduire les instructions suivantes sous forme de tableaux:
+array (
+ 'hosts' => 'web',
+ 'tasks' =>
+ array (
+ 0 =>
+ array (
+ 'name' => 'Check if host is alive',
+ 'ansible.builtin.ping' => NULL,
+ ),
+ ),
+ )
+On constate encore plus aisément sous cette forme que la clé tasks
permet de définir un nombre indéfini de « tâches » à exécuter, celles-ci ayant toujours au moins pour structure:
name
);ping
utilisé précédemment) chaque module acceptant ou non des paramètres.Les modules Ansible
++ Un module pour Ansible est un composant logiciel qui encapsule une tâche spécifique. + Pour résumer, il s'agit d'un bloc de code qui est exécuté par Ansible pour accomplir une action donnée sur un système cible. On trouve notamment des modules capables de gérer des fichiers, d'exécuter des commandes ou encore de gérer des services. + Ils peuvent être écrits dans divers langages de programmation, mais la plupart sont écrits en Python. Ansible vient avec une large gamme de modules intégrés pour gérer différents aspects des systèmes, des applications et des infrastructures. +
+Nous avons déjà vu les commandes ansible
et ansible-inventory
au tour de ansible-playbook
En exécutant cette commande ansible-playbook example.yml -i inventories
vous devriez obtenir la sortie suivante ou équivalente (si tout se passe bien).
Nous venons donc de faire appel au module ping mais à l'intérieur d'un playbook. Ce que nous avons en retour et une sortie type d'Ansible sur laquelle on peut remarquer quelques informations toujours intéressantes (tout en bas) avec notamment:
+ok
: Le nombre de tâches (tasks) qui se sont correctement exécutées;changed
: Le nombre de changements opérés sur nos machines cibles;unreachable
: Le nombre de machines injoignables (par soucis de réseau par exemple);failed
: Le nombre de tâches en erreur;skipped
: Le nombre de tâches qui ont été ignorées (par exemple si une tâches ne remplie pas certaines conditions prédéfinies).Il est bon de noté également qu'un playbook peut contenir plusieurs « plays » nous pouvons donc avoir des tâches attribuées à différents groupes cible comme ceci:
+---
+- hosts: webservers
+
+ tasks:
+ - name: Check if host is alive # Description of the task
+ ansible.builtin.ping:
+
+- hosts: dbservers
+
+ tasks:
+ - name: Get stats of a file
+ ansible.builtin.stat:
+ path: /etc/hosts
+
+Nous avons dans ce cas de figure deux groupes chacun concerné par une « tâche »:
+webservers
(contenant donc 2 machines) sur lequel nous exécutons le module ping;dbservers
(contenant également 2 machines) sur lequel nous exécutons le module stat
.Le module stat
+
+ Le module stat permet d'exécuter la commande système stat
sur un fichier du serveur cible. Il prends différents paramètres que l'on peut retrouver sur la documentation officielle dont le paramètre path
qui lui est obligatoire.
+
Rappelez-vous également qu'un « play » peut exécuter plusieurs tâches les unes à la suite des autres, exemple:
+---
+- hosts: webservers
+
+ tasks:
+ - name: Check if host is alive # Description of the task
+ ansible.builtin.ping:
+ - name: Execute a simple command
+ ansible.builtin.shell: echo "Ansible was here !" > ansible.txt
+
+- hosts: dbservers
+
+ tasks:
+ - name: Get stats of a file
+ ansible.builtin.stat:
+ path: /etc/hosts
+Vous devriez, en jouant votre playbook (ansible-playbook example.yml -i inventories
) obtenir une sortie équivalente à:
À la différence de nos premières tâches, l'utilisation du module shell
a entrainé une modification de l'état des deux serveurs membres du groupe webservers
qu'Ansible nous confirme à l'aide de son retour changed
.
Lorsque l'on dispose de playbook assez longs, il peut-être intéressant de vérifier la liste des hôtes concernés, c'est faisable à l'aide de la commande ansible-playbook example.yml -i inventories --list-host
.
Il est également possible de lister les tâches avec l'option --list-tasks
et bien évidemment de combiner ces deux options ansible-playbook example.yml -i inventories --list-tasks --list-hosts
.
Vous aurez également remarqué la présence d'une information [TAGS]
très utile dont nous parlerons par la suite ;)
Nous avons vu les principes fondamentaux du fonctionnement des « tasks » avec Ansible, mais celles-ci peuvent être plus complexes que celles que nous avons pu voir jusqu'à présent. +Afin de s'en rendre compte nous allons déployer un serveur web Nginx sur nos instances web.
+Nous allons ajouter une tâche dédiée dans un nouveau playbook que nous appelerons webservers.yml
et qui contiendra les instructions suivantes:
---
+- hosts: webservers
+
+ tasks:
+ - name: Install Nginx web server
+ ansible.builtin.apt:
+ name: nginx
+ update_cache: yes
+ state: present
+En l'exécutant (ansible-playbook webservers.yml -i inventories
) vous devriez obtenir la sortie ci-dessous, Ansible nous indiquant qu'il a effectué une modification sur nos machines distantes:
On notera l'utilisation du module apt
(attention, utilisable bien évidemment uniquement avec les distributions basées sur Debian) accompagné de plusieurs paramètres;
name
: le nom du paquet à installerupdate_cache
: Indique qu'il faut effectuer une mise à jour de l'index des paquets avant l'installation.state
: « L'état » dans lequel nous souhaitons avoir le paquet installé (present, absent, latest...)Vous devriez également pouvoir interroger votre serveur web en utilisant l'IP de votre machine http://XXX.XXX.XXX.XXX
.
Avec cette tâche d'installation nous touchons une autre problématique qui est celle de la gestion des droits et notamment la modification de manière globale de l'état d'un système, ce qui relève normalement de la compétence du compte root
, super administrateur des systèmes à base UNIX.
Si nous n'avons pas rencontré de problème jusqu'à présent c'est parce que nous utilisons un lazy Ansible pré-configuré avec certaines directives dans le fichier de configuration d'Ansible dont nous reparlerons un peu plus tard.
+Il est toutefois possible le cas échéant, d'indiquer au niveau d'une tâche que celle-ci réclame des droits d'administrateur et qu'il faut déclencher une escalade de privilèges. Cela se fait en utilisant des clés réservées comme ci-dessous (en reprenant la tâche d'installation Nginx):
+---
+- hosts: webservers
+ remote_user: debian
+
+ tasks:
+ - name: Ensure Nginx service is started
+ service:
+ name: nginx
+ state: started
+ become: yes
+ become_user: root # This is the default value, so it's not mandatory here
+On remarquera les clés:
+remote_user
: Précisant l'utilisateur avec lequel se connecter à la machine;become
: Indiquant s'il faut déclencher une escalade de privilèges;become_user
: Indiquant le nom du compte utilisateur vers lequel faire l'escalade (Par défaut root).Le mécanisme utilisé par Ansible pour faire son escalade est par défaut la commande sudo
, il est possible de modifier ce comportement avec la clé become_method
.
Nous avons vu que chaque « play » peut contenir plusieurs tâches, il faut savoir que celles-ci sont exécutées dans l'ordre dans lequel elles apparaissent et sur l'ensemble des machines qui correspondent à leur domaine d'application (un groupe ou une machine). +Le but de chacune de ces tâches est d'exécuter un module (nous en avons déjà vu plusieurs, ping, stat, apt, shell), chaque module se devant d'être idempotent garantissant ainsi que peu importe le nombre de fois ou il sera exécuté il produira toujours le même résultat si ses paramètres d'entrée demeurent inchangés.
+Il est important que chaque tâche dispose d'une clé name
fournissant des instructions claires sur son rôle (pensez à la maintenance).
Ceci-dit il est bon de savoir que nos tâches peuvent être organisées de différentes manières et notamment en utilisant les différentes sections que l'on peut trouver dans un playbook:
+pre_tasks
: Contient les tâches à exécuter en premier;roles
: Indiquant une liste de rôles à utiliser dans notre « play » (Nous verrons cette notion plus tard);post_tasks
: Contenant les tâches à exécuter en dernier;handlers
: Contenant des tâches déclenchées à la fin de chaque bloc ou section de tâches en fonction de certains évènements.Elle correspond à une exécution conditionnelle d'un bloc de code AVANT de lancer le « play », elle peut être chargée soit de vérifier des pré-requis soit de valider un état.
+Souvenez-vous au moment d'installer notre paquet Nginx nous avions ajouté le paramètre update_cache
afin de mettre à jour l'index des paquets. Mais nous avons une autre option qui se présente, plutôt que de faire figurer cette option sur chaque appel au module apt
que nous aurons dans notre playbook, nous pouvons gérer la mise à jour de l'index des paquets avant de le jouer.
Modifions notre playbook webservers.yml
de la façon suivante:
---
+- hosts: webservers
+
+ pre_tasks:
+ - name: Updating APT cache index
+ ansible.builtin.apt:
+ update_cache: yes
+
+ tasks:
+ - name: Install Nginx web server
+ ansible.builtin.apt:
+ name: nginx
+ state: present
+Et exécutons le, nous devrions obtenir la sortie suivante:
+ +Où l'on constate qu'effectivement la première tâche exécutée est notre mise à jour d'index de paquets (nous parlerons plus en détails de la tâche « Gathering facts » lorsque nous aborderons les variables)
+Nous ne détaillerons pas la section post_tasks
puisqu'elle fonctionne exactement de la même manière, toutefois nous pouvons enrichir notre playbook avec de nouvelles instructions concernant nos instances de bases de données.
Pour cela nous avons plusieurs options:
+webservers.yml
, mais l'on pourra faire remarquer à raison, que le nom du fichier n'est plus en adéquation avec son contenu;dbservers.yml
.Nous nous orienterons pour l'exemple, sur cette seconde option, nous créerons donc un fichier dbservers.yml
à la racine de notre répertoire de travail dont le contenu ressemblera beaucoup à celui de webservers.yml
.
- hosts: dbservers
+
+ pre_tasks:
+ - name: Updating APT cache index
+ ansible.builtin.apt:
+ update_cache: yes
+
+ tasks:
+ # MARIADB
+ - name: Install MariaDB server
+ ansible.builtin.apt:
+ name: mariadb-server
+ state: present
+ notify:
+ - restart_mariadb
+Notre nouveau playbook est bien evidemment « jouable » à l'aide de la commande ansible-playbook dbservers.yml -i inventories
.
Bien, reprenons notre exemple d'installation d'Nginx, nous avons un paquet « tout neuf » auquel nous n'avons apporté aucune configuration pour l'instant. +Imaginons à présent que nous souhaitions ajouter un fichier de configuration spécifique pour notre serveur web, pour notre exemple nous mettrons en place un fichier qui nous renvoie simplement un « état » de notre serveur Nginx.
+En premier lieu nous allons créer un nouveau répertoire appelé files
à la racine de notre espace de travail lui même contenant un répertoire nginx
(histoire d'organiser un minimum les choses) dans lequel nous ajouterons le fichier status.conf
contenant:
server {
+ listen *:8080;
+ root /usr/share/nginx/html;
+ access_log off;
+ location / {
+ return 404;
+ }
+ location = /nginx/status {
+ stub_status on;
+ }
+}
+Modifions à présent notre fichier webservers.yml
de la façon suivante:
---
+- hosts: webservers
+
+ pre_tasks:
+ - name: Updating APT cache index
+ ansible.builtin.apt:
+ update_cache: yes
+
+ tasks:
+ - name: Install Nginx web server
+ ansible.builtin.apt:
+ name: nginx
+ state: present
+ - name: Nginx status configuration file
+ ansible.builtin.copy:
+ src: nginx/status.conf
+ dest: /etc/nginx/conf.d/status.conf
+Si tout s'est déroulé correctement vous devriez avoir un fichier status.conf
nouvellement créé par Ansible sur vos machines cibles dans le répertoire /etc/nginx/conf.d/
.
+Pour terminer nous pouvons vérifier que notre configuration fonctionne bien en interrogeant l'adresse: http://XXX.XXX.XXX.XXX:8080/nginx/status... ou pas !
Le module copy
+
+ Le module copy
permet de gérer les fichiers de nos machines cibles à savoir leur création, leur suppression mais également leur type (n'oubliez pas, sur des systèmes UNIX tout est fichier !). Il permet notamment de transférer des fichiers de configuration vers des machines. Par défaut à son utilisation Ansible recherche le fichier passé en paramètre dans le répertoire files
de l'espace de travail.
+
En l'état actuel vous devriez avoir pour toute réponse une page blanche, en effet bien que notre fichier de configuration ait été déposé sur le serveur, Nginx ne le prend pas encore en compte car le service n'a pas été redémarré. +C'est là qu'entre en jeu les handlers !
+Les handlers sont des tâches un peu particulières qui ne se déclenchent que lorsqu'elles sont notifiées. +Complétons notre playbook de manière à obtenir la configuration suivante:
+---
+- hosts: webservers
+
+ pre_tasks:
+ - name: Updating APT cache index
+ ansible.builtin.apt:
+ update_cache: yes
+
+ tasks:
+ - name: Install Nginx web server
+ ansible.builtin.apt:
+ name: nginx
+ state: present
+ - name: Nginx status configuration file
+ ansible.builtin.copy:
+ src: nginx/status.conf
+ dest: /etc/nginx/conf.d/status.conf
+ notify:
+ - restart_nginx
+
+ handlers:
+ - name: restart_nginx
+ ansible.builtin.service:
+ name: nginx
+ state: restarted
+En rejouant notre playbook ansible-playbook webservers.yml -i inventories
nous constons que cela n'a rien changé ! Effectivement, comme dit précédemment un handler réagit à un évènement, dans notre cas à la modification du fichier status.conf
. Comme nous ne l'avons pas modifié le handler n'a pas été notifié.
En introduisant une modification dans notre fichier (par exemple en modifiant la directive access_log
pour la passer à off) nous devrions enfin pouvoir accéder à notre page de statut à l'adresse: http://XXX.XXX.XXX.XXX:8080/nginx/status.
Vous devriez également pouvoir constater l'exécution du handler sur la sortie Ansible:
+ +La directive « Notify »
+
+ Les actions de type notify
sont déclenchées à la fin de chaque bloc de tâches d'un « play » donné, elles ne le sont bien évidemment qu'une seule fois même si elles sont appelée plusieurs fois.
+
Il est également possible d'ajouter à un handler une clé listen
comme ci-dessous, celle-ci indiquant au handler « d'écouter » un thème spécifique permettant de regrouper plusieurs « handlers ».
handlers:
+ - name: restart_nginx
+ ansible.builtin.service:
+ name: nginx
+ state: restarted
+ listen: restart_http_stack
+
+ - name: restart haproxy
+ ansible.builtin.service:
+ name: haproxy
+ state: restarted
+ listen: restart_http_stack
+Vous l'aurez compris, si l'on conserve l'ensemble de nos instructions dans un seul playbook celui-ci peut rapidemnent devenir volumineux et difficile à maintenir. Pour autant séparer nos instructions dans des playbooks dédiés conduit invariablement à dupliquer certains blocs d'instructions ce qui n'est pas non plus l'idéal, fort heureusement il est possible de résoudre ces problématiques de manière élégante en utilisant différentes instructions préfixées import_
et export_
.
Avant de réorganiser nos travaux il est important de bien comprendre la différence entre les deux:
+import_*
sont « pré-traitées » au moment où les playbooks sont parcourus et donc avant leur exécution;export_*
sont traitées au moment où elles sont rencontrées durant l'exécution. Réorganisons à présent nos playbooks en tenant compte de cette nouvelle information:
+pre_tasks
peut-être considérée comme une tâche commune à l'ensemble des machines;webservers.yml
et dbservers.yml
mais il peut aussi être « sympa » de pouvoir les appeler de manière groupée;Nous déplacerons donc nos tâches « communes » dans un playbook dédié common.yml
qui contiendra donc:
- name: Updating APT cache index
+ ansible.builtin.apt:
+ update_cache: yes
+Nous supprimerons bien évidemment des playbooks webservers.yml
et dbservers.yml
les instructions correspondantes.
Nos handlers eux, finiront dans un nouveau playbook handlers.yml
comme ci-dessous:
- name: restart_nginx
+ ansible.builtin.service:
+ name: nginx
+ state: restarted
+- name: restart_mariadb
+ ansible.builtin.service:
+ name: mariadb
+ state: restarted
+Quant à nos deux playbooks principaux nous les modifierons légèrement en y ajoutant:
+common.yml
);handlers.yml
);Respectivement:
+---
+- hosts: webservers
+
+ pre_tasks:
+ - ansible.builtin.import_tasks: common.yml
+
+ tasks:
+ # NGINX
+ - name: Install Nginx web server
+ ansible.builtin.apt:
+ name: nginx
+ state: present
+
+ - name: Nginx status configuration file
+ ansible.builtin.copy:
+ src: nginx/status.conf
+ dest: /etc/nginx/conf.d/status.conf
+ notify:
+ - restart_nginx
+
+ handlers:
+ - ansible.builtin.include_tasks: handlers.yml
+---
+- hosts: dbservers
+
+ pre_tasks:
+ - ansible.builtin.import_tasks: common.yml
+
+ tasks:
+ # NGINX
+ - name: Install MariaDB server
+ ansible.builtin.apt:
+ name: mariadb-server
+ state: present
+
+ handlers:
+ - ansible.builtin.include_tasks: handlers.yml
+Nous créerons enfin pour terminer un dernier playbook main.yml
contenant:
- ansible.builtin.import_playbook: webservers.yml
+- ansible.builtin.import_playbook: dbservers.yml
+Nous pouvons à présent jouer l'ensemble avec la commande: ansible-playbook main.yml -i inventories
!
Nous venons de voir la possibilité de « diviser pour réorganiser » nos tâches, mais il existe également la possibilité de « taguer » nos tâches de manière à les déclencher de manière ciblée, ouvrant également la possibilité de les exécuter de façons transverses si celles-ci appartiennent à plusieurs playbooks différents.
+Nous verrons qu'ils sont très utiles voir indispensables dès lorsque nous aurons abordé la notion de roles.
+Reprenons notre exemple précédent où nous disposons de deux playbooks principaux distincts webservers.yml
et dbservers.yml
nous les modifierons de façon à « taguer » nos différentes tâches comme ci-après:
Webservers:
+...
+ tasks:
+ # NGINX
+ - name: Install Nginx web server
+ ansible.builtin.apt:
+ name: nginx
+ state: present
+ tags:
+ - nginx
+ - installation
+
+ - name: Nginx status configuration file
+ ansible.builtin.copy:
+ src: nginx/status.conf
+ dest: /etc/nginx/conf.d/status.conf
+ notify:
+ - restart_nginx
+ tags:
+ - nginx
+ - configuration
+...
+Dbservers:
+...
+ tasks:
+ # NGINX
+ - name: Install MariaDB server
+ ansible.builtin.apt:
+ name: mariadb-server
+ state: present
+ tags:
+ - db
+...
+Maintenant que nos tags sont définis nous sommes en capacité de les exploiter en ajoutant l'option --tags
à notre exécution ce qui nous donnera par exemple:
ansible-playbook main.yml -i inventories --tags "nginx,db"
.Il est également possible d'ignorer certains tags avec l'option --skip-tags
:
ansible-playbook main.yml -i inventories --skip-tags db
.Ansible dans son fonctionnement, prévoit des tags réservés:
+always
, permet de systématiquement jouer une tâche sauf lorsqu'elle est explicitement exclue à l'aide de l'option --skip-tags
;never
à l'inverse, permettra de ne jamais jouer les tâches concernées à moins de le spécifier explicitement à l'aide le l'option --tags
.La tâche « Gathering facts »
++ La tâche « Gathering fact » porte le tag « always » par défaut qui lui permet d'être jouée systématiquement, il est donc possible d'ignorer cette tâche via les options vues ci-dessus. Toutefois son absence peut entrainer un mauvais fonctionnement (voir une erreur) des différentes tâches devant être exécutées à sa suite. +
+Nous savons à présent gérer:
+Nous pouvons toutefois encore apporter un peu de dynamisme à ces premières notions par l'introduction de variables dont nous parlerons dans la suite.
++ Une typo ? + Modifier cet article sur Github +
+Dans ce premier cours à destination des étudiants et/ou néophytes, nous verrons ce qu'est Ansible ainsi qu'un exemple très simple de son utilisation.
+Ce cours est utilisé dans le cadre de TP au sein de l'IUT Lyon 1. Il est notamment dispensé à des étudiants peu ou pas familiers avec les stratégies d'automatisation et de déploiement des infrastructures. +Bien que très axé débutants il peut également représenter une possibilité de monter « rapidement » pour certaines équipes sur les principes fondamentaux d'Ansible afin de disposer du bagage minimal nécessaire à son utilisation.
+Il s'agit bien évidemment de supports à vocation pédagogique qui ne sont pas toujours transposables à une activité professionnelle.
+Afin d'aborder les différents concepts du cours il est recommandé de disposer:
+workspace/ansible
(très original oui), son nom importe peu, l'idée est que vous sachiez vous y retrouver;Pour ceux qui utilisent Windows, il est possible d'utiliser WSL pour faire fonctionner les conteneurs Docker, une machine virtuelle Linux fonctionne encore mieux, libre à vous d'utiliser l'un ou l'autre.
+Première étape avant de pouvoir rentrer dans le vif du sujet, nous aurons besoin de mettre en place un environnement de travail dédié à nos travaux.
+Pour pouvoir configurer nos serveurs, il nous faudra... des serveurs, ou plutôt des machines virtuelles pour leur facilité à être arrêtées, détruites et reconstruites. +N'importe quel fournisseur de cloud public peut faire l'affaire, utilisez celui avec lequel vous avez le plus d'affinités.
+Dans le cadre de l'IUT nous utiliserons OpenStack, solution OpenSource qui a fait ses preuves et qui plus est disponible dans l'enceinte de l'université, c'est également la solution technique utilisée par le Public Cloud d'OVHCloud. +C'est donc sur cette base que je présenterai les étapes suivantes, au demeurant, parfaitement transposables chez d'autres fournisseurs.
+Nous travaillerons avec deux environnements distincts, « Staging » et « Production » qui embarqueront chacune une instance applicative (qui portera donc le code d'une application) et une instance destinée aux données (et donc chargée de faire fonctionner notre serveur de base de données). +Si vous êtes limité en terme de création d'instances, il est envisageable de n'avoir qu'une instance par environnement, celle-ci embarquant l'applicatif et les données.
+Les étapes suivantes seront donc à exécuter à partir de votre machine.
+Considérant que vous remplissez les prérequis et que vous avez créé vos instances distantes nous allons pour commencer initier une « simple » connexion SSH vers notre instance.
+ssh debian@XXX.XXX.XXX.XXX
+Si vous rencontrez des soucis .. forbidden (exemple) ré-essayez en ajoutant explicitement le chemin vers la clé.
+ssh -i ~/.ssh/ed25519 debian@XXX.XXX.XXX.XXX
+Utilisateur sous Windows
+
+ Pour rappel aux utilisateurs de Windows vous trouverez ce répertoire .ssh
dans C:\Users\MonNomUtilisateur\
+
Afin d'éviter d'avoir à spécifier le chemin vers la clé à chaque connexion et afin d'affiner la configuration de notre client nous pouvons également définir un fichier ~/.ssh/config
contenant les directives suivantes:
Host 192.168.140.*
+ Port 22
+ User debian
+ IdentityFile ~/.ssh/keyfile
+ IdentitiesOnly yes
+ ForwardAgent yes
+Celles-ci sont relativement compréhensibles, précisons tout de même pour les deux dernières:
+IdentitiesOnly
indique à SSH de n'envoyer au serveur QUE la clé définie à la directive IdentityFile
quand bien même vous disposez d'autres clés dans votre répertoire ~/.ssh
ForwardAgent
permet d'activer le transfert d'identité vers l'agent SSH du serveurCette configuration vous permet d'indiquer certaines directives de manière automatique pour un ou plusieurs hôtes distants, pour en savoir plus concernant les fichiers de configuration SSH vous pouvez aller jeter un oeil ici
+La prochaine étape est l'utilisation d'un service spécifique à SSH, l'agent.
+L'agent SSH sur la plupart des systèmes UNIX est lancé au démarrage de votre machine, toutefois si ça n'est pas le cas, il est possible de le démarrer avec la commande eval 'ssh-agent'
.
+Son rôle est de permettre de stocker de manière sécurisée votre/vos clés privées SSH (rappelez-vous c'est la partie que l'on ne partage pas !) mais également d'assurer le transfert de cette clé privée en toute sécurité vers les serveurs distants auxquels vous tenterez de vous connecter.
L'ajout d'une clé dans un agent est trivial et se fait à l'aide de la commande ssh-add ~/.ssh/my_private_key
.
Si vous avez protégé votre clé avec une phrase de passe elle vous sera demandée par l'agent au moment de son ajout.
+Afin de vérifier que votre clé a bien été ajoutée à votre agent vous pouvez lister les clés contenues à l'intérieur avec la commande ssh-add -l
qui devrait vous donner une sortie équivalente à la suivante:
rix@debian:~$ ssh-add -l
+4096 SHA256:knyjFlzIWukj77PBs0V+mO4eKD9mnSITOkYfYvgvZcQ /home/rix/.ssh/gfaivre-iut (RSA)
+Cette étape, complétée par la directive ForwardAgent
contenue dans notre fichier de configuration SSH (pour rappel ~/.ssh/config
) va nous permettre lorsque nous nous connectons à un serveur distant de transférer notre clé privée vers l'agent de ce même serveur.
De cette manière notre clé privée sera même disponible sur le serveur auquel nous nous connectons, nous aborderons l'utilité de cette configuration plus tard.
+Notre environnement étant « prêt » testons à présent la bonne communication avec nos serveurs distants en utilisant le module ping
d'Ansible.
À partir de ce moment et sauf instruction contraire nous partirons du principe que nous évoluons à l'intérieur de notre répertoire de travail (workspace/ansible
donc ;)) pour saisir nos commandes et créer notre arborescence de projet.
Les modules Ansible
+
+ Dans la terminologie Ansible, les « modules » sont des morceaux de code pouvant être utilisés soit directement dans la ligne de commande (avec l'option -m
, soit dans une section task
d'un « playbook »). Ils peuvent prendre en charge des arguments avec une syntaxe classique key=value
.
+
Pour pouvoir effectuer notre premier test nous allons donc créer un fichier que nous appellerons hosts.yml
contenant (à adapter en fonction du réseau sur lequel sont déployées vos machines virtuelles):
all:
+ hosts:
+ ansible-vm-01:
+ ansible_host: 192.168.140.30
+ ansible_user: debian
+Attention à l'indentation et faites attention de bien utiliser des espaces pour celle-ci.
+Pour terminer nous lançons notre conteneur docker « lazy » avec un make sh
et y exécutons la commande ansible -i hosts.yml all -m ping
, qui utilise le module ping d'ansible pour vérifier que l'on arrive bien à se connecter à l'instance distante.
Ce qui nous donne:
+ +Le module ping
++ Bien que son nom puisse porter à confusion, il s'agit là d'un module propre à Ansible et qui n'a rien à voir avec la commande système du même nom. Pour rappel, la commande système envoie un paquet ICMP (ECHO_REQUEST) à une machine distante et attend en retour un paquet du même type (ECHO_RESPONSE) indiquant le bon état de la liaison réseau. + Le module Ansible quant à lui se connecte via SSH à la machine distante et y vérifie la bonne configuration de Python. +
+Cette dernière étape me permet d'introduire un concept que nous verrons dans la section suivante, celui des inventaires !
++ Une typo ? + Modifier cet article sur Github +
+Génération, utilisation et cas pratiques d'utilisation de clés SSH.
+Une clé SSH est un moyen d'authentification vers un serveur SSH reposant sur les principes de cryptographie asymétrique et d'authentification défi / réponse.
+Elle a deux avantages fondamentaux comparativement avec une authentification par couple identifiant/mot de passe:
+La très grande majorité des accès serveurs sont aujourd'hui basés sur leur utilisation, au dela de l'aspect fluidité et sécurité, elle ouvre également la possibilité d'authorisation multiple (sur plusieurs serveurs), de révocation et de signature des accès facilités.
+Secure Shell (SSH)
++ Secure Shell (SSH) est à la fois un programme informatique et un protocole de communication sécurisé. + Le protocole de connexion impose un échange de clés de chiffrement en début de connexion. Par la suite, tous les segments TCP sont authentifiés et chiffrés. Il devient donc impossible d'utiliser un sniffer pour voir ce que fait l'utilisateur. + Le protocole SSH a été conçu avec l'objectif de remplacer les différents protocoles non chiffrés comme rlogin, telnet, rcp et rsh. +
+Génération d'une paire de clés:
+ssh-keygen -t ed25519 -a 150
+Se connecter à un serveur distant
+ssh -i ~/.ssh/id25519 user@server_address
+Le principe de l'authentification par clés repose, comme explicité sur les différents liens ci-dessus, par la création d'une paire de clés asymétriques. +L'une de ces clés sera votre clé publique à déployer sur les machines auxquelles vous avez le droit de vous connecter, l'autre, votre clé privée. Et comme son nom l'indique, celle-ci est à vous et rien qu'à vous ; elle ne se partage pas. JAMAIS.
+Deux notions de base avant de se lancer pour bien comprendre ce que l'on fait:
+Il est recommandé, à la date de rédaction de cet article, d'utiliser l'algorithme Ed25519 qui a plusieurs avantages comparativement à RSA:
+ssh-keygen -t ed25519 -a 150 -C "courriel@example.com"
+
+L'option -C
permet d'ajouter un commentaire à votre clé, pratique notamment pour identifier le propriétaire d'une clé publique coté serveur.
Phrase de passe
++ Bien que facultative, il est « extrêmement vachement recommandé » de disposer d'une phrase de passe sur vos clés SSH (dans le cadre des cours et pour gagner du temps il est possible de s'en passer si vous n'utilisez pas votre clé en dehors de ceux-ci). +
+Cette commande vous aura généré deux fichiers dans le répertoire ~/.ssh/
(sauf si vous l'avez modifié bien évidemment):
id_ed25519.pub
(comme son extension l'indique c'est votre clé publique);id_ed25519
votre clé privée (on remarquera les droits qui lui sont appliqués 0600
, en effet seul votre utilisateur doit y avoir accès).Générer une clé RSA
+
+ Ed25519 n'étant de temps en temps pas supporté (surtout par les anciens systèmes) il est parfois nécessaire de générer une paire de clé RSA (on remarquera la longueur de clé de 4096 bits recommandée à date de rédaction de l'article):
+ ssh-keygen -t rsa -a 150 -b 4096
+
C'est un peu la finalité.
+Imaginons un serveur pour lequel votre clé est autorisée à se connecter (pour rappel fichier authorized_keys
), nous pouvons initier une connexion à l'aide de la commande:
ssh user@server_address
Cette commande aura donc pour effet « d'ouvrir » une connexion sur un serveur distant via le protocol SSH vous permettant de saisir des lignes de commande directement sur ce serveur et donc de l'administrer.
+ +Cette exemple montre l'ouverture d'une session avec l'utilisateur debian
sur le serveur ayant pour adresse IP 146.59.243.95
.
Plusieurs choses à retenir à cette étape:
+~/.ssh
afin de les proposer au serveur auquel vous essayez de vous connecter.Si vous disposez de plusieurs clés SSH et que vous ne souhaitez pas que l'ensemble de vos clés privées soient soumises au serveur distant vous pouvez spécifier quelle clé utiliser en utilisant l'option -i
.
ssh -i ~/.ssh/id25519 debian@146.59.243.95
+Il est possible d'utiliser des syntaxes différentes en fonction de votre fichier de configuration SSH.
+Vous pouvez ainsi agir sur les comportements par défaut de votre client SSH et notamment sur la clé à utiliser en fonction de tel ou tel serveur.
++ Une typo ? + Modifier cet article sur Github +
+Avec l'intégration WSL2 de Windows et Docker Desktop, comment utiliser des conteneurs Docker dans une machine virtuelle WSL ?
+Avec l'arrivée de Docker Desktop il est dorénavant aisé de faire « tourner » des conteneurs Docker sous Windows. +Il est par contre moins simple d'utiliser d'autres outils propres au monde UNIX que nous aurons besoin d'utiliser avec le Lazy Ansible de Manala (make par exemple).
+Et comme nous préférons éviter d'installer trop de choses sur les machines hôtes nous opterons pour un fonctionnement qui reste relativement élégant à savoir lancer une machine WSL Debian et y faire tourner notre conteneur Docker. +De cette manière nous disposerons de l'ensemble de l'outillage Linux, sans avoir à l'installer sur notre poste.
+wsl --set-default-version 2
wsl --install -d Debian
Il faudra ensuite renseigner un nom d'utilisateur ainsi qu'un mot de passe (à ne pas perdre de préference). +Vous devriez au final obtenir un shell comme ci-dessous, félicitation vous êtes dans une machine virtuelle Debian WSL !
+ +La partie la plus simple, téléchargez et installez le ici: https://docs.docker.com/desktop/windows/wsl/#download
+Il y a quelques options à vérifier / activer pour un bon fonctionnement.
+Il faudra pour cela quitter et relancer (Dans un PowerShell wsl -d Debian
) votre machine virtuelle Debian.
+Une fois à l'intérieur de celle-ci il sera nécessaire de donner les droits à votre utilisateur d'utiliser Docker en l'ajoutant au groupe du même nom.
usermod -a -G docker <username>
+Pour terminer la commande docker ps
devrait vous renvoyer l'écran ci-dessous:
+ Une typo ? + Modifier cet article sur Github +
+Apprendre à utiliser le fichier de configuration SSH pour organiser ses options de connexion.
+Si vous vous connectez à plusieurs hôtes distants il y a fort à parier que vous ne mémorisez pas les subtilités de connexion propre à chacun d'entre eux (utilisateur spécifique, port non standard, options spécifiques…).
+On a eu, il est vrai, l'occasion de croiser des façons originales de le faire, notamment à base d'alias Bash mais ça reste assez artisanal alors même que tout est prévu et qu'OpenSSH permet de définir un fichier de configuration propre à chaque utilisateur du système ;)
+Cet article, principalement à destination des étudiant·e·s et des nouveaux arrivants dans le domaine saura sans doute également servir de pense bête aux confirmé·e·s !
+Ils sont plus que pauvre puisqu'un client OpenSSH et une machine distante à laquelle se connecter suffiront.
+Contenu d'un fichier config d'un client SSH pour référence:
+Host *
+ User rix
+ IdentityFile ~/.ssh/ed_25519.key
+ IdentityFile ~/.ssh/id_rsa.key
+ IdentitiesOnly yes
+ ForwardAgent yes
+Comme abordé dans l'introduction, il existe autant de manières de se connecter à un serveur avec SSH qu'il n'en existe (de serveurs), les principaux bénéfices que l'on peut retirer de cette utilsation:
+En « standard » vous trouverez un dossier appelé .ssh
dans le répertoire utilisateur de votre système (/home/username/
sur un système de type UNIX ou C:\Users\username\
sous Windows). C'est ici que nous allons créé un fichier appelé tout simplement config
(sans extension).
Configuration globale
+
+ Il est possible d'appliquer un comportement global au client SSH (C'est à dire pour tous les utilisateurs du système) en utilisant le fichier /etc/ssh/ssh_config
.
+
Si le répertoire .ssh
n'existe pas (il est créé automatiquement lorsque vous créez une nouvelle clé par exemple) vous pouvez le créer comme suit:
mkdir -p ~/.ssh && chmod 0700 ~/.ssh
+Pour ensuite créer le fichier config
touch ~/.ssh/config && chmod 0600 ~/.ssh/config
+Les droits
+
+ Attention SSH est très sensible (à juste titre) aux droits appliqués aux fichiers qu'il doit utiliser.
+ Le répertoire .ssh
tout comme le fichier config
ne doit être accessible, lisible et modifiable qu'à l'utilisateur propriétaire.
+
Le fichier config
est basé sur un système de paires clé/valeur organisées par section, une structure minimal d'un fichier de configuration pourrait être la suivante:
Host server-hostname-1
+ KEY value
+ KEY value
+Allons plus loin avec une configuration:
+Host server-hostname-1
+ HostName server.tld
+ User rix
+ IdentityFile ~/.ssh/ed_25519.key
+La directive Host
permet d'indiquer à la fois une nouvelle section mais également le « pattern » qui permettra au client de savoir quand appliquer la configuration.
+Dans ce premier exemple c'est assez simple et spécifique puisque notre bloc s'appliquera à la chaine server-hostname-1
Ainsi lorsque nous taperons ssh server-hostname-1
notre client saura à quel hote se connecter, avec quel utilisateur et quelle clé.
+L'équivalent sans fichier de configuration serait ssh -i ~/.ssh/ed_25519.key rix@server.tld
L'utilisation d'un fichier de configuration prend tout son sens lorsque l'on souhaite appliquer des comportements spécifiques à un ensemble de machines.
+Il est ainsi possible d'utiliser des « pattern » (et de les enchaîner) en utilisant des opérateurs:
+Host *
par exemple s'appliquera à tous les hôtes puisque le caractère *
correspond à aucun ou plusieurs caractères.192.168.140.*
il est possible de composer, dans ce cas vous appliquerez votre configuration à l'ensemble des hôtes dont l'adresse fait partie du sous réseau 192.168.140.0/24
?
permet de restreindre une expression à un seul caractère. Ainsi Host 172.16.1.?
correspondra à tous les hôtes ayant en dernier octet un chiffre compris entre 0 et 9.!
En début de chaîne permet d'exclure une correspondance. Ainsi 172.16.1.* !172.16.1.20
s'appliquera à tous les hôtes du sous réseau 172.16.1.0/24
à l'exception de 172.16.1.20
.Organisation et structure du fichier
++ Le fichier de configuration SSH n'impose pas d'indentation, il est toutefois fortement recommandé de l'organiser afin de faciliter sa lecture et sa maintenance. + Il faut également noter que les instructions sont appliquées dans leur ordre d'apparition il est donc préférable de commencer par les sections très spécifiques et de terminer par les plus génériques. +
+Il est possible en fonction d'où elles sont indiquées de surcharger certaines options de connexion, ainsi votre client SSH considérera par ordre de priorité:
+config
du compte utilisateur (~/.ssh/config
)/etc/ssh/ssh_config
Ainsi en reprendant notre section précédente:
+Host server-hostname-1
+ HostName server.tld
+ User rix
+ IdentityFile ~/.ssh/ed_25519.key
+Il est possible de vous connecter avec un autre utilisateur que celui défini dans votre fichier en surchargeant la clé User
, soit avec ssh root@server-hostname-1
ou encore ssh -o "User=root" server-hostname-1
.
Il est également possible, notamment lorsque le contenu des fichiers devient conséquent ou tout simplement pour organiser ses configurations entre différents contextes (clients, perso, pro...), de séparer la configuration dans plusieurs fichiers.
+Il est ainsi possible d'avoir autant de fichiers de configuration que de contextes pour ensuite les inclure dans notre fichier principal.
+Exemple:
+# Contenu de ~/.ssh/config
+Host server-hostname-1
+ HostName server.tld
+ User rix
+ IdentityFile ~/.ssh/ed_25519.key
+
+Include ~/.ssh/config_alternative
+# Contenu de ~/.ssh/config_alternative
+Host 192.168.140.*
+ User debian
+ IdentityFile ~/.ssh/id_rsa.key
+ AddKeysToAgent yes
+ UseKeychain yes
+Le fichier config
supporte nombre d'options de configuration, celles-ci sont consultables ici.
+Il va de soi que dans l'activité quotidienne, les mêmes instructions sont souvent utilisées, ci-dessous une liste des plus courantes:
IdentityFile
: Nous l'avons vu précédemment, elle permet d'indiquer la clé à utiliser pour la section définie;ForwardAgent
: Un grand classique, permet de « faire suivre » comme son nom l'indique au serveur distant, votre clé privée de manière à ce que celui-ci la stocke dans son propre agent SSH. Cette option permet ensuite de se connecter à d'autres serveurs « par rebond », c'est ce principe qui est notamment mis en oeuvre par les « bastions » SSH;IdentitiesOnly
: Important si vous utilisez l'option précédente, permet de ne transmettre que la ou les clé(s) spécifiée(s) avec l'option IdentityFile
précédente, par défaut SSH envoie toutes les clés privées qu'il trouvera dans votre trousseau;StrictHostKeyChecking
: Permet de vérifier la signature du serveur auquel on se connecte, toujours à Yes
sauf dans le cas de figure que l'on présente plus bas.Désactiver StrictHostKeyChecking
+ Précaution d'usage, à ne faire que si vous savez réellement ce que vous faites ;) + Le seul exemple qui me vient à l'esprit pouvant nécessiter de désactiver cette option est celui de séances de cours / TP durant lesquelles nous avons souvent besoin de créer / détruire des instances qui peuvent potentillement récupérer les mêmes adresses IPs. +
+Pour éviter d'avoir régulièrement l'erreur, WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
il est possible de spécifier:
StrictHostKeyChecking no
+UserKnownHostsFile /dev/null
+Le principe du multiplexage réside dans le fait de « partager » la même connexion entre les différentes sessions ouvertes sur une même machine. +Cette stratégie permet, dans le cas d'SSH de réutiliser une connexion TCP déjà ouverte vers un serveur distant.
+Le but ? S'épargner le délai d'ouverture d'une connexion TCP ainsi que celui de la réauthentification. +Cette fonctionnalité peut-être particulièrement utile lors du transfert de nombreux fichiers d'une machine à une autre, elle réside principalement en l'utilisation de 3 options de configuration:
+ControlMaster
: Permet d'indiquer à SSH la stratégie à adopter lorsqu'il détecte une possibilité de réutilisation d'une connexion ouverte (Fixée à no
par défaut);ControlPersist
: Permet d'indiquer comment SSH doit gérer la fermeture de la connexion initiale à la machine distante (celle qui a entrainée l'ouverture de la socket partagée);ControlPath
: Le chemin vers la socket utilisée pour le partage de connexion, cette option supporte les tokens %h
%p
et %r
dont la combinaison est très fortement recommandée. Plus d'informations sur les tokens supportés par SSH (https://man.openbsd.org/ssh_config#TOKENS).Host server-hostname-1
+ HostName server.tld
+ User rix
+ IdentityFile ~/.ssh/ed_25519.key
+ ControlPath ~/.ssh/controlmasters/%C
+ ControlMaster auto
+ ControlPersist 10m
+Le token %C
+
+ On remarquera son utilisation dans l'exemple ci-dessus. Il s'agit du hash SHA1 des tokens %l%h%p%r (Respectivement le nom d'hôte local (%l
), le nom d'hôte distant (%h
), le port de connexion distant (%p
) et pour finir le nom d'utilisateur distant utilisé (%r
)).
+ L'utilisation du token %C
assurant à la fois, l'unicité de la connexion et l'obfuscation de ses détails sur le système de fichiers.
+
+ Une typo ? + Modifier cet article sur Github +
+Découverte des playbooks, élément essentiel d'Ansible qui va nous permettre d'organiser et structurer nos tâches !
+Première étape vers l'utilisation d'Ansible, les inventaires. Ils sont le point d'entrée vers vos infras et sont donc central au pilotage de vos instances / serveurs.
+ + +Dans ce premier cours à destination des étudiants et/ou néophytes, nous verrons ce qu'est Ansible ainsi qu'un exemple très simple de son utilisation.
+ + +Utilisation de la recipe Lazy Ansible du projet Manala pour mettre en oeuvre un environnement de travail dédié Ansible.
+ + +Génération, utilisation et cas pratiques d'utilisation de clés SSH.
+ + +Interprétation pas à pas d'un incident sur infrastructures applicatives, cas pratique d'un incident vécu.
+ + +Avec l'intégration WSL2 de Windows et Docker Desktop, comment utiliser des conteneurs Docker dans une machine virtuelle WSL ?
+ + +Apprendre à utiliser le fichier de configuration SSH pour organiser ses options de connexion.
+ + +Construire une image source Debian à déployer sur Raspberry Pi en remplacement de Raspberry Pi OS (anciennement Raspbian).
+ + +Intégrer (relativement) facilement des agendas iCloud à Gnome Calendar
+ + +Construire une image source Debian à déployer sur Raspberry Pi en remplacement de Raspberry Pi OS (anciennement Raspbian).
+Je vous vois venir ! Quelle idée de vouloir construire sa propre image ? +Alors même que Raspberry fourni un OS ET un utilitaire permettant de créer des cartes SD « bootables » rapidement et quasi sans douleur !
+Pour les opérations à suivre utilisez une Debian Bulleyes (de préférence VM)
+git clone --recursive https://salsa.debian.org/raspi-team/image-specs.git
+cd image-specs
apt install -y vmdb2 dosfstools qemu-utils qemu-user-static debootstrap binfmt-support time kpartx bmap-tools python3
+apt install -y fakemachine
make raspi_4_bullseye.img
;dd if=raspi_4_bullseye.img of=/dev/XXX bs=64k oflag=dsync status=progress
.Oui mais…
+Avant d'aller plus loin il faut savoir que nous utilisons en interne plusieurs Raspberry Pi afin de faire tourner des services qui nous permettent de piloter la gestion du réseau local de nos bureaux et/ou d'y fournir des services basiques et non critiques (Serveurs DNS locaux, VPN, métriques, monitoring…).
+Nous avons également une petite flotte de ces machines qui nous permettent d'aller enseigner « quelques trucs » à des étudiants (du réseau, du provisioning, linux…) en se reposant dessus.
+Alors bien évidemment le besoin ne tombe pas du ciel, et même si l'exercice reste formateur et amusant (si, si) le but n'est bien évidemment pas « juste ludique ». +Raspberry Pi OS a en fait ses limites, particulièrement lorsqu'on va l'utiliser sur d'anciens Raspberry Pi (notamment des 2 ou précédents).
+Pour terminer il faut savoir que Raspbian (dérivé de Debian) a été créé en premier lieu parce que jusqu'à 2018 il n'était pas possible de démarrer un kernel linux sur Raspberry Pi mais également parce que Raspbian arrivait avec des composants non libres contraires à la philosophie Debian.
+On se retrouve notamment par défaut (il est possible d'aller chercher d'autres versions d'OS dans l'utilitaire de création d'images) avec une version de Raspberry Pi OS commune à toutes les versions et donc 32 bits…
+Pour rappel les premières architectures 64 bits des Raspberry Pi sont arrivées avec la version 3. +Debian fait le choix de coller exactement aux différentes archi, mais au prix d'une image pour chacune, celles-ci sont d'ailleurs disponibles ici.
+Version Raspberry Pi | +Debian | +Raspberry Pi OS | +
---|---|---|
0 / 1 | +armel, 32 bit | +armhf, 32 bit | +
2 | +armhf, 32 bit | +armhf, 32 bit | +
3 | +arm64, 64 bit | +armhf, 32 bit | +
4 | +arm64, 64 bit | +armhf, 32 bit | +
Il existe d'autres versions d'OS disponibles en version serveur ou desktop (Ubuntu, Manjaro…) mais comme nous utilisons les roles Ansible du projet Manala pour provisionner l'ensemble de nos machines et afin d'assurer au maximum la compatibilité (et nous éviter de la maintenance), nous préferons rester cohérents et utiliser Debian.
+Pour terminer, les images pré-construites Debian peuvent carrément faire l'affaire mais certains choix de configuration ne nous vont pas et nous avons besoin que nos images soient prêtes à être « provisionnées » et donc disposer:
+Ils sont peu nombreux, tant la construction d'images est rendue très simple par les contributeurs à la version Raspberry Pi de Debian.
+Vous aurez besoin:
+En tout premier lieu, une fois sur votre VM Debian Bullseye, on clone le répertoire d'outils:
+git clone --recursive https://salsa.debian.org/raspi-team/image-specs.git
+cd image-specs
+Nous aurons également besoin de quelques paquets pour la construction:
+apt install -y vmdb2 dosfstools qemu-utils qemu-user-static debootstrap binfmt-support time kpartx bmap-tools python3
+apt install -y fakemachine
+Le fichier makefile fournit vous permet ensuite, au choix:
+De construire une image spécifique à votre Raspberry Pi en utilisant une configuration par défaut:
+make raspi_<model>_<release>.img
<model>
vaut pour la version de votre Raspberry (1,2,3 ou 4 avec 1 utilisé pour les versions Pi 0, 0w and 1);<release>
pour la version de Debian que vous souhaitez construire.Dans notre cas une Bullseye pour un Raspberry Pi 2: make raspi_2_bullseye.img
De construire une image spécifique à partir de VOTRE configuration (et c'est ce choix qui nous intéresse)
+Alors bien évidemment nous ne partirons pas d'une page blanche mais du fichier de configuration généré par l'outil grâce à la commande:
+make raspi_2_bullseye.yaml
Nous obtenons un fichier de configuration par défaut (celui utilisé pour la construction de l'image avec la commande précédente). +Il est possible de l'éditer directement mais préférable de le nommer différemment histoire de ne pas malencontreusement écraser nos prochaines modifications en rejouant la commande précédente.
+cp raspi_2_bullseye.yaml rix_raspi_2_bullseye.yaml
En ce qui nous concerne nous y opérerons plusieurs modifications:
+- chroot: tag-root
+ shell: |
+ useradd -g100 -Gsudo -m -s /bin/bash rix
+- create-dir: /home/rix/.ssh
+ uid: 1000
+ gid: 100
+- create-file: /home/rix/.ssh/authorized_keys
+ contents: |+
+ ssh-ed25519 AAAAC3XXXXXXXXXXXXXXXXXXXX
+- create-file: /etc/sudoers.d/rix-default
+ contents: |+
+ rix ALL=(ALL) NOPASSWD: ALL
+root
locale sans mot de passe.- # Allow root logins locally with no password
+- sed -i 's,root:[^:]*:,root::,' "${ROOT?}/etc/shadow"
+La directive chroot
+ Elle est essentielle dès lors que vous souhaitez exécuter une commande dans le contexte du système en cours de construction. +
+Une fois l'ensemble de nos instructions ajoutées à notre fichier nous pouvons démarrer la construction de notre image:
+vmdb2 --rootfs-tarball=rix_raspi_2_bullseye.tar.gz --output \
+rix_raspi_2_bullseye.img rix_raspi_2_bullseye.yaml --log rix_raspi_bullseye.log
+Cette commande devrait nous donner en sortie 3 fichiers:
+rix_raspi_bullseye.log
rix_raspi_2_bullseye.img
rix_raspi_2_bullseye.tar.gz
L'installation de l'image est ensuite assez standard, une fois votre carte SD montée:
+bmaptool
à partir de l'image compressée;bmaptool copy rix_raspi_2_bullseye.tar.gz /dev/mmcblk0
dd
:dd if=rix_raspi_2_bullseye.img of=/dev/XXX bs=64k oflag=dsync status=progress
+ Attention à la « cible » de l'écriture, en cas de mauvais volume sélectionné vous écraserez son contenu. +
+Vous voilà paré·e·s pour déployer du Raspberry Pi en série sur une base Debian !
+Sources:
++ Une typo ? + Modifier cet article sur Github +
+Intégrer (relativement) facilement des agendas iCloud à Gnome Calendar
+Contrairement à ce que certains pensent on peut être utilisateur d'un iPhone (ou d'un iPad) sans avoir de mac.
+Et oui c'est mon cas d'ailleurs ;)
+Autant je ne changerais pas mon iPhone contre un Android (même si j'ai aussi un XPeria avec SailfishOS) autant je n'échangerais pas plus mon Linux contre un OSX.
Oui mais… bien qu'il devrait être très facile de synchroniser ses agendas iCloud avec Gnome (étant donné qu'iCloud propose un format CalDAV), la réalité n'est pas tout aussi simple !
+Petit guide pour épargner les arrachages de cheveux pour y parvenir.
+En tout premier lieu, ouvrez l'onglet « Agenda » (vous serez pas défaut sur la vue « courriel ») une fois sur la partie agenda, créer en un nouveau comme ci-contre.
+Renseignez ensuite vos informations et suivez les étapes ci-contre.
++
Pour terminer, libre à vous d'activer les options afin de rendre vos agendas disponibles hors ligne et de sélectionner votre agenda par défaut.
+ATTENTION
les étapes ci-dessus devront être répétées pour CHACUN
des agendas dont vous disposez, je n'ai pas trouvé mieux pour l'instant.
+Une fois vos agendas synchronisés vous pouvez fermer Evolution, l'agenda de Gnome devrait automatiquement ajouter les agendas que vous venez de configurer.
+ Une typo ? + Modifier cet article sur Github +
+Passer d'OSX à Linux en milieu professionnel, le quotidien, équivalence d'applications, fonctionnement, astuces.
+Parce que le choix (ou la nécessité) de changer de système d'exploitation remet en cause notre utilisation quotidienne et nos réflèxes applicatifs, il me parait louable de partager MA façon d'utiliser Linux après de nombreuses années avec OSX et quelles solutions j'ai « trouvé » pour reprendre mes marques notamment en terme d'équivalence d'applications et d'utilisation au quotidien.
+Billet à destination de celles et ceux qui hésitent encore à franchir le pas de peur de se retrouver perdu·e.
+En préambule et pour mieux cerner certaines contraintes que j'ai pu avoir ou choix que j'ai pu faire:
+pro et perso
depuis plus de 20 ans (J'ai commencé avec Debian/Potato);Je ne prêche pour aucune distribution en particulier
, sauf côté serveur, mais ça n'est pas le sujet;
+Gnome
comme environnement graphique;Je séparerai cet article en plusieurs parties en fonction des différentes utilisations:
+Sans plus attendre un premier chapitre qui va se concentrer sur l'utilisation que chacun d'entre nous peut avoir d'une machine.
+L'une des premières utilisation, les courriels !
+J'utilise uniquement les clients de courriel et quasiment jamais un navigateur pour consulter ma messagerie. Avec OSX j'utilisais l'excellent Postbox
.
Du côté de linux j'ai retenu deux candidats:
+Mailspring
qui dispose d'une interface beaucoup plus simple et accessible et fonctionne très bien avec le bridge de chez ProtonMail
.À noter que j'attends la refonte annoncée de Thunderbird avec impatience tant le fonctionnel de Mailspring reste « relativement » limité.
+(Mise à jour du 18 Novembre 2022: Quelques écrans de la nouvelle interface ont fait leur apparition, ils semblent augurer d'un gros et bon travail d'UI.)
Au niveau des messageries j'utilise principalement Signal
et Whatsapp
(pour les proches), les deux disposent d'intégration des clients comme je l'avais sous OSX rien à signaler à ce niveau on est ISO !
Probablement la brique la plus standardisée à l'heure actuelle, on retrouve exactement la même chose côté Linux c'est donc plus l'affinité de chacun qui va jouer.
+De mon côté j'en utilise deux principalement Brave
(sur une base chromium donc) et Librewolf
(sur une base Firefox).
À ces derniers vient se greffer TorBrowser
.
Ah ! La bureautique…
+Point de friction lié principalement à la comptabilité avec les formats propriétaires, je n'ai plus rencontré de « vrai » problème depuis un moment.
+J'utilise OnlyOffice Desktop
pour l'édition de document de type Word et Excel et ça juste marche !
Point plus embêtant si vous avez des imprimantes réseau un peu anciennes il est probable qu'il vous soit compliqué d'imprimer sans faire un effort de configuration (je ne l'ai pas fait, je n'imprime quasiment jamais).
+Du côté des PDFs, le visionneur de documents de Gnome fait très bien le boulot pour de la lecture.
+Au niveau de l'édition c'est un domaine ou il faut encore bricoler par rapport à OSX qui est très bon nativement pour manipuler les PDFs.
+J'utilise donc Xournal++ dès lors que je dois y insérer des images ou autres éléments mais il s'agit d'un projet qui semble être à l'abandon et pour lequel je n'ai pas encore cherché/trouvé d'alternative viable.
Là encore l'offre est plétorique, après avoir pas mal utilisé Lightning
(Thunderbird) je suis revenu sur Gnome Calendar
qui fait le boulot.
ATTENTION toutefois il n'intègre pas la mécanique d'invitations, si vous planifiez beaucoup de réunions il vaut sans doute mieux rester sur Lightning.
+Pour ceux qui disposent d'agendas iCloud (j'en fais partie) leur ajout à Lightning passe par l'utilisation de l'extension TBSync quant à Gnome Calendar il faut passer par une gymnastique assez lourde que je décris ici.
++ Une typo ? + Modifier cet article sur Github +
+Passer d'OSX à Linux en milieu professionnel, le quotidien, équivalence d'applications, fonctionnement, astuces.
+ + +Tour d'horizon de ce qu'on a pour faire de beaux articles. Et quelques bonnes pratiques de rédaction.
+ + +Interprétation pas à pas d'un incident sur infrastructures applicatives, cas pratique d'un incident vécu.
+Premier article concernant la résolution d'incidents, toujours à but de formation. +N'ayant jamais vu beaucoup d'articles traitant du sujet il nous parait intéressant d'expliquer et commenter les post-mortems qu'il nous arrive d'envoyer à nos clients. +C'est aussi, à notre avis, une bonne façon (si ce n'est la meilleure) d'expliquer pourquoi le DevOps est important dans les métiers SRE, à quoi il sert et comment nous utilisons les outils que l'on met en place.
+Gardez à l'esprit que chaque applicatif est unique (même si l'on retrouve des comportements type) et que l'un des meilleurs indices d'anomalie et « l'écart par rapport à la moyenne normale », autrement dit un comportement qui diffère fortement de ce que vous avez l'habitude de voir.
+Pour finir, c'est l'exercice le moins « confortable » du métier. +En fonction de sa gravité, l'incident infra peut passer inaperçu comme impacter de manière significative l'activité d'un client, l'expérience des équipes dans ce cas de figure est souvent un facteur clé pour la rapidité de la résolution.
+Le contexte est assez classique pour de l'application web.
+En complément:
+Comme tous les incidents, nous sommes alertés par nos sondes infra:
+Il n'est pas rare d'avoir des alertes isolées dues à une défaillance d'un hyperviseur ou à une panne réseau, dans notre cas de figure l'effondrement de l'infrastructure est très rapide (inférieure à 3 minutes), aucun doute donc sur « un gros pépin ».
+Les alertes infras se terminent par une alerte StatusCake sur le « endpoint » applicatif HTTP configuré.
+Nous notifions à notre client le début de l'incident et le début d'analyse pour remédiation.
+Elles sont systématiques en cas d'incident et consistent en une checklist assez simple:
+En seconde étape nous procédons à une première analyse des « graphs » sur quelques unes des instances applicatives:
+ +Pour autant les instances n'apparaissent pas « chargées » outre mesure.
+Sur l'ensemble des instances nous ne constatons pas d'augmentation de la consommation des ressources, de même le traffic n'explose pas, nous ne sommes donc pas dans le cas d'un afflux massif de connexions (légitimes ou non d'ailleurs), ni d'une charge anormale du à un script mal conçu.
+Nous disposons toutefois d'un premier indice au niveau réseau, puisque nous constatons une augmentation des connexions « ouvertes » et une chute flagrante des connexions en attente de fermeture.
+Nous avons également constaté que les médias applicatifs sont bien disponibles et que nous n'avons pas de coupure vers les espaces de stockage distants.
+À ce stade nous avons donc une infra fonctionnelle mais une application « dans les choux ». +Nous tentons une première approche en redémarrant les services PHP-FPM sur l'ensemble des instances, ceux-ci se retrouvent rapidement à nouveau saturés et hors service, comportement qui semble confirmer un souci d'ordre applicatif.
+Il est temps d'aller jeter un oeil aux logs applicatifs qui donnent rapidement un résultat puisque nous avons l'erreur suivante:
+SQLSTATE[HY000]: General error: 2006 MySQL server has gone away at XXXXXXX
+Nous avons donc bien une perturbation au niveau de la connectivité entre les instances applicatives et les instances de base de données, reste à déterminer la raison !
+À ce stade nous prenons contact avec l'équipe de développement applicatif afin de disposer de sa connaissance métier et fonctionnelle.
+Nous poursuivons nos investigations à l'aide de nos métriques infra / applicatif plus spécifiquement sur le réseau privé, zone d'échange entre les instances applives et données pour y trouver ceci:
+ + + +Enfin du concret ! On constate à l'aide de ces deux graphs une volumétrie de données d'échange anormalement élevée entre les instances applicatives et les instances de base de données.
+Constat:
+On constate surtout que cette volumétrie vient saturer la bande passante avec un bel « effet plafond » du graph concerné (3).
+Nous avons donc la cause de l'incident à savoir, la saturation de la bande passante entre les instances applicatives et les instances de base de données, ce qui conduit à une grosse attente au niveau PHP-FPM qui se retrouve dans l'incapacité de prendre de nouvelles connexions entrantes.
+Au passage, on voit ici l'importance de « caper » le nombre de connexions maximum que l'on autorise à PHP-FPM, dans le cas ou ce travail n'est pas et/ou mal fait ou si aucun seuil n'est fixé, nous pouvons avoir potentiellement une perte complète de la connectivité à l'instance applicative qui peut impacter de manière significative le temps de rétablissement.
+Nous avons l'origine du blocage, il nous faut à présent comprendre d'où cela vient, nous passons donc du côté serveur de base de données.
+Afin d'identifier d'éventuelles requêtes problématiques nous jouons un SHOW PROCESSLIST
sur notre serveur de base de données et isolons les requêtes en cours d'exécution depuis plusieurs secondes.
+En rejouant l'une de ces requêtes nous constatons qu'elle est anormalement volumineuse (taille supérieure à 5Mo).
Plus spécifiquement elle « ramène » un champ d'une table bien précise et après échange avec les équipes applicatives il correspond à l'ajout d'un « relativement nouveau » fonctionnel, relativement parce qu'il a tout de même quelques semaines mais n'a, à priori pas été utilisé tout de suite par les utilisateurs finaux.
+Le champ en question permet de stocker du contenu libre saisi par l'utilisateur à l'aide d'un éditeur de contenu (À ce moment là, certain(e)s d'entre vous doivent avoir une idée de ce qu'il se passe ;)).
+Nous décidons de passer la publication concernée en « draft »... ce qui est sans influence directe sur la saturation de la bande passante.
+Nous élargissons notre champ de recherche, cette fois-ci en recherchant les lignes disposant d'un champ de contenu dont la taille est supérieure au Mo (SELECT id ... WHERE CHAR_LENGTH(content) > 10000
), pour finalement identifier une centaine de lignes présentant la même problématique.
Vu la gravité de la situation (indisponibilité complète de l'application) et en concertation avec les équipes applicatives nous « dépublions » l'ensemble des contenus problématiques ce qui a pour effet de faire revenir les échanges de données à un seuil normal et de facto rendre à nouveau disponible l'applicatif.
+Dans le même temps les équipes applicatives auront préparé un « quick fix » désactivant la fonctionnalité, le temps de la retravailler.
+Il s'avère que l'application proposait un module de publication à ses utilisateurs embarquant un éditeur de contenus riches qui autorisait l'insertion d'images directement dans les contenus HTML (sans passer par un stockage sur le système de fichiers et donc directement en base de données). +Cerise sur le gateau, nous sommes en 2023 et les images « brutes » pèsent souvent plusieurs Mo.
+Ce cas est une parfaite illustration de ce que l'on peut avoir comme incident avec une application web, bien que l'origine soit assez sournoise, en effet il n'est pas déclenché par une mise à jour récente mais par un fonctionnel développé il y a plusieurs semaines, mais mis en avant que récemment. +De plus, en première lecture, il n'y a pas d'incident apparent, ni charge anormale des instances, ni pépin réseau.
+Les logs applicatifs permettent de s'orienter vers une cause probable de l'indisponibilité mais ne sont pas suffisants pour identifier de manière précise son origine, c'est leur corrélation avec la lecture des métriques qui permet de gagner énormément de temps sur le diagnostic et ainsi cerner le problème.
+Les équipes applicatives sont un renfort précieux, pour dans un premier temps, fournir les informations de dernières mises à jour ou d'arrivée de nouveau fonctionnel (et surtout de mettre en relation un fonctionnel et un schéma de données) et dans un second temps pour corriger (même temporairement) le code, afin d'éviter une rechute inévitable.
++ Une typo ? + Modifier cet article sur Github +
+Tour d'horizon de ce qu'on a pour faire de beaux articles. Et quelques bonnes pratiques de rédaction.
+1 page = 1 titre principal h1
.
Dans le blog, le h1
est le titre de l'article. Dans le corps de l'article, on commence donc par des h2
.
Le sommaire permet d'afficher les h2
et les h3
présents dans l'article. Selon le besoin, précisez le niveau de titre à faire figurer au sommaire.
tableOfContent: true
+# identique à:
+# tableOfContent: 2
+ou
+tableOfContent: 3
+Nous avons des paragraphes, des liens, parfois du code inline
.
++Nous avons aussi des citations. +- Jane Doe
+
Un coup sur deux, on a un style différent de citation, sinon on s'ennuie.
+++Quoi ? Un deuxième style de citation ? Eos officia, vel corporis eaque architecto eveniet voluptatibus, ullam impedit excepturi quis quidem sint facere laboriosam harum error esse iusto. Asperiores, placeat. +John Doe
+
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod +tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, +quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo +consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse +cillum dolore eu fugiat nulla pariatur.
+Titre
+
+ Nous avons des admonition
pour les informations à faire ressortir.
+
Excepteur sint occaecat cupidatat non +proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+Titre
++ Le même composant dans le style "success". +
+Excepteur sint occaecat cupidatat non +proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+Titre
++ Le même composant dans le style "danger". +
+Une image (qui a du sens, ça n'inclut pas les gifs rigolos) a toujours une légende, et si possible on crédite son auteur·ice.
+ +<figure>
+ <img src="./../../images/blog/styleguide/photo.png" alt="photo de ...">
+ <figcaption>
+ <span class="figure__legend">Photo de ...</span>
+ <span class="figure__credits">Crédit photo : <a href="">Nom de l'auteur</a></span>
+ </figcaption>
+</figure>
+Lorem ipsum, dolor sit amet consectetur adipisicing elit. Non natus laborum optio provident, ad dolore molestiae ea, labore quo mollitia eaque iste accusantium similique fugit voluptatem nisi asperiores facilis consectetur.
+Lorem ipsum, dolor sit amet consectetur adipisicing elit. Non natus laborum optio provident, ad dolore molestiae ea, labore quo mollitia eaque iste accusantium similique fugit voluptatem nisi asperiores facilis consectetur.
+Lorem ipsum, dolor sit amet consectetur adipisicing elit. Non natus laborum optio provident, ad dolore molestiae ea, labore quo mollitia eaque iste accusantium similique fugit voluptatem nisi asperiores facilis consectetur.
+Lorem ipsum, dolor sit amet consectetur adipisicing elit. Non natus laborum optio provident, ad dolore molestiae ea, labore quo.
+<div class="side-image">
+ <div class="side-image__content">
+ <p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Non natus laborum optio provident, ad dolore molestiae ea, labore quo mollitia eaque iste accusantium similique fugit voluptatem nisi asperiores facilis consectetur.</p>
+ </div>
+ <figure>
+ <img src="https://upload.wikimedia.org/wikipedia/commons/b/bc/Juvenile_Ragdoll.jpg">
+ <figcaption>
+ <span class="figure__legend">Légende</span>
+ <span class="figure__credits">Crédit photo</span>
+ </figcaption>
+ </figure>
+</div>
+ou si l'image n'a pas besoin de légende / crédit :
+<div class="side-image">
+ <img src="content/images/blog/styleguide/exemple-image.jpg">
+ <div class="side-image__content">
+ <p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Non natus laborum optio provident, ad dolore molestiae ea, labore quo mollitia eaque iste accusantium similique fugit voluptatem nisi asperiores facilis consectetur.</p>
+ <p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Non natus laborum optio provident, ad dolore molestiae ea, labore quo.</p>
+ </div>
+</div>
+Pour les autres images, utilisez simplement la syntaxe Markdown classique (cf sections suivantes).
+Les images inclues dans un contenu sont automatiquement adaptée et fournies en version rétina et non-rétina lorsque cela le permet.
+![Image d'exemple depuis la racine du projet](content/images/blog/styleguide/exemple-image.jpg)
+![Image d'exemple en relatif](./../../images/blog/styleguide/exemple-image-relative.jpg)
++ Les GIFs ne peuvent être redimensionnés mais peuvent tout de même être référencés +
+![Test gif](./../../images/blog/styleguide/exemple-gif.gif)
+Pensez à préciser dans le markdown le langage dans lequel est votre code, si vous voulez des couleurs ! 🌈
+<html>
+ <head></head>
+ <body>
+ Oups
+ </body>
+</html>
+<html>
+ <head></head>
+ <body>
+ C'est mieux
+ </body>
+</html>
+Comme toujours, on essaie tant que possible de choisir des photos libres de droit et d'en créditer les auteurs. Quelques sites de photos libres de droit : Unsplash (chouchou ❤️), Pexels, etc.
+Pour créditer l'auteur de la photo de couverture, renseignez la clé credits
dans le header de l'article :
credits: { name: 'Jane Doe', url: 'https://unsplash.com/@janedoe' }
+,
et .
ne sont précédés d'aucune espace ;!
, ?
, ;
, :
, «
, »
sont toujours entourés de deux espaces ;…
et non 3 points à la suite ...
. Sur Mac, ⌥ alt + .« »
. Sur Mac, ⌥ alt + è et ⌥ alt + ⇧ maj + è. Souvent, les abréviations officielles sont assez méconnues. En voici quelques-unes :
+Une abréviation est suivie d’un point, sauf :
+N. B.
Le séparateur de millier est l’espace insécable, le séparateur de décimale est la virgule.
+Exemple : « Le solde est de 3 586,12 euros ».
Les items d'une liste à puces commencent toujours avec une majuscule et finissent par un point-virgule, sauf le dernier qui se termine par un point.
+Exemple :
+Pour se sentir mieux :
N. B. : la règle étant à la base pour l'édition de documents imprimés, il est admis pour les présentations et interfaces web de ne pas surcharger et de ne pas suivre la règle des ponctuations de liste. Mais si vous souhaitez en mettre, c'est cette règle qu'il faut suivre.
+Les items d'une liste numérotée commencent toujours avec une majuscule et finissent par un point.
+Exemple :
+Les valeurs d'Elao sont :
Quand on fait une liste qui se termine par "etc", celui-ci est précédé d'une virgule et suivi d'un point. Il n'est JAMAIS suivi de points de suspension "etc...".
+Exemple : « Pensez à acheter des fruits : pommes, bananes, clémentines, etc. »
.
à un titre ;:
après un titre ou un label
de formulaire, puisqu'ils introduisent toujours leur sujet, c'est redondant ;et
ne doivent jamais être précédés d'une virgule, sauf dans des cas exceptionnels comme l'énumération ;Si vous souhaitez être inclusif·ve dans votre rédaction, voici quelques solutions possibles pour que cela reste lisible en fonction du contexte :
+Exemple 1 : « Chaque employé et employée doit faire sa demande de congés sur Lucca. »
+Exemple 2 : « Bonjour à toutes et à tous ! »
Exemple 1 : « Chaque employé·e doit faire sa demande de congés sur Lucca. »
+Exemple 2 : « Bonjour à tou·te·s ! »
Pour faire un point médian :
+Sur Mac : ⌥ alt + ⇧ maj + F ;
+Sur PC : Alt+0183 ou Alt+00B7.
Exemple 1 : « L'ensemble de l'équipe doit faire sa demande de congés sur Lucca. »
+Exemple 2 : « Bonjour tout le monde ! »
Il est à votre discrétion d'utiliser la formule la plus adaptée en fonction du contexte.
+Quelques ressources intéressantes :
+Commenter
++ Des commentaires ? + + Poursuivons la discussion sur twitter ! + +
+ ++ Une typo ? + Modifier cet article sur Github +
+Ces données ne sont accessibles et manipulées que par les employé·e·s Rix.
++ L'ensemble des documents transmis par nos correspondants sont conservés sur un stockage privé, hébergé par en France 🇫🇷. + Dans le cas de correspondances écrites (courriels) ils sont stockés en Suisse 🇨🇭. +
+Il est possible de chiffrer les correspondances envoyées à contact@rix.fr à l'aide de notre clé publique.
+Elles sont stockées sur nos serveurs, en France, qu'il s'agisse de données collectées lors de votre passage sur nos sites, ou de données collectées lors de l'une de nos correspondances.
+Consultez le site de la CNIL pour plus d’informations sur vos droits.
+ +Pour exercer ces droits ou pour toute question sur le traitement de vos données dans ce dispositif, vous pouvez nous contacter: contact@rix.fr
+ Si vous estimez, après nous avoir contactés, que vos droits « Informatique et Libertés » ne sont pas respectés, vous pouvez adresser une réclamation à la CNIL. + +
+ Une typo ? + Modifier cet article sur Github +
+