2022: bash n'est toujours pas une bonne idée pour l'administration système
Mon article Trop de shell pour l’administration système: une mauvaise idée ? est probablement un de mes articles les plus populaires. Je reviens dans ce nouvel article sur pourquoi je pense que bash (et le shell de manière générale) n’est pas un bon outil pour les besoins d’aujourd’hui.
Pourquoi vous ne devez pas utiliser bash
Je me suis rendu compte que mon premier article sur sujet avait généré quelques incompréhensions. Il est je pense important de reparler rapidement de pourquoi on fait de l’administration système. Je vous recommande pour cela la lecture de mon article L’important n’est pas la technologie mais la plateforme qui explique bien ma vision actuelle sur ce qui doit être mis en place en entreprise.
L’idée principale dans cet article est qu’en tant qu’admin système on doit maintenir un certain nombre d’applications (au sens large) en production. Nous souhaitons également pouvoir facilement administrer notre production, par exemple:
-
Pouvoir facilement et de manière répétable déployer, configurer et mettre à jour des applications
-
Réaliser un certain nombre de tâches de manière fiable (backups par exemple)
-
Pouvoir détecter les problèmes et y remédier
-
Avoir une infrastructure pouvant s’adapter à de nouveaux besoins, que ce soit l’ajout de nouvelles applications, avoir de la tolérance aux pannes, pouvoir "scale" en cas de croissance de l’entreprise ou de pic de charge soudain…
De plus, nous ne faisons pas de l’administration système pour la beauté du geste. Dans de nombreuses entreprises des équipes de développement se chargent de développer des applications qui seront ensuite déployées sur l’infrastucture. Ces personnes ne sont pas des admin système mais doivent être autonomes pour déployer des changements et opérer leurs applications. Cela se traduit dans le cas d’équipes de développement par l’autonomie de ces équipes pour créer et déployer des applications, gérer leurs métriques, alertes, accéder à leux logs… Bref, faire leur travail de manière efficace.
On construit donc une plateforme qui est ensuite mise à disposition d’utilisateurs. Fin du résumé, lisez l’article pour avoir plus d’informations.
Et bash dans tout ça ?
Nous devons donc gérer cette infrastructure. Et comme dit précédemment, de manière fiable.
Comme décrit dans l’article dont j’ai donné le lien précédemment il y a plusieurs méthodes pour faire cela. Des outils comme Ansible, Puppet ou Terraform peuvent aider. D’autres, comme Kubernetes par exemple, sont également une solution. Tout dépend des besoins et il est commun d’utiliser plusieurs outils pour plusieurs besoins, et à différentes étapes de provisioning de notre plateforme.
Au delà des technologies ce sont les concepts derrière ces outils qui sont importants: cloud, API first, boucles de réconciliation, infrastructure as code, auto healing, autoscaling, rolling restart…
On se rend également compte rapidement que tous les outils cités précédemment et le cloud en général sont des logiciels. Ce sont des programmes qui vont piloter l’infrastructure pour que nous humains, peu fiables par nature et dont le temps est trop précieux pour aller s’embêter à faire des actions répétitives, n’ayons pas à le faire. Lorsqu’un nouveau besoin se fait sentir, qu’une nouvelle abstraction est nécessaire, nous allons soit utiliser ces outils pour automatiser des choses et créer notre abstraction soit nous allons la développer nous même (création d’API, de CLI, de programmes réagissant à des événements…).
On se retrouve donc en tant qu’admin sys à devoir écrire du code (des scripts mais cela va souvent plus loin), même si l’on s’appuie sur les outils cités précédemment. On veut même parfois les étendre voir pouvoir y contribuer.
Ces programmes peuvent également souvent s’utiliser dans différents contextes. Le même script de backup pourrait par exemple être lancé manuellement depuis le poste de travail, déployé sur un serveur et tourner via un cronjob, ou déployé dans un conteneur tournant sur Kubernetes avec une ressource de type CronJob
.
Est ce que le bash/Shell est un bon langage pour construire ces outils et scripts ?
Pourquoi bash n’est pas un bon outil
J’ai déjà mentionné un certain nombre de limitations à bash dans mon premier article sur le sujet. Mais au final tout peut se résumer à un point: quand on fait du logiciel (ce qu’est un script), on fait de l’ingénierie logicielle et non du bricolage. On veut de la qualité. Et pour cela, on applique les bonnes pratiques de développement comme n’importe quel développeur. Et bash n’est tout simplement pas bon à cela.
Gestion des dépendances
Arrêtons s’il vous plaît de comparer source
en bash avec un vrai système de gestion de dépendances supportant:
-
Gestion des versions des dépendances (avec gestion des dépendances transitives, fichiers
.lock
…) -
L’utilisation de dépôts pour ces dépendances avec tout ce que cela implique (caching, checksums, partage entre projets…)
-
Outillage pour gérer ces dépendances (build, tests, publication, génération automatique de documentation…)
Ecosystème
C’est bien sûr en lien avec la gestion des dépendances mais pouvoir bénéficier de librairies de qualité (ce qui est le cas dans des langages comme Golang ou Python que l’on retrouve souvent dans l’administration système) est toujouts intéressant. Ecrire une CLI en Golang avec une gestion correcte des commandes et flags (commandes, sous commandes, flags optionnels ou non, répétition de flags, gestion de priorités entre flags et configuration via variables d’environnement… le tout vérifié grâce à du typage statique) se fait assez bien, de manière largement plus simple qu’en bash.
Clients de base de données (SQL, NoSQL…), de cloud, de queues ou logs distribués (RabbitMQ, Kafka…), ou même d’outils comme Kubernetes sont autant de choses très facilement utilisables dans des langages de programmation modernes, et qui ne le sont pas en bash. Vous pourriez certes me citer kafkacat
, la CLI aws
ou kubectl
… mais ce n’est pas du tout le même niveau de confort à l’utilisation, la même fiabilité, ni les mêmes garanties qu’un SDK.
Mais l’écosystème ici va également plus loin. J’aime parler aussi d’écosystème d’entreprise (ou écosystème interne). Pouvoir partager des dépendances entre équipes (que ce soit dev ou ops, car les deux font au final du logiciel) est par exemple super. Cela permet de la même façon à n’importe quelle équipe de contribuer et faire évoluer les outils internes si besoin.
Outillage
J’ai déjà parlé de l’outillage dans la gestion des dépendances. Linter, analyse statique de code, IDE intelligents, outils pour les tests (mocking, framework de tests)… sont autant d’outils dont les équivalents pour le shell sont tout justes passables.
Logs
Logs structurés, gestion simplifiée de la verbosité via l’utilisation de logger globaux, possibilité de passer simplement sans changer le code, mais seulement la configuration du logger, sur des formats de sortie différents (texte, json…). C’est ça qu’on veut aujourd’hui.
Des intégrations comme Sentry sont également très intéressantes et facilitées avec des langages autres que bash, notamment par l’utilisation de librairies fournies directement par l’éditeur ou par la construction d’abstractions au dessus d’une librairie de logging.
Gestion des erreurs
Comment peut-on comparer les erreurs de bash (utilisation de set
, de code de retours…) et des systèmes d’erreurs modernes présents dans les langages de programmations ? Type Result
ou Error
, exceptions, classification d’erreurs, vérification statique que toutes les erreurs sont correctement gérées… Comparer les deux n’est pas pertinent et montre vraiment un manque d’expérience en développement.
Métriques
Je parlais dans mon premier article sur le shell des métriques. Cela a souvent été interprété en mode "lol en shell on a time
a on a une variable qui donne le temps d’exécution du script". Raisonner comme cela montre une certaine incompréhension des bonnes pratiques de monitoring.
Nos scripts ont souvent besoin de faire des I/O: appels HTTP divers, interactions avec des services SaaS, actions sur le système de fichier ou avec des bases de données par exemple. Comment dit précémmement nous essayons toujours de réutiliser ces scripts dans différents contextes, voir de fournir en tant que librairie externe certaines fonctionnalités.
Les systèmes de monitoring modernes supportent plusieurs types de métriques: gauges, histogrammes, counter… permettant ensuite de dériver de nombreuses autres métriques: rates (requêtes par secondes) ou quantiles (p99, p95…sur des I/O) par exemple. Ces systèmes supportent également l’ajout de labels
sur les métriques.
Nous avons besoins de métriques dans nos programmes, comme par exemple:
-
Le temps d’exécution global d’un script. Plusieurs labels peuvent être attachés à cette métrique. Prenons par exemple le cas d’un script de backup: nous pourrons avoir des labels de type
environnement
(staging, production…),database
(nom de la base de données à backup),datacenter
(nom du datacenter où se trouve la base de données)… Bref, on veut du contexte sur nos métriques. -
Temps d’exécution des I/O: certains scripts peuvent prendre du temps. Par exemple, un script lancé toutes les heures pourrait exécuter un grand nombre de requêtes HTTP vers différents services pour réaliser des actions. Monitorer le temps d’exécution de chaque appel correctement (avec un histogramme permettant ensuite de dériver des quantiles sur plusieurs exécutions) peut être intéressant. Là aussi, l’ajout de labels est important (ne serait-ce que pour organiser les mesures par bucket comme c’est le cas dans certains systèmes de monitoring comme Prometheus). Rappelez vous aussi ce que j’ai énoncé précédemment: l’utilisation et le partage de librairies pour ce genre de besoins est encouragé, et donc la gestion des métriques est prévue et ajoutée directement au niveau de notre dépendance.
-
On veut s’intégrer avec les outils du marché (par exemple Prometheus et push gateway, services de monitoring cloud …).
Ici, bash ne tient pas aussi la comparaison.
On en revient au développement
J’ai cité précédemment quelques points importants, mais d’autres le sont encore plus.
Le nerf de la guerre aujourd’hui est la donnée. On interagit en permanence avec des données de tout types. Fichiers de configuration, payload de requêtes et réponses HTTP, résultat de requêtes à des bases de données…. nos scripts et programmes travaillent avec de la donnée, en entrée et en sortie.
Bash n’est pas un bon outil pour travailler avec de la donnée: structures de données limitées et avec peu de fonctionnalités built-in pour interagir avec ces données (itérations, map, reduce, filter…), pas de façons simples de représenter des données (typage fort, structure de données immuables par exemple), ou de la sérialisation et désérialisation des données (mapping entre des types et des données en json ou YAML, gestion de valeurs optionnelles, validation métiers sur les données). Il faut vraiment aimer se donner du travail pour vouloir utiliser bash pour tout besoin un peu sérieux demandant interaction avec des systèmes externes.
On pourrait également parler du threading, d’architecture logicielle, de programmation fonctionnelle, de typage statique… Bref, de sujets familiers aux développeurs. J’ai souvent entendu dire par les fan du bash "je ne veux pas apprendre à coder donc je fais du bash". Je traduis personnellement cela par "je refuse de m’imposer une certaine rigueur dans ce que je produis". Bash ne serait donc pas du code ? C’est donc OK d’utiliser des outils peu efficaces dans une tâche donnée car "on a toujours fait comme ça" ? J’ai vraiment du mal à comprendre cette approche.
Et franchement, quelqu’un qui a réussit à maîtriser bash ne devrait pas avoir trop de mal à basculer sur un langage plus évolué qui au contraire lui donnera encore plus de garanties de fiabilité sur ce qui est produit.
Je ne vais pas m’étendre plus sur le sujet du développement car mon but n’est pas non plus d’écrire un article de type "programming 101". Mais répétons le encore une fois: bash n’est pas un bon outil pour développer.
On travaille en équipe, et sur le long terme
C’est également un point important que j’ai déjà mentionné précédemment mais sur lequel il faut insister. Ce que l’on produit n’est pas que pour nous, mais aussi pour notre équipe et pour notre entreprise. Encourager les gens à contribuer à des scripts et programmes, à partager des librairies et faciliter la construction d’un écosystème interne (ou externe via l’open source) est ce qui apportera de la valeur sur le long terme à l’entreprise.
Et ce long terme est important. Car j’ai l’impression dans ce débat "bash vs le reste du monde" que c’est aussi deux visions de l’administration système qui s’affrontent. D’un côté une vision court-termiste, à coup de scripts bash "roulés sous les aisselles" comme j’ai entendu récemment, où le but est d’essayer d’éteindre l’incendie en mode "quick and dirty". Et une vision long terme, basée sur l’ingénierie, la qualité, le travail en équipe, la fiabilité, la reproductibilité des actions, et avec une projection sur les besoins et les évolutions futures de la plateforme. Bash n’a rien à faire dans cette dernière.
Je comprends que bash puisse sembler utile dans certains contextes "entreprises difficiles", mais c’est aussi de notre devoir en tant que professionnel de conseiller et mettre en place des solutions pérennes dans le temps. On a tous des contraintes que je peux comprendre et que parfois faire un truc peu maintenable mais rapidement disponile peut se justifier. Mais cela n’en fait pas une bonne pratique à promouvoir pour autant, plutôt quelque chose à garder en tête et à supprimer lorsque l’occasion s’en présente.
Bash peut être un outil intéressant pour certains petits besoins. Chaîner un kubectl -o json
avec un jq
, utiliser du awk/grep… pour rapidement récupérer une information m’arrive fréquemment. Pour des petits scripts "one shot", qui ne sont jamais réutilisés une fois lancés, pourquoi pas (et encore). Si vous avez quelques commandes simples à lancer dans un script de CI, ça le fait.
Mais c’est tout. N’utilisons pas bash pour de l’administration système long terme ou des systèmes critiques ou complexes.
Change my mind (ce sera compliqué).
Add a comment
If you have a bug/issue with the commenting system, please send me an email (my email is in the "About" section).