Bonnes pratiques ops#

Hide code cell source

import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import matplotlib.patches as patches
import matplotlib.dates as mdates
import numpy as np
import pandas as pd
import seaborn as sns
import datetime

sns.set_theme(style="whitegrid", palette="muted", font_scale=1.1)

Documentation#

Pourquoi documenter#

La documentation est souvent perçue comme une corvée secondaire. En pratique, c’est une assurance collective : celui qui documente aujourd’hui se protège lui-même des appels à 3h du matin dans six mois.

Les trois formes essentielles de documentation opérationnelle sont :

  • Runbooks : procédures pas-à-pas pour les opérations courantes et les incidents. Ils permettent à un collègue moins expérimenté d’intervenir en autonomie.

  • Wikis : documentation de référence (architectures, décisions techniques, contacts, accès). Confluence, Notion, ou un simple dépôt git avec des fichiers Markdown conviennent.

  • README serveur : fichier /etc/motd ou /etc/README décrivant le rôle du serveur, ses contacts, et ses services critiques. Visible à chaque connexion SSH.

Diagrammes d’architecture#

Un diagramme vaut mille commandes ifconfig. Les outils recommandés :

  • draw.io / diagrams.net : gratuit, stockage XML versionnable, intégré à Confluence.

  • Mermaid : diagrammes en Markdown, compatible GitLab/GitHub.

  • PlantUML : infrastructure as diagram, intégrable dans les wikis.

Documentation vivante

Une documentation jamais mise à jour est pire qu’une absence de documentation : elle induit en erreur. Intégrer la mise à jour de la documentation dans la définition de « terminé » pour toute modification d’infrastructure. Un changement non documenté n’est pas terminé.

README serveur automatisé#

# /etc/update-motd.d/10-readme (Debian/Ubuntu)
#!/bin/bash
echo "=== SERVEUR : $(hostname) ==="
echo "Rôle    : Proxy inverse Nginx + Certbot"
echo "Contact : infra@example.com"
echo "Wiki    : https://wiki.example.com/serveurs/$(hostname)"
echo "Dernière mise à jour infra : $(stat -c %y /etc/nginx/nginx.conf | cut -d' ' -f1)"

Gestion des changements#

Change management#

En production, tout changement doit être planifié, communiqué et réversible. Les étapes minimales d’un processus de changement :

  1. Demande de changement (RFC) : description, motivation, impact estimé, plan de rollback.

  2. Revue : validation par un pair ou un responsable.

  3. Fenêtre de maintenance : plage horaire à faible trafic, communiquée aux parties prenantes.

  4. Exécution : avec un observateur si l’impact est élevé.

  5. Vérification : tests fonctionnels post-changement.

  6. Documentation : mise à jour du wiki et du changelog.

Fenêtres de maintenance#

# Notifier les utilisateurs via /etc/motd
echo "MAINTENANCE PLANIFIÉE : dimanche 17/03 02h00-04h00 UTC" \
  >> /etc/motd

# Supprimer après la maintenance
truncate -s 0 /etc/motd

Rollback#

Chaque changement doit avoir un plan de rollback défini avant l’exécution.

  • Configuration nginx : cp /etc/nginx/nginx.conf{,.bak} avant toute modification.

  • Paquets : apt-mark hold <paquet> pour geler une version.

  • Noyau : garder l’entrée GRUB précédente, tester avec reboot + surveillance.

Git pour /etc#

# Initialiser un dépôt git dans /etc
cd /etc
git init
git add .
git commit -m "État initial du serveur web01"

# Ou utiliser etckeeper (automatise les commits avant apt)
apt install etckeeper
etckeeper init

etckeeper crée automatiquement un commit avant chaque opération apt install ou apt upgrade, permettant de retrouver exactement quel paquet a modifié quel fichier de configuration.

Post-mortems#

Culture blameless#

Le post-mortem blameless (sans blâme) est une pratique née chez Google et Etsy. Son principe : les incidents sont des opportunités d’apprentissage, pas des occasions de punir. Lorsque les ingénieurs craignent d’être punis, ils cachent les incidents et n’apprennent pas collectivement.

Un post-mortem blameless part du principe que :

  • Les personnes impliquées ont pris les meilleures décisions possibles avec les informations disponibles à ce moment.

  • L’objectif est de comprendre les causes systémiques, pas de trouver un coupable.

  • Les actions correctives visent le système (monitoring, documentation, automatisation), pas l’individu.

Format standard d’un post-mortem#

# Post-mortem : Indisponibilité base de données (2024-03-14)

## Impact
- Durée : 47 minutes (02h13 — 03h00 UTC)
- Utilisateurs affectés : ~12 000 (toutes les requêtes écritures en échec)
- Revenus estimés : 2 400 €

## Chronologie
- 02h13 — Alerte Prometheus : `pg_up == 0`
- 02h18 — Ingéniaire d'astreinte contacté
- 02h31 — Diagnostic : disque root plein (inode exhausted)
- 02h45 — Libération d'espace (/var/log, pg_log)
- 03h00 — Service restauré, confirmation monitoring

## Causes racines
1. Rotation des logs PostgreSQL non configurée (pg_log non limité)
2. Alerte espace disque seuil 95 % — trop tardif (atteint en 10 min après 90 %)

## Actions correctives
- [ ] Configurer `log_rotation_age = 1d` et `log_rotation_size = 100MB` (J+2)
- [ ] Abaisser le seuil d'alerte disque à 80 % (J+1)
- [ ] Ajouter monitoring des inodes (J+3)
- [ ] Runbook disque plein dans le wiki (J+5)

Hide code cell source

# Timeline d'un post-mortem (Gantt simplifié)

sns.set_theme(style="whitegrid", palette="muted", font_scale=1.1)

base = datetime.datetime(2024, 3, 14, 2, 0)

phases = [
    ("Incident non détecté",       0,   13, "#C44E52"),
    ("Détection + alerte",         13,  18, "#E76F51"),
    ("Prise en charge astreinte",  18,  31, "#F4A261"),
    ("Diagnostic",                 31,  45, "#4C72B0"),
    ("Remédiation",                45,  60, "#55A868"),
    ("Vérification + clôture",     60,  75, "#8172B2"),
]

fig, ax = plt.subplots(figsize=(12, 4))
ax.set_xlim(0, 80)
ax.set_ylim(-0.5, len(phases) - 0.3)
ax.axis("off")
ax.set_title("Timeline post-mortem — Indisponibilité BDD (2024-03-14 02h00 UTC)",
             fontsize=12, fontweight="bold", pad=14)

for i, (label, debut, fin, couleur) in enumerate(phases):
    rect = patches.FancyBboxPatch(
        (debut, i - 0.3), fin - debut, 0.6,
        boxstyle="round,pad=0.05", linewidth=1.0,
        edgecolor="#ffffff", facecolor=couleur, alpha=0.88
    )
    ax.add_patch(rect)
    milieu = (debut + fin) / 2
    ax.text(milieu, i, label, ha="center", va="center",
            fontsize=8.5, color="white", fontweight="bold")
    ax.text(debut, i - 0.42, f"{debut}'", ha="center", fontsize=7.5, color="#555555")

ax.text(75, -0.45, "75'", ha="center", fontsize=7.5, color="#555555")
ax.axvline(47, color="#888888", linestyle="--", linewidth=1.2)
ax.text(47, len(phases) - 0.1, "Service\nrestauré", ha="center", fontsize=8,
        color="#555555", style="italic")

plt.savefig("22_postmortem_timeline.png", dpi=100, bbox_inches="tight")
plt.show()
_images/8a9cbe3ba4235d743b2bc9b9c175860cf42fb84069df8b2547c797e5b019e1c0.png

Gestion des secrets#

Ne jamais committer de secrets#

La première règle de la sécurité des secrets est absolue : aucun secret (mot de passe, clé API, certificat privé, token) ne doit être commité dans un dépôt git, même privé.

# Détecter les secrets avant un commit (outil git-secrets ou trufflehog)
apt install trufflehog
trufflehog git file://. --since-commit HEAD

# Configurer un hook pre-commit
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/bash
if git diff --cached --name-only | xargs grep -lE \
   'password\s*=|api_key\s*=|secret\s*=|token\s*=' 2>/dev/null; then
    echo "ERREUR : secret potentiel détecté dans les fichiers stagés"
    exit 1
fi
EOF
chmod +x .git/hooks/pre-commit

Rotation des secrets#

Tous les secrets doivent être rotés régulièrement :

  • Mots de passe : rotation tous les 90 jours minimum, immédiate en cas de départ d’un collaborateur avec accès.

  • Clés SSH : au moins une fois par an, immédiatement si un poste est compromis.

  • Tokens API : à chaque départ ou en cas d’exposition accidentelle.

  • Clés de chiffrement : selon la politique de sécurité, avec procédure de re-chiffrement des données.

HashiCorp Vault — bases#

Vault est un gestionnaire de secrets centralisé. Il expose une API REST, gère les politiques d’accès et l’audit.

# Démarrer Vault en mode dev (tests uniquement)
vault server -dev

# Stocker un secret
vault kv put secret/db/prod password=MonMotDePasse

# Lire un secret
vault kv get secret/db/prod

# Générer un mot de passe dynamique PostgreSQL (lease 1h)
vault read database/creds/readonly

pass — gestionnaire de secrets local#

# Initialiser avec une clé GPG
pass init "admin@example.com"

# Stocker un secret
pass insert infra/db/prod/password

# Lire
pass infra/db/prod/password

# Synchroniser avec git
pass git init
pass git push

Sauvegarde et restauration#

Tester régulièrement#

Une sauvegarde non testée n’est pas une sauvegarde. La seule façon de savoir qu’une sauvegarde fonctionne est de la restaurer effectivement sur un environnement de test.

Règle 3-2-1

3 copies des données, sur 2 supports différents, dont 1 hors site. Exemple : données en production + sauvegarde BorgBackup locale + réplication sur serveur distant (ou stockage objet S3/Backblaze B2).

RTO et RPO#

  • RPO (Recovery Point Objective) : perte de données maximale acceptable. Une sauvegarde quotidienne implique un RPO de 24h.

  • RTO (Recovery Time Objective) : durée maximale acceptable d’indisponibilité. Un RTO de 4h exige une procédure de restauration testée et documentée.

Ces deux métriques doivent être définies avec les parties prenantes métier, pas unilatéralement par l’équipe technique.

Simulation d’incident de restauration#

# Procédure de restauration BorgBackup (à tester mensuellement)
# 1. Lister les archives disponibles
borg list user@backup-server:/mnt/borg/prod

# 2. Monter une archive pour inspection
borg mount user@backup-server:/mnt/borg/prod::prod-2024-03-14 /mnt/restore

# 3. Vérifier l'intégrité d'un fichier critique
diff /etc/nginx/nginx.conf /mnt/restore/etc/nginx/nginx.conf

# 4. Restaurer sélectivement
borg extract user@backup-server:/mnt/borg/prod::prod-2024-03-14 \
  var/lib/postgresql/data

# 5. Démonter
borg umount /mnt/restore

Sécurité opérationnelle#

Comptes de service#

Chaque service applicatif doit tourner sous un compte dédié sans shell et sans droits superflus :

useradd --system --no-create-home --shell /usr/sbin/nologin appservice
# ou avec home applicatif
useradd --system --home-dir /opt/app --shell /usr/sbin/nologin appservice

Rotation des clés SSH#

# Générer une nouvelle paire de clés Ed25519
ssh-keygen -t ed25519 -C "admin@example.com-$(date +%Y)" \
  -f ~/.ssh/id_ed25519_2024

# Déployer la nouvelle clé sur tous les serveurs (via Ansible)
ansible all -m authorized_key -a \
  "user=ansible key='{{ lookup('file', '~/.ssh/id_ed25519_2024.pub') }}'"

# Après validation, retirer l'ancienne clé
ansible all -m authorized_key -a \
  "user=ansible key='{{ lookup('file', '~/.ssh/id_ed25519_old.pub') }}' state=absent"

Audit des accès#

# Dernières connexions SSH
last -n 20

# Connexions échouées (brute force)
journalctl -u sshd | grep "Failed password" | tail -20

# Comptes avec accès sudo
getent group sudo
grep -v '^#' /etc/sudoers /etc/sudoers.d/* 2>/dev/null

# Ports ouverts actuels vs attendus
ss -tlnp

Journalisation centralisée#

Les journaux locaux peuvent être effacés par un attaquant. En production, centraliser les logs sur un serveur syslog distant dès que possible :

# /etc/systemd/journald.conf
[Journal]
ForwardToSyslog=yes

# /etc/rsyslog.d/50-remote.conf
*.* @siem.example.com:514    # UDP (non fiable)
*.* @@siem.example.com:514   # TCP (fiable)

Infrastructure as Code#

Git pour les configurations#

Versionner /etc avec etckeeper ou un dépôt Ansible/Terraform constitue une source de vérité unique. Chaque changement devient un commit avec auteur, date et message.

Peer review des changements infra#

Un changement d’infrastructure qui passe par une pull request bénéficie du regard d’un pair avant d’être appliqué. Cette pratique, venue du développement logiciel, est aussi précieuse pour l’infra :

  • Détection d’erreurs avant la production.

  • Partage de connaissance entre membres de l’équipe.

  • Traçabilité des décisions (pourquoi ce changement, à quelle date, validé par qui).

CI/CD pour l’infra#

# .gitlab-ci.yml — pipeline Ansible simplifié
stages: [lint, test, deploy]

ansible-lint:
  stage: lint
  image: pipelinecomponents/ansible-lint
  script: ansible-lint site.yml

molecule-test:
  stage: test
  script:
    - pip install molecule molecule-docker
    - molecule test -s default

deploy-prod:
  stage: deploy
  when: manual
  only: [main]
  script:
    - ansible-playbook -i inventaire/prod site.yml

Veille et amélioration continue#

Suivi des CVE#

Une CVE (Common Vulnerabilities and Exposures) est un identifiant public pour une vulnérabilité de sécurité. Les administrateurs système doivent surveiller les CVE affectant leurs logiciels.

# apt-listchanges affiche les changelogs lors des mises à jour
apt install apt-listchanges

# Lister les CVE corrigées dans la dernière mise à jour OpenSSH
apt changelog openssh-server | grep CVE

# Flux RSS CVE Ubuntu
# https://ubuntu.com/security/cves/rss.xml

# Outil Debian pour auditer les paquets vulnérables
apt install debsecan
debsecan --suite bookworm --only-fixed

Ressources de veille#

  • CERT-FR (cert.ssi.gouv.fr) : alertes et bulletins en français.

  • NVD (nvd.nist.gov) : base nationale américaine, API REST.

  • oss-security (mailing list) : divulgations avant correctif (full disclosure).

  • RHEL/CentOS Errata : liste des correctifs par version.

Certifications Linux#

Hide code cell source

# Comparaison des certifications Linux

sns.set_theme(style="whitegrid", palette="muted", font_scale=1.1)

certifs = {
    "LPIC-1": {
        "Organisme": "LPI", "Niveau": "Débutant", "Coût (€)": 200,
        "Validité (ans)": 5, "Pratique (%)": 0, "Théorique (%)": 100,
    },
    "LPIC-2": {
        "Organisme": "LPI", "Niveau": "Intermédiaire", "Coût (€)": 200,
        "Validité (ans)": 5, "Pratique (%)": 0, "Théorique (%)": 100,
    },
    "LFCS": {
        "Organisme": "CNCF/LF", "Niveau": "Intermédiaire", "Coût (€)": 295,
        "Validité (ans)": 3, "Pratique (%)": 100, "Théorique (%)": 0,
    },
    "RHCSA": {
        "Organisme": "Red Hat", "Niveau": "Intermédiaire", "Coût (€)": 400,
        "Validité (ans)": 3, "Pratique (%)": 100, "Théorique (%)": 0,
    },
    "RHCE": {
        "Organisme": "Red Hat", "Niveau": "Avancé", "Coût (€)": 400,
        "Validité (ans)": 3, "Pratique (%)": 100, "Théorique (%)": 0,
    },
    "CKA": {
        "Organisme": "CNCF", "Niveau": "Avancé", "Coût (€)": 365,
        "Validité (ans)": 2, "Pratique (%)": 100, "Théorique (%)": 0,
    },
}

df = pd.DataFrame(certifs).T.reset_index()
df.columns = ["Certification"] + list(df.columns[1:])

fig, axes = plt.subplots(1, 2, figsize=(13, 4.5))

# Graphe 1 : coût et validité
ax1 = axes[0]
x = np.arange(len(certifs))
noms = list(certifs.keys())
couts = [v["Coût (€)"] for v in certifs.values()]
validites = [v["Validité (ans)"] for v in certifs.values()]

palette = sns.color_palette("muted", len(certifs))
bars = ax1.bar(x, couts, color=palette, edgecolor="white", linewidth=0.8)
ax1.set_xticks(x)
ax1.set_xticklabels(noms, fontsize=9, rotation=20, ha="right")
ax1.set_ylabel("Coût (€)", fontsize=10)
ax1.set_title("Coût des certifications Linux", fontsize=11, fontweight="bold")

ax1b = ax1.twinx()
ax1b.plot(x, validites, "D--", color="#C44E52", linewidth=1.8, markersize=7,
          label="Validité (ans)")
ax1b.set_ylabel("Validité (ans)", fontsize=10, color="#C44E52")
ax1b.tick_params(axis="y", colors="#C44E52")
ax1b.set_ylim(0, 7)
ax1b.legend(loc="upper right", fontsize=8)

# Graphe 2 : pratique vs théorique
ax2 = axes[1]
pratique = [v["Pratique (%)"] for v in certifs.values()]
theorique = [v["Théorique (%)"] for v in certifs.values()]

ax2.bar(x, pratique, color="#55A868", label="Pratique", edgecolor="white")
ax2.bar(x, theorique, bottom=pratique, color="#4C72B0", label="Théorique", edgecolor="white")
ax2.set_xticks(x)
ax2.set_xticklabels(noms, fontsize=9, rotation=20, ha="right")
ax2.set_ylabel("Part de l'examen (%)", fontsize=10)
ax2.set_title("Format de l'examen (pratique vs théorique)", fontsize=11, fontweight="bold")
ax2.legend(fontsize=9)
ax2.set_ylim(0, 120)

plt.savefig("22_certifications.png", dpi=100, bbox_inches="tight")
plt.show()
_images/84bcfb583a4fce5a9591e50c2dfa80911b60e8ab80998ddaa049528e8bf57f91.png

Résumé du parcours#

De Bash à l’administration avancée#

Ce livre a couvert l’ensemble du spectre de l’administration système Linux :

Partie

Chapitres

Thème

I

1–4

Fondations : boot, noyau, utilisateurs, systemd

II

5–8

Stockage : disques, LVM, RAID, sauvegardes

III

9–12

Réseau : configuration, pare-feu, SSH, services

IV

13–15

Sécurité : permissions, durcissement, cryptographie

V

16–18

Observabilité : monitoring, logs, performance

VI

19–22

Pratiques : Ansible, virtualisation, automatisation, ops

Hide code cell source

# Radar des compétences de l'administrateur système (8 dimensions)

sns.set_theme(style="whitegrid", palette="muted", font_scale=1.1)

dimensions = [
    "Réseau &\npare-feu", "Stockage\n& LVM",
    "Sécurité\n& hardening", "Automatisation\nAnsible",
    "Monitoring &\nlogs", "Virtualisation\n& conteneurs",
    "Scripts\nBash/Python", "Documentation\n& ops",
]

N = len(dimensions)
angles = np.linspace(0, 2 * np.pi, N, endpoint=False).tolist()
angles += angles[:1]

profils = {
    "Administrateur junior":   [2, 2, 2, 1, 2, 1, 2, 2],
    "Administrateur confirmé": [4, 4, 3, 3, 4, 3, 4, 3],
    "Ingénieur SRE senior":    [5, 5, 5, 5, 5, 5, 5, 5],
}

couleurs_p = ["#4C72B0", "#55A868", "#C44E52"]
fig, ax = plt.subplots(figsize=(8, 8), subplot_kw=dict(polar=True))

for (label, valeurs), couleur in zip(profils.items(), couleurs_p):
    v = valeurs + valeurs[:1]
    ax.plot(angles, v, linewidth=2.0, color=couleur, label=label)
    ax.fill(angles, v, alpha=0.12, color=couleur)

ax.set_theta_offset(np.pi / 2)
ax.set_theta_direction(-1)
ax.set_xticks(angles[:-1])
ax.set_xticklabels(dimensions, fontsize=9)
ax.set_ylim(0, 5)
ax.set_yticks([1, 2, 3, 4, 5])
ax.set_yticklabels(["1", "2", "3", "4", "5"], fontsize=8, color="#888888")
ax.yaxis.set_tick_params(labelsize=7)
ax.set_title("Radar des compétences — Administrateur Linux", fontsize=13,
             fontweight="bold", pad=25)
ax.legend(loc="upper right", bbox_to_anchor=(1.35, 1.1), fontsize=9)

plt.savefig("22_radar_competences.png", dpi=100, bbox_inches="tight")
plt.show()
_images/3bc64d2b73264a440c68bc0c3369b2f9d9c43d0d3b019a731eb36bc1e8eb0d0a.png

Hide code cell source

# Modèle de maturité ops (diagramme de progression par niveau)

sns.set_theme(style="whitegrid", palette="muted", font_scale=1.1)

niveaux = ["Niveau 0\nManuel", "Niveau 1\nDocumenté",
           "Niveau 2\nAutomatisé", "Niveau 3\nObservable",
           "Niveau 4\nSelf-healing"]

descriptions = [
    "Interventions\nmanuelles,\npas de runbook",
    "Runbooks écrits,\ngit pour /etc,\npost-mortems",
    "Ansible/Puppet,\nCI/CD infra,\ntimer systemd",
    "Prometheus,\nalertes fiables,\ndashboards",
    "Auto-scaling,\nauto-remédiation,\nchaos engineering",
]

couleurs_n = ["#C44E52", "#E76F51", "#F4A261", "#55A868", "#2d9e6b"]

fig, ax = plt.subplots(figsize=(13, 5))
ax.set_xlim(-0.5, len(niveaux) - 0.5)
ax.set_ylim(0, 5)
ax.axis("off")
ax.set_title("Modèle de maturité opérationnelle", fontsize=13,
             fontweight="bold", pad=14)

for i, (niveau, desc, couleur) in enumerate(zip(niveaux, descriptions, couleurs_n)):
    hauteur = 1.0 + i * 0.6
    rect = patches.FancyBboxPatch(
        (i - 0.42, 0.2), 0.84, hauteur + 1.0,
        boxstyle="round,pad=0.08", linewidth=1.2,
        edgecolor="#dddddd", facecolor=couleur, alpha=0.88
    )
    ax.add_patch(rect)
    ax.text(i, hauteur + 1.25, niveau, ha="center", va="center",
            fontsize=9.5, fontweight="bold", color="white",
            multialignment="center")
    ax.text(i, 0.8 + hauteur * 0.3, desc, ha="center", va="center",
            fontsize=7.5, color="white", multialignment="center",
            style="italic")

    if i < len(niveaux) - 1:
        ax.annotate("", xy=(i + 0.45, hauteur * 0.5 + 0.5),
                    xytext=(i + 0.42, hauteur * 0.5 + 0.5),
                    arrowprops=dict(arrowstyle="->", color="#888888", lw=1.5))

ax.text(2, 4.75, "Progression de la maturité →", ha="center", fontsize=9,
        color="#666666", style="italic")

plt.savefig("22_maturite_ops.png", dpi=100, bbox_inches="tight")
plt.show()
_images/48fa78604ecff2475b45dc7f24f9765f37f1423a922878c12c7186dbcf18492b.png

Prochaines étapes#

L’administration système Linux est un domaine en évolution permanente. Les axes d’approfondissement naturels après ce livre sont :

CI/CD et DevOps

  • GitLab CI / GitHub Actions pour l’automatisation des déploiements.

  • Terraform et Pulumi pour le provisionnement d’infrastructure cloud.

  • ArgoCD et Flux pour le GitOps appliqué à Kubernetes.

Sécurité avancée

  • Analyse forensique Linux : auditd, osquery, SIEM.

  • Pentest d’infrastructure : outils défensifs (Lynis, OpenVAS).

  • Gestion des secrets à l’échelle : HashiCorp Vault en cluster.

Observabilité

  • La suite Prometheus + Grafana + Loki + Tempo (métriques, logs, traces).

  • OpenTelemetry pour l’instrumentation des applications.

Conteneurs et orchestration

  • Docker en profondeur : réseaux, volumes, multi-stage builds.

  • Kubernetes : pods, deployments, services, ingress, RBAC.

  • Sécurité des conteneurs : Falco, OPA/Gatekeeper, Trivy.

Conseil final

L’expertise opérationnelle s’acquiert en production, pas seulement en formation. Mettre en place un homelab, contribuer à des projets open source, passer des certifications pratiques (RHCSA, LFCS, CKA) — chacune de ces pratiques consolide les réflexes que les livres ne peuvent qu’amorcer. La meilleure façon d’apprendre à diagnostiquer une panne est d’avoir déjà résolu des pannes.

Résumé#

Les bonnes pratiques ops ne sont pas un ensemble de règles rigides mais une culture :

Pratique

Valeur apportée

Documentation

Résilience collective, réduction du bus factor

Change management

Réversibilité, traçabilité, communication

Post-mortems blameless

Apprentissage systémique, confiance dans l’équipe

Gestion des secrets

Réduction de la surface d’attaque

Tests de restauration

Confiance réelle dans les sauvegardes

Infrastructure as Code

Reproductibilité, revue de code, audit

Veille CVE

Réactivité face aux vulnérabilités

Un administrateur système efficace n’est pas celui qui connaît le plus de commandes, mais celui qui construit des systèmes fiables, observables, documentés et réparables — par lui-même et par son équipe.