Cours 1 · Culture et fondationsLeçon 2 sur 2
Rappels indispensables
4 h de lecture10 sections Version PDF
Linux en ligne de commande, processus et permissions ; ports, DNS et HTTP ; Git avancé — branches, fusion, rebase, GitFlow contre trunk-based — et revue de code.
Trois choses bloquent un TP de DevOps dès la première séance, et aucune n'est du DevOps.
Le serveur n'a pas d'interface graphique : tout se fait en ligne de commande, et un étudiant
qui hésite sur chmod ou sur un pipe perd son temps sur autre chose que le sujet.
L'application ne répond pas, et il faut savoir où regarder : le processus écoute-t-il ? le
port est-il ouvert ? le nom se résout-il ? Et le dépôt Git compte huit branches divergentes,
parce que personne n'a décidé d'une stratégie.
Ce chapitre remet ces trois outils à niveau. Il ne remplace pas les cours de systèmes et de réseaux — il en extrait ce dont on se sert tous les jours, et il ajoute la partie de Git que l'usage individuel ne demande jamais.
Linux, ce qui sert vraiment
Le cours de systèmes a tout posé ; voici ce qu'on emploie sans y penser.
| Commande | Usage quotidien en exploitation |
|---|---|
ps aux, top, htop | qu'est-ce qui tourne, et qui consomme |
kill -TERM, kill -9 | arrêter proprement, puis brutalement |
df -h, du -sh * | le disque est plein — où ? |
tail -f fichier.log | suivre un journal en direct |
grep, awk, sort | uniq -c | fouiller ces journaux |
chmod, chown | droits et propriétaire |
systemctl status, journalctl -u | l'état d'un service et ses journaux |
ssh, scp | atteindre la machine, y déposer un fichier |
Deux rappels du cours de systèmes qui reviendront constamment.
Les droits. rwx pour le propriétaire, le groupe et les autres, notés en octal — 755,
644. Un conteneur qui refuse de démarrer parce qu'un script n'est pas exécutable est le
grand classique du chapitre 3.
Les processus et les signaux. SIGTERM demande de s'arrêter proprement, SIGKILL tue sans
préavis. Cette distinction n'est pas théorique : Docker et Kubernetes envoient un SIGTERM,
attendent quelques secondes, puis un SIGKILL. Une application qui n'écoute pas SIGTERM
perd ses requêtes en cours à chaque déploiement — et personne ne comprend pourquoi.
Réseau, le minimum pour diagnostiquer
Quand « ça ne répond pas », la question se décompose en quatre, et il faut les poser dans cet ordre.
Le nom se résout-il ? dig monsite.fr ou nslookup. Un DNS mal propagé se manifeste comme
une panne d'application.
Le port est-il ouvert et écouté ? ss -tlnp liste ce qui écoute localement ; curl -v ou
nc -zv hôte port teste depuis l'extérieur. La distinction compte : un service qui écoute sur
127.0.0.1 fonctionne en local et est injoignable de partout ailleurs — c'est l'erreur la plus
fréquente du chapitre 3, où un conteneur doit écouter sur 0.0.0.0 pour être atteignable.
La requête arrive-t-elle ? Les journaux du serveur le disent. Si rien n'apparaît, le problème est en amont : pare-feu, routage, groupe de sécurité.
Que répond-elle ? Les codes HTTP suffisent à orienter : 2xx succès, 3xx redirection,
4xx la faute vient du client — 404 introuvable, 401 non authentifié, 403 interdit — et
5xx la faute vient du serveur, 500 erreur interne, 502 la passerelle n'a pas obtenu de
réponse, 503 service indisponible.
Cette dernière ligne est celle qu'on emploie le plus : un 502 accuse le service en amont,
un 500 accuse l'application. Savoir lequel des deux on regarde fait gagner une heure.
Git au-delà de l'usage individuel
Un étudiant arrive avec commit, push, pull. Le travail en équipe demande trois choses de
plus.
Les branches. Une branche est un simple pointeur mobile sur un commit. La créer ne copie rien — c'est ce qui rend l'opération instantanée, et ce qui explique qu'on en crée sans compter.
La fusion contre le rebasage. Les deux intègrent le travail d'une branche dans une autre, et produisent des historiques de formes différentes.
merge rebase A───B───C───────M A───B───C───D'──E' \ / D───────E les commits sont REJOUÉS au-dessus de Cmerge préserve l'histoire telle qu'elle s'est produite, au prix d'un graphe qui se
ramifie. rebase réécrit les commits pour donner une ligne droite, plus lisible — mais il
crée de nouveaux commits, ce qui donne la seule règle absolue du chapitre : on ne rebase
jamais une branche déjà partagée avec d'autres. Les commits d'origine disparaissent, et les
collègues qui les avaient récupérés se retrouvent avec un historique incompatible.
L'usage courant : rebaser sa branche locale sur la principale avant de proposer sa contribution, puis fusionner. On obtient un historique lisible sans réécrire ce que d'autres ont déjà.
Les conflits. Ils surviennent quand deux branches modifient les mêmes lignes. Git ne peut pas trancher et vous laisse le fichier avec les deux versions marquées. Le point important est statistique : la probabilité de conflit croît avec la durée de vie de la branche. Une branche fusionnée le jour même entre rarement en conflit ; une branche de trois semaines touche des fichiers qui ont bougé entre-temps.
Deux stratégies de branchement
C'est le lien direct avec le chapitre 1, et le choix a des conséquences mesurables.
GitFlow organise le travail autour de branches durables : main, develop, une branche par
fonctionnalité, des branches de version et de correctif. C'est structuré, adapté à des
versions livrées — un logiciel installé chez des clients, avec plusieurs versions
maintenues en parallèle.
Trunk-based ne garde qu'une branche principale, dans laquelle chacun intègre au moins une fois par jour, à l'aide de branches de très courte durée. Les fonctionnalités inachevées sont masquées par des drapeaux de fonctionnalité plutôt que par des branches.
| GitFlow | Trunk-based | |
|---|---|---|
| Durée de vie d'une branche | semaines | heures à un jour |
| Taille des lots | grosse | petite |
| Conflits | fréquents et larges | rares et étroits |
| Compatible livraison continue | difficilement | oui |
| Adapté à | versions installées chez des clients | service en ligne |
Le rapprochement avec le chapitre 1 est immédiat : une branche de trois semaines est un lot de trois semaines. Toute la logique DORA — petits lots, rétroaction courte, retour arrière facile — pousse vers le trunk-based dès qu'on livre en continu. Ce n'est pas une question de mode mais de cohérence : un pipeline qui déploie plusieurs fois par jour ne peut pas cohabiter avec des branches qui vivent un mois.
La revue de code
Une demande de fusion (pull request) n'est pas une formalité administrative : c'est le point où trois choses se produisent — un second regard sur la correction, une diffusion de la connaissance dans l'équipe, et le déclenchement automatique du pipeline du chapitre 5.
Trois règles d'usage, et la première explique les deux autres.
Petit. Une demande de deux cents lignes est relue sérieusement ; une de deux mille est approuvée sans être lue. Le taux de détection s'effondre au-delà de quelques centaines de lignes, et c'est encore un argument pour les petits lots.
Rapide. Une demande qui attend deux jours bloque son auteur et se désynchronise de la branche principale — donc conflits.
Sur le code, pas sur la personne. « Cette boucle relit la base à chaque tour » plutôt que « tu n'as pas réfléchi ». C'est le post-mortem sans blâme du chapitre 1, appliqué à la relecture.
Pourquoi ne rebase-t-on jamais une branche déjà poussée et partagée ?
Une équipe qui déploie plusieurs fois par jour maintient des branches de fonctionnalité vivant trois semaines. Où est l'incohérence ?
À vous
L'exercice simule un dépôt et rend visible ce que la ligne de commande cache.
D'abord la forme de l'historique : les mêmes contributions intégrées par fusion puis par rebasage, avec le graphe affiché dans les deux cas. Vous constaterez que le contenu final est identique et que les identifiants de commits, eux, ont changé — d'où la règle.
Ensuite un simulateur de stratégie de branchement : vous faites varier la durée de vie des branches et le nombre de contributeurs, et le programme compte les conflits, la taille des lots intégrés et le délai moyen d'intégration. Les chiffres de GitFlow et du trunk-based se séparent nettement, et ils se relient directement aux indicateurs DORA du chapitre 1.
Comparez fusion et rebasage sur le même historique, puis chiffrez l'effet de la durée de vie des branches.
// ── 1. Fusion contre rebasage ───────────────────────────────────────────── // Un commit : identifiant, message, parents. let compteur = 0; const commit = (msg, parents) => ({ id: "c" + (++compteur), msg, parents }); function creerDepot() { const a = commit("A : socle", []); const b = commit("B : lecture config", [a]); const c = commit("C : correctif principal", [b]); // sur main const d = commit("D : début fonctionnalité", [b]); // sur la branche const e = commit("E : fin fonctionnalité", [d]); return { a, b, c, d, e }; } function fusionner(depot) { // La fusion CONSERVE d et e tels quels, et crée un commit à deux parents. const m = commit("M : fusion de la branche", [depot.c, depot.e]); return [depot.a, depot.b, depot.c, depot.d, depot.e, m]; } function rebaser(depot) { // ← à écrire : rejouer d et e AU-DESSUS de c. Ce sont de NOUVEAUX commits. return []; } function afficher(nom, commits) { console.log(" " + nom); for (const c of commits) { const p = c.parents.map((x) => x.id).join(", ") || "—"; console.log(" " + c.id.padEnd(4) + c.msg.padEnd(28) + "parents : " + p); } } // ── 2. Effet de la durée de vie des branches ────────────────────────────── // Modèle simple : chaque jour, chaque contributeur produit une modification. // Une branche accumule ses modifications jusqu'à son intégration. Le risque // de conflit croît avec le nombre de modifications faites AILLEURS pendant // qu'elle vivait. function simuler({ contributeurs, jours, dureeBranche }) { const modifsParJour = contributeurs; const integrations = Math.floor(jours / dureeBranche) * contributeurs; const tailleLot = dureeBranche; // modifications par lot const modifsAilleurs = 0; // ← à écrire const probaConflit = 0; // ← à écrire return { integrations, tailleLot, modifsAilleurs, probaConflit, delaiIntegration: dureeBranche / 2 }; } // ── À VOUS ──────────────────────────────────────────────────────────────── // 1. Écrivez rebaser(). Comparez les identifiants : que constate-t-on, et // pourquoi ne rebase-t-on pas une branche partagée ? // 2. Complétez simuler() : pendant qu'une branche vit d jours, les autres // contributeurs produisent (contributeurs − 1) × d modifications. // La probabilité de conflit croît avec ce nombre. // 3. Comparez GitFlow (branches de 15 jours) et trunk-based (0,5 jour) sur // six contributeurs et trois mois. Reliez aux indicateurs DORA. const d = creerDepot(); afficher("après fusion", fusionner(d));
En travaux pratiques
Mise en place du dépôt et diagnostic réseau
Lancer l'application du fil rouge à la main, diagnostiquer une erreur de réseau, puis installer la stratégie de branchement qui servira tout le semestre.
- Une machine Linux ou un WSL, avec Git, Node et curl
- L'archive de l'application tickets fournie par l'enseignant
- 1. Lancer l'application, et échouer
Démarrez l'application fournie, puis tentez de l'atteindre depuis un autre terminal avec curl. Elle ne répond pas. Ne modifiez rien tant que vous n'avez pas suivi les quatre questions du diagnostic.
- 2. Identifier l'interface d'écoute
Listez ce qui écoute sur la machine et comparez l'adresse d'écoute à celle que vous interrogez. Corrigez la configuration, sans toucher au code métier.
- 3. Vérifier les droits
Le script de démarrage fourni n'est pas exécutable. Rendez-le exécutable pour son seul propriétaire, sans donner de droit d'écriture au groupe ni aux autres. Écrivez la valeur octale que vous employez et justifiez-la.
- 4. Créer le dépôt et sa stratégie
Initialisez un dépôt, poussez-le, protégez la branche principale, et écrivez un fichier CONTRIBUTING.md qui fixe la stratégie de branchement : durée de vie maximale d'une branche, taille maximale d'une demande de fusion, et délai maximal de relecture.
- 5. Fusion contre rebasage, sur un vrai conflit
À deux, modifiez la même ligne du même fichier sur deux branches. Intégrez la première par fusion, la seconde par rebasage. Comparez les deux historiques obtenus, puis dites laquelle des deux opérations vous vous interdiriez si la branche avait déjà été poussée.
- curl obtient une réponse depuis un autre terminal, et vous savez dire quelle question du diagnostic a révélé la cause
- Le script démarre et ses droits sont justifiés
- La branche principale refuse un push direct
- Vous savez énoncer la règle sur le rebasage d'une branche partagée
Ce que la suite en fait
Le bloc II attaque le premier vrai sujet : empaqueter l'application avec tout ce dont elle a
besoin, pour que « ça marche sur ma machine » cesse d'être une excuse. Les droits Unix et les
signaux de ce chapitre y reviennent dès le premier Dockerfile, et la question du port écouté
y devient le premier bogue de tout le monde.
Et la revue de code retrouvera son sens au chapitre 5 : une demande de fusion est ce qui déclenche le pipeline, et le pipeline est ce qui rend la revue supportable — le relecteur n'a plus à vérifier que le code compile et que les tests passent.
À retenir
Vous avez parcouru les 10 sections.
Marquez-la terminée pour faire avancer votre parcours, ou revenez sur un point avant de passer à la suite.