Le toil a une définition précise, pas juste « pénible »
Le toil a une définition précise : travail manuel, répétitif, automatisable, tactique et sans valeur durable, les critères qui décident quoi automatiser en premier.
Des pipelines qui déploient sans suspense : CI/CD industrialisé, livraisons reproductibles et réversibles, outillage de plateforme qui survit au départ de son auteur. Ici, l'automatisation se juge à l'ennui qu'elle produit les jours de mise en production.
Ces sujets, je les traite aussi en mission : Industrialisation CI/CD.
Pour lire ces articles dans l'ordre plutôt que par date : Le socle Linux · La chaîne CI/CD.
Le vocabulaire du domaine : Canary deployment · Drift (dérive d’infrastructure) · Expand/contract (migration de schéma) · Feature flag · GitOps · Infrastructure as Code (IaC) · OIDC / Workload Identity Federation · Pipeline CI/CD (intégration et déploiement continus) · SBOM (Software Bill of Materials) · tout le glossaire.
Le toil a une définition précise : travail manuel, répétitif, automatisable, tactique et sans valeur durable, les critères qui décident quoi automatiser en premier.
Toil is manual, repetitive, automatable, tactical work with no enduring value, the precise criteria that decide what to automate first.
Atlantis verrouille un répertoire Terraform contre deux PR concurrentes. Ce verrou n'a rien à voir avec le lock d'état Terraform, un mécanisme indépendant.
Atlantis locks a Terraform directory against two concurrent PRs. That lock has nothing to do with Terraform's own state lock, an independent mechanism.
Backstage centralise la découverte des services, mais sa valeur dépend de catalog-info.yaml. Sans propriétaire clair, le catalogue diverge de la réalité.
Backstage centralizes service discovery, but its value depends on how fresh catalog-info.yaml stays. Without a clear owner, the catalog silently drifts from reality.
A script killed mid-execution leaves a temp file or lockfile behind, unless trap catches the signal first. SIGKILL remains impossible to intercept.
A server whose clock drifts by a few minutes silently rejects valid TLS certificates. chronyc tracking reveals in one command what nobody actually monitors.
cloud-init ne s'exécute qu'une fois par instance, un état tracké localement. Cloner une VM sans l'effacer fait croire à cloud-init qu'il a déjà tourné, clés SSH dupliquées à la clé.
Un crash sans core dump n'est pas un mystère : ulimit -c vaut 0 par défaut, et systemd ignore souvent /etc/security/limits.conf pour cette limite.
A crash with no core dump isn't always a mystery: ulimit -c defaults to 0 on most distros, and systemd often ignores /etc/security/limits.conf.
Un serveur dont l'horloge dérive de quelques minutes rejette silencieusement des certificats TLS valides. chronyc tracking révèle en une commande ce que personne ne surveille.
Could not get lock pousse à supprimer le verrou directement. Vérifier quel processus le détient d'abord évite une base de paquets corrompue.
Could not get lock pushes toward deleting the lock directly. Checking which process holds it first avoids a corrupted package database.
Flyway impose des scripts SQL versionnés, Liquibase ajoute un changelog agnostique du SGBD et un rollback déclaratif. Le vrai critère n'est pas lequel est meilleur.
Flyway enforces versioned SQL scripts, Liquibase adds a DB-agnostic changelog and declarative rollback. The real deciding factor isn't which one is better.
Un périphérique listé dans fstab mais absent au boot peut bloquer tout le démarrage. L'option nofail existe pour ça.
A device listed in fstab but absent at boot can block the machine's entire startup. The nofail option exists for this.
Un hard link partage le même inode que l'original, un symlink pointe vers un chemin. C'est pourquoi l'un survit à la suppression de l'original, l'autre non.
A hard link shares the same inode as the original, a symlink points to a path. That difference explains why one survives deleting the original and the other doesn't.
df continue d'afficher l'ancienne taille après un lvextend réussi : agrandir un volume logique LVM ne redimensionne jamais automatiquement le système de fichiers qu'il contient.
df still shows the old size after a successful lvextend: growing an LVM logical volume never automatically resizes the filesystem it contains.
Une commande lancée avec & tourne en arrière-plan mais meurt quand même à la fermeture du terminal : le shell envoie SIGHUP à ses enfants. nohup et disown évitent ça.
Une résolution de nom incohérente entre deux machines pointe souvent vers nsswitch.conf, pas vers le DNS : il définit l'ordre des sources pour hosts, passwd et group.
Inconsistent name resolution between two machines often points to nsswitch.conf, not DNS itself: it defines the order sources are checked for hosts, passwd, and group.
Packer builds an immutable image once on a temporary machine. cloud-init configures each instance at its first boot. Confusing the two breaks the pipeline.
Packer construit une image immuable une fois sur une machine temporaire. cloud-init configure chaque instance à son premier démarrage. Les confondre casse le pipeline.
Un processus zombie est déjà mort. Lui envoyer SIGKILL ne fait rien : la vraie cause est un parent qui n'a jamais récupéré son code de sortie.
Puppet resolves a dependency graph before executing, Ansible runs tasks in the order they're written. A line-by-line port loses that implicit resolution.
Puppet résout un graphe de dépendances avant d'exécuter, Ansible exécute les tâches dans l'ordre écrit. Un portage ligne à ligne perd cette résolution implicite.
chmod and chown are correct, yet Permission denied persists. SELinux enforces a second permission system, independent of classic Unix rights: the security context.
chmod et chown corrects, et pourtant Permission denied persiste. SELinux applique un second système de permissions : le contexte de sécurité, indépendant des droits Unix.
Le bit setuid marche sur un binaire compilé mais le kernel l'ignore silencieusement sur un script shell, protection délibérée contre une classe de faille connue.
Écrire dans un répertoire suffit à y supprimer n'importe quel fichier, même d'un autre utilisateur. Le sticky bit sur /tmp casse délibérément cette règle par défaut.
Write permission on a directory normally lets you delete any file inside, even one owned by someone else. The sticky bit on /tmp changes that default rule.
Ajouter du swap aggrave parfois la situation : un système qui thrashe devient inutilisable, souvent pire qu'un processus tué proprement et vite par l'OOM killer.
Adding swap doesn't always buy time before an OOM: a thrashing system becomes unusable, often worse than a process killed cleanly and fast.
/tmp n'est pas nettoyé qu'au reboot : systemd-tmpfiles-clean tourne périodiquement et supprime les fichiers dépassant un âge configuré, reboot ou pas.
/tmp isn't only cleared on reboot: systemd-tmpfiles-clean runs periodically and deletes files past a configured age, reboot or not.
Un script tué en pleine exécution laisse un lockfile derrière lui, sauf si trap intercepte le signal avant. SIGKILL reste impossible à intercepter, quel que soit le trap défini.
Un script fonctionne bien à la main mais crée des fichiers aux permissions différentes lancé par cron. Le coupable est presque toujours un umask différent, pas le script.
A script works fine by hand but creates files with different permissions under cron. The culprit is almost always a different umask, rarely the script.
Editing /etc/sudoers directly risks a syntax error that breaks sudo for everyone, including the person fixing it. visudo validates before writing.
Éditer /etc/sudoers directement risque une erreur de syntaxe qui casse sudo pour tout le monde, y compris pour la corriger. visudo valide avant d'écrire.
cloud-init only runs once per instance, a state tracked locally. Cloning a VM without wiping it makes cloud-init think it already ran, duplicating SSH host keys in the process.
Launching a command with & runs it in the background, but it still dies when the terminal closes: the shell sends SIGHUP to its children. nohup and disown prevent that.
The setuid bit works on a compiled binary but the kernel silently ignores it on a shell script, a deliberate security protection against a known exploit class.
A zombie process is already dead. Sending it SIGKILL does nothing: the real cause is a parent that never collected its exit status.
Une tâche cron qui échoue ne le dit à personne par défaut. Un systemd timer hérite du Restart et de l'historique journalctl du service qu'il déclenche.
A failing cron job doesn't notify anyone by default. A systemd timer inherits the Restart behavior and journalctl history of the service it triggers.
No space left on device while df -h shows 40% free isn't a contradiction: it's never disk space that's exhausted, it's inodes, a distinct and equally finite resource.
No space left on device alors que df -h affiche 40% de libre : ce n'est jamais l'espace disque qui manque, ce sont les inodes, une ressource distincte et finie.
nftables est le défaut depuis des années, mais une couche de compatibilité fait tourner les anciennes règles iptables sans jamais forcer leur migration.
nftables has replaced iptables by default on most distributions for years, but a compatibility layer keeps old rules running without ever truly migrating them.
A disk filling up with no visible file explaining the space often hides a log renamed by rotation, but still open by a process writing into thin air.
Un disque qui se remplit sans qu'aucun fichier visible ne l'explique cache souvent un log renommé par rotation, mais toujours ouvert par un processus qui écrit dans le vide.
set -e n'arrête jamais un script à l'intérieur d'un if ni d'une condition &&. Comprendre les trois options séparément évite le faux sentiment de sécurité.
What set -euo pipefail actually means, flag by flag: set -e never catches an error inside an if or an && condition, and each flag catches something else.
Restart=on-failure ne suffit pas à empêcher un service de boucler indéfiniment. StartLimitBurst est le vrai coupe-circuit, souvent jamais réglé.
Restart=on-failure alone doesn't stop a service from looping forever. StartLimitBurst is the real circuit breaker, and it's rarely configured explicitly.
Augmenter ulimit -n dans limits.conf ne change rien pour un service systemd : LimitNOFILE= dans l'unité prime totalement sur les limites PAM classiques.
Raising ulimit -n in /etc/security/limits.conf changes nothing for a systemd service: LimitNOFILE= in the unit completely overrides classic PAM limits.
Un hook Helm s'exécute en dehors de la release qu'il accompagne. helm rollback ne le rejoue jamais, ce qui casse le principe même du rollback si on ne le sait pas.
A Helm hook runs outside the release it accompanies. helm rollback never replays it, which breaks the whole point of rollback if you don't know that.
Un module Terraform n'a pas son propre state : il partage celui du module racine. Ce détail structurel change tout ce qu'on peut faire avec, et casser.
A Terraform module doesn't have its own state: it shares the root module's. That structural detail changes what you can do with it, and break.
Des environnements éphémères par pull request, créés et détruits automatiquement, résolvent un vrai problème de revue. Ce que ça coûte en isolation, et le piège du nettoyage qui ne se fait jamais.
A full ephemeral environment per PR, provisioned and torn down automatically, solves a real review problem. What it costs in isolation, and the cleanup that never fires.
Terraform provisions infrastructure, Ansible configures it. The confusion comes from a real but partial overlap, not an actual choice to make.
Terraform provisionne l'infrastructure, Ansible la configure. La confusion vient d'un chevauchement réel mais partiel, pas d'un vrai choix à trancher.
Signer une image prouve qu'elle vient de votre pipeline, pas comment le pipeline l'a produite. Ce que le framework SLSA ajoute, et à quel niveau viser.
Signing an image proves it came from your pipeline, not how it was built. What the SLSA framework adds, and which level to actually target.
GitHub Actions and GitLab CI look alike in YAML but diverge on what matters: platform portability, built-in features, and real lock-in.
GitHub Actions et GitLab CI se ressemblent en YAML mais divergent sur ce qui compte : portabilité de la plateforme, fonctionnalités intégrées, verrouillage.
Terraform catches drift at the next plan, whenever someone remembers to run it. Crossplane fixes it continuously, using the same loop that already manages pods.
Terraform détecte la dérive au prochain plan, quand quelqu'un pense à l'exécuter. Crossplane la corrige en continu, via le même mécanisme qui gère déjà les pods.
Un canary réussi sur un cluster ne garantit rien sur les autres régions. Comment orchestrer un rollout progressif entre clusters, vague par vague.
A successful canary on one cluster guarantees nothing about the others. How to orchestrate a progressive rollout across clusters, wave by wave.
Why a monorepo that rebuilds everything on every commit stops scaling, how a dependency graph determines what actually changed, and the remote-cache hash trap.
Pourquoi un monorepo qui teste tout à chaque commit ne scale pas, comment un graphe de dépendances détermine ce qui a changé, et le piège du cache mal invalidé.
Le choix d'un outil IaC ne se résume pas à une préférence de syntaxe. Licence, écosystème de providers, et le vrai coût d'une migration une fois engagé.
Choosing an infrastructure-as-code tool isn't really a syntax preference. License, provider ecosystem, and the real cost of migrating once you're committed.
A dependency never updated becomes a security debt that accumulates silently. Renovate and Dependabot both automate updates, but not the same way.
Une dépendance jamais mise à jour devient une dette de sécurité qui s'accumule en silence. Renovate et Dependabot automatisent la mise à jour, pas la même façon.
Why a replayed playbook should change nothing, how check mode lies about shell-based modules, and a simple rule for sorting your Ansible tasks.
Pourquoi un playbook rejoué ne devrait rien changer, comment le check mode ment sur les modules à commande shell, et une règle simple pour trier ses tâches.
A runner hosted by GitHub or GitLab can never reach your internal network. The choice between self-hosted and hosted isn't primarily a cost question.
Des runners CI hébergés par GitHub ou GitLab ne peuvent jamais atteindre votre réseau interne. Le vrai calcul n'est pas d'abord une question de coût à la minute.
Un cache Docker mal ordonné invalide tout à chaque commit, peu importe le backend. Ce qui détermine réellement le taux de cache hit en CI, avant même BuildKit.
A badly ordered Docker cache invalidates everything on every commit, regardless of backend. What actually determines cache hit rate in CI, before BuildKit even matters.
Comment un rollout canary se déclenche et se juge depuis le pipeline via Prometheus, et pourquoi déploiement et release ne sont pas le même événement.
How a canary rollout gets triggered and judged automatically from the pipeline using Prometheus metrics, and why deployment and release are not the same event.
Vulnerability scanning as a pipeline gate, keyless image signing with cosign, SBOM generation, and verifying signatures at admission before an image runs.
Scan de vulnérabilités en garde-fou de pipeline, signature keyless des images de conteneurs avec cosign, SBOM et vérification à l'admission Kubernetes.
How CI secrets leak from a masked variable, why masking isn't a security boundary, and how OIDC federation replaces long-lived keys with short-lived tokens.
Comment un credential cloud dans la CI finit par fuiter, pourquoi masquer une variable n'est pas une frontière de sécurité, et ce que change l'identité fédérée.
Pourquoi rebuilder par environnement empêche de garantir qu'on déploie ce qu'on a testé, comment marche la promotion par digest, et le piège du tag flottant.
Why rebuilding per environment cannot guarantee you deploy what you tested, how artifact promotion by digest works, and the floating-tag trap.
How to sequence a database migration job ahead of a rollout, the expand/contract pattern for zero-downtime changes, and why rollback is often a myth.
Comment ordonnancer les migrations de schéma avant un rollout, le pattern expand/contract pour rester compatible, et pourquoi le rollback est souvent un mythe.
How Deployment revisions map to ReplicaSets, what kubectl rollout undo actually restores, why GitOps prefers a Git revert, and the gotchas around rollbacks.
Comment les révisions d'un Deployment correspondent aux ReplicaSets, ce que kubectl rollout undo restaure vraiment, et pourquoi GitOps préfère un revert Git.
Kubernetes Secrets are base64, not encryption. How Sealed Secrets make manifests git-safe, when external Vault earns its cost, and how to choose.
Les Secrets Kubernetes sont du base64, pas du chiffrement. Comment Sealed Secrets rend un manifeste committable, quand Vault vaut son coût, comment choisir.
Why local Terraform state breaks a team, how remote backends and state locking work on S3, GCS and HCP, and how to recover from a stale lock safely.
Pourquoi le state local casse en équipe, comment marchent les backends distants et le verrouillage, et comment récupérer proprement d'un verrou bloqué.