La culture DevOps et la livraison continue
Livrer souvent, par petits morceaux, avec des machines qui vérifient tout : ce n'est pas plus risqué, c'est le contraire.
Les fiches 11, 12 et 13 t'ont appris à déployer une application Symfony. Cette fiche prend du recul : comment une équipe organise-t-elle la livraison, quel que soit le langage ? Ce qu'elle présente vaut aussi bien pour une API en Go, un front en TypeScript ou une application mobile. Les exemples utilisent un projet Symfony parce que c'est ton terrain, mais seules quelques commandes changeraient pour un autre langage.
Aucun pipeline de cette fiche n'a été exécuté : ce sont des illustrations, relues et comparées à la documentation officielle. Seuls les deux exemples en PHP et en SQL ont tourné.
1.DevOps : une culture, pas un poste
Pendant longtemps, deux équipes se partageaient une application. Les développeurs étaient jugés sur les fonctionnalités livrées. L'exploitation (les « ops ») était jugée sur la stabilité de la production. Leurs objectifs s'opposaient : chaque livraison était un risque pour les uns et une victoire pour les autres. Le code passait « par-dessus le mur », avec un « ça marche sur ma machine », et les mises en production devenaient des soirées tendues, deux fois par an.
Le mot DevOps est né en 2009, autour de Patrick Debois et des premières conférences DevOpsDays. Il désigne une façon de travailler où la même équipe est responsable du code, de sa livraison et de son fonctionnement en production. Werner Vogels, d'Amazon, l'avait résumé dès 2006 : « You build it, you run it », tu le construis, tu le fais tourner.
- Une responsabilité partagée : un développeur qui reçoit les alertes de son propre code écrit des logs utiles et des migrations prudentes.
- L'automatisation : ce qui est répété (tests, construction, déploiement) est confié à des machines, qui ne se fatiguent pas et n'oublient pas d'étape.
- De petits lots : beaucoup de petites livraisons plutôt qu'une grosse. Chacune est facile à comprendre, à vérifier et à annuler (fiche 13).
- La mesure : on regarde ce qui se passe vraiment en production, plutôt que de supposer (section 7 et fiche 21).
L'intitulé existe sur beaucoup d'offres d'emploi. Il désigne en général quelqu'un qui construit les outils de livraison et l'infrastructure. C'est utile, mais si cette personne devient la seule à savoir déployer, on a simplement recréé le mur avec un nouveau nom. Le but reste que chaque développeur puisse livrer et comprendre la production.
2.L'intégration continue
Deux développeurs travaillent trois semaines chacun sur leur branche. Le jour de la fusion, tout entre en conflit, et personne ne sait plus quelle combinaison a été testée. L'intégration continue (CI, Continuous Integration) prend le problème à l'envers : intégrer petit et souvent dans la branche principale, au moins une fois par jour, et vérifier automatiquement chaque changement.
Concrètement, chaque push déclenche un pipeline : une suite d'étapes exécutée sur une machine propre. Avec GitHub Actions :
# .github/workflows/ci.yml : à chaque push et à chaque pull request
name: CI
on:
push:
branches: [main]
pull_request:
permissions:
contents: read # lire le dépôt, rien de plus
concurrency: # un nouveau push annule l'exécution précédente
group: ci-${{ github.ref }}
cancel-in-progress: true
jobs:
tests:
runs-on: ubuntu-24.04
timeout-minutes: 15
services:
postgres:
image: postgres:17
env:
POSTGRES_USER: app
POSTGRES_PASSWORD: app # base jetable, détruite après le job
POSTGRES_DB: app_test
ports: ['5432:5432']
options: >-
--health-cmd pg_isready --health-interval 5s
--health-timeout 5s --health-retries 10
env:
# Symfony ajoute « _test » au nom de la base en environnement de test
DATABASE_URL: postgresql://app:app@127.0.0.1:5432/app?serverVersion=17
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
php-version: '8.4'
tools: composer
- run: composer install --no-progress --prefer-dist
- run: composer audit # failles connues des dépendances
- run: vendor/bin/php-cs-fixer fix --dry-run --diff
- run: vendor/bin/phpstan analyse --no-progress
- run: bin/console doctrine:migrations:migrate --no-interaction --env=test
- run: vendor/bin/phpunit- Une machine neuve à chaque fois : rien ne dépend de ce qui traîne sur le poste d'un développeur. Si ça passe ici, ça passe partout.
- Du moins cher au plus cher : le style et l'audit échouent en quelques secondes, les tests prennent plus longtemps. On met en premier ce qui échoue vite.
- Une vraie base de données, dans un conteneur jetable, pour les tests d'intégration (fiche 3).
- Un pipeline rouge se répare en premier, avant toute nouvelle fonctionnalité. Un pipeline qu'on laisse rouge n'avertit plus personne.
- Un pipeline rapide : au-delà d'une dizaine de minutes, l'équipe commence à le contourner. Parallélise les jobs et mets en cache les dépendances.
Cette pratique va de pair avec des branches courtes : quelques heures ou quelques jours, pas des semaines (fiche 4). Poussée jusqu'au bout, c'est le trunk-based development : tout le monde intègre directement dans la branche principale, plusieurs fois par jour, et le code pas encore prêt est caché derrière un feature flag (section 5).
3.Livraison et déploiement continus
Une fois le code vérifié, il faut l'amener en production. Deux pratiques portent des noms proches, et la différence compte :
- La livraison continue (Continuous Delivery) : chaque changement fusionné est prêt à partir en production. Une personne décide du moment, d'un clic.
- Le déploiement continu (Continuous Deployment) : chaque changement qui passe toutes les étapes part en production automatiquement, sans clic.
Voici un pipeline de livraison continue, avec GitHub Actions. Il reprend une règle de la fiche 13 : l'image est construite une seule fois, étiquetée par son commit, et c'est exactement elle qui part en recette puis en production.
# .github/workflows/deliver.yml : après chaque fusion dans main
name: Livraison
on:
push:
branches: [main]
permissions:
contents: read
packages: write # publier l'image dans le registre du dépôt
jobs:
image: # construite UNE fois, étiquetée par le commit
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v6
with:
push: true
tags: ghcr.io/boutique/app:${{ github.sha }}
staging:
needs: image
runs-on: ubuntu-24.04
environment: staging # ses propres secrets : ceux de la recette
steps:
- uses: actions/checkout@v4
- run: ./deploy.sh staging ${{ github.sha }}
- run: curl --fail --retry 5 --retry-delay 5 https://staging.example.com/health
production:
needs: staging
runs-on: ubuntu-24.04
environment: production # règle de protection : une personne doit approuver
steps:
- uses: actions/checkout@v4
- run: ./deploy.sh production ${{ github.sha }}
- run: curl --fail --retry 5 --retry-delay 5 https://www.example.com/health- Un environnement GitHub par cible (
staging,production), chacun avec ses propres secrets. Une règle de protection peut exiger qu'une personne approuve avant la production. Sa disponibilité dépend de ton offre GitHub. - Un test de fumée (smoke test) après chaque déploiement : une requête sur une route de santé qui vérifie que l'application démarre et joint sa base. S'il échoue, le pipeline s'arrête avant la production.
- Le script
deploy.shcontient la bascule vue en fiche 13 (lien symbolique, ou mise à jour progressive des conteneurs). Le pipeline ne fait que l'appeler.
Les mêmes idées s'écrivent avec une autre syntaxe dans GitLab CI. Ici, le bouton de mise en production est la ligne when: manual :
# .gitlab-ci.yml : le même pipeline, avec GitLab CI
stages: [test, build, deploy]
tests:
stage: test
image: registry.example.com/boutique/php-ci:8.4 # PHP, ses extensions et Composer
services:
- postgres:17
variables:
POSTGRES_USER: app
POSTGRES_PASSWORD: app
POSTGRES_DB: app_test
DATABASE_URL: postgresql://app:app@postgres:5432/app?serverVersion=17
script:
- composer install --no-progress --prefer-dist
- composer audit
- vendor/bin/phpstan analyse --no-progress
- bin/console doctrine:migrations:migrate --no-interaction --env=test
- vendor/bin/phpunit
image:
stage: build
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
script:
- docker build -t "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA" .
- docker push "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA"
deploy_staging:
stage: deploy
environment: staging
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
script:
- ./deploy.sh staging "$CI_COMMIT_SHA"
deploy_production:
stage: deploy
needs: [deploy_staging]
environment: production
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
when: manual # un bouton : livraison continue, pas déploiement continu
script:
- ./deploy.sh production "$CI_COMMIT_SHA"La livraison continue est le bon objectif pour presque toutes les équipes : la production est toujours à un clic, et une personne garde la main sur le moment.
Le déploiement continu demande une grande confiance dans les tests, de la surveillance, des feature flags et un retour en arrière rapide. Sans eux, il envoie les bugs en production plus vite. C'est une destination, pas un point de départ.
4.Les environnements
Un environnement est un endroit où l'application tourne, avec sa configuration et ses données. La fiche 13 en a présenté trois. Le principe qui les relie : le même code partout, seule la configuration change.
- La parité : mêmes versions de PHP, de PostgreSQL, de Redis sur ton poste, en recette et en production. Docker Compose sert à ça sur le poste (fiche 12). Chaque différence est un bug qui n'apparaîtra qu'en production.
- La configuration dans l'environnement : des variables d'environnement, jamais des fichiers propres à chaque serveur ajoutés à la main.
- Des données de recette anonymisées : une copie de la production avec les vrais noms, e-mails et adresses de tes clients expose des données personnelles à toute l'équipe. Le RGPD l'interdit sans raison solide.
- Des environnements éphémères : certaines équipes créent un environnement temporaire par pull request, détruit à la fusion. Pratique pour faire valider une fonctionnalité, mais il faut une infrastructure qui le permette (fiche 20).
5.Les feature flags : déployer n'est pas livrer
Un feature flag (interrupteur de fonctionnalité) est une condition dans le code qui active ou non une fonctionnalité, réglée sans redéployer. Il sépare deux moments qu'on confond souvent : déployer (le code est en production) et mettre en service (les utilisateurs s'en servent).
<?php
declare(strict_types=1);
// Des interrupteurs de fonctionnalités, avec une ouverture progressive
final class FeatureFlags
{
/**
* @param array<string, array{enabled: bool, percentage?: int, users?: string[]}> $flags
*/
public function __construct(private array $flags)
{
}
public function isEnabled(string $flag, string $userId): bool
{
$config = $this->flags[$flag] ?? null;
if ($config === null || !$config['enabled']) {
return false; // inconnu ou coupé : désactivé, par prudence
}
if (in_array($userId, $config['users'] ?? [], true)) {
return true; // les testeurs désignés le voient toujours
}
// Le même utilisateur tombe toujours dans le même « seau », de 0 à 99
$bucket = crc32("$flag:$userId") % 100;
return $bucket < ($config['percentage'] ?? 100);
}
}
// En vrai, cette configuration vient d'une base ou d'un service : on la change sans redéployer
$flags = new FeatureFlags([
'new_checkout' => ['enabled' => true, 'percentage' => 20, 'users' => ['alice']],
'pdf_invoices' => ['enabled' => false], // coupé en urgence : un bug en production
]);
$enabled = 0;
for ($i = 1; $i <= 1000; $i++) {
$enabled += $flags->isEnabled('new_checkout', "user-$i") ? 1 : 0;
}
echo "Nouveau tunnel de commande : $enabled utilisateurs sur 1000\n";
$show = fn (bool $enabled): string => $enabled ? 'activé' : 'désactivé';
$first = $flags->isEnabled('new_checkout', 'user-42');
$second = $flags->isEnabled('new_checkout', 'user-42');
echo "user-42, deux visites : {$show($first)} puis {$show($second)}\n";
echo 'alice, testeuse désignée : ' . $show($flags->isEnabled('new_checkout', 'alice')) . "\n";
echo 'Factures PDF : ' . $show($flags->isEnabled('pdf_invoices', 'alice')) . "\n";
echo 'Interrupteur inconnu : ' . $show($flags->isEnabled('dark_mode', 'alice')) . "\n";Nouveau tunnel de commande : 206 utilisateurs sur 1000 user-42, deux visites : désactivé puis désactivé alice, testeuse désignée : activé Factures PDF : désactivé Interrupteur inconnu : désactivé
- Le même utilisateur voit toujours la même chose : le seau est calculé à partir de son identifiant, pas tiré au hasard à chaque visite.
- Un interrupteur inconnu est coupé : une faute de frappe dans un nom ne doit pas mettre en service une fonctionnalité inachevée.
- Quatre usages courants : cacher du code pas fini (trunk-based), ouvrir progressivement, couper en urgence une fonctionnalité qui pose problème, comparer deux versions (test A/B).
- Des outils existent : Unleash est un service open source, et OpenFeature, un projet de la CNCF, propose une interface commune à plusieurs fournisseurs. Pour quelques interrupteurs, une table en base suffit.
Chaque interrupteur double les chemins possibles dans le code : deux interrupteurs, quatre combinaisons à tester. Un interrupteur oublié devient une dette, et des années plus tard, plus personne n'ose le retirer. Donne-lui une date de fin, et supprime-le du code dès qu'il est à 100 %. Pour une petite modification sans risque, il n'en faut pas : un déploiement suffit.
6.Les 12 facteurs
En 2011, des ingénieurs de Heroku, une plateforme d'hébergement, ont résumé en douze règles ce qui rend une application facile à déployer et à faire grandir : The Twelve-Factor App. Elles valent pour tous les langages, et tu en as déjà appliqué la plupart sans le savoir :
| Facteur | En une phrase | Chez toi |
|---|---|---|
| 1. Base de code | Un dépôt par application, déployé dans plusieurs environnements | Un dépôt Git |
| 2. Dépendances | Déclarées et isolées, jamais supposées présentes | composer.json et composer.lock |
| 3. Configuration | Dans l'environnement, pas dans le code | Variables d'environnement, %env()% |
| 4. Services externes | Base, cache, e-mail : des ressources attachées par une URL | DATABASE_URL, MAILER_DSN |
| 5. Construire, livrer, exécuter | Trois étapes séparées : on ne modifie pas le code en production | L'image construite une fois (section 3) |
| 6. Processus | Sans état : rien d'important sur le disque local | Sessions et fichiers hors du serveur (fiche 19) |
| 7. Port | L'application s'expose elle-même sur un port | Moins direct en PHP : nginx devant PHP-FPM, ou FrankenPHP |
| 8. Concurrence | Grandir en ajoutant des processus, pas en grossissant un seul | Plus de conteneurs, plus de workers Messenger |
| 9. Jetable | Démarrer vite, s'arrêter proprement | Un worker qui finit son message avant de s'arrêter |
| 10. Parité | Le développement ressemble à la production | Docker Compose (section 4) |
| 11. Logs | Un flux écrit sur la sortie standard, pas des fichiers à gérer | Monolog vers php://stderr, que Docker récupère |
| 12. Tâches d'administration | Lancées comme des processus ponctuels, avec le même code | Une commande console dans le même conteneur |
Ces règles ont été écrites pour une plateforme précise, en 2011, et certaines se discutent pour PHP, comme le facteur 7. Prends-les comme une liste de questions à se poser, pas comme un examen à réussir.
7.Mesurer : les indicateurs DORA
Comment savoir si une équipe livre bien ? Le programme de recherche DORA (DevOps Research and Assessment) a interrogé des dizaines de milliers de professionnels pendant des années. Ses résultats, publiés dans le livre Accelerate (2018) et dans un rapport annuel, retiennent quatre indicateurs, deux pour la vitesse et deux pour la stabilité : la fréquence de déploiement, le délai de mise en production, le taux d'échec des changements et le temps de rétablissement.
Ces chiffres se calculent simplement, à partir des déploiements que ton pipeline enregistre. Le SQL suffit :
-- Les déploiements en production de deux semaines, tels qu'un pipeline peut les enregistrer
CREATE TABLE deployment (
id INTEGER PRIMARY KEY,
first_commit_at TEXT NOT NULL, -- premier commit du changement livré
deployed_at TEXT NOT NULL,
failed INTEGER NOT NULL, -- 1 si le déploiement a causé un incident
restored_at TEXT -- retour à la normale, si échec
);
INSERT INTO deployment VALUES
(1, '2026-10-19 09:10', '2026-10-19 16:40', 0, NULL),
(2, '2026-10-20 10:00', '2026-10-21 11:15', 0, NULL),
(3, '2026-10-21 14:30', '2026-10-22 10:05', 1, '2026-10-22 10:47'),
(4, '2026-10-22 11:00', '2026-10-22 17:20', 0, NULL),
(5, '2026-10-23 09:45', '2026-10-23 15:00', 0, NULL),
(6, '2026-10-26 10:20', '2026-10-26 16:30', 0, NULL),
(7, '2026-10-26 15:00', '2026-10-28 09:30', 0, NULL),
(8, '2026-10-28 08:50', '2026-10-28 14:10', 1, '2026-10-28 15:55'),
(9, '2026-10-29 13:15', '2026-10-29 17:45', 0, NULL),
(10, '2026-10-30 09:00', '2026-10-30 11:40', 0, NULL);
-- 1. Fréquence de déploiement : combien par semaine ?
SELECT strftime('%W', deployed_at) AS week, COUNT(*) AS deployments
FROM deployment
GROUP BY week;
-- 2. Délai de mise en production : du premier commit à la production, en heures
SELECT ROUND(AVG((julianday(deployed_at) - julianday(first_commit_at)) * 24), 1)
AS average_lead_time_hours
FROM deployment;
-- 3. Taux d'échec des changements
SELECT ROUND(100.0 * SUM(failed) / COUNT(*), 1) AS change_failure_rate_percent
FROM deployment;
-- 4. Temps de rétablissement après un échec, en minutes
SELECT ROUND(AVG((julianday(restored_at) - julianday(deployed_at)) * 24 * 60))
AS average_recovery_minutes
FROM deployment
WHERE failed = 1;▸ 1. Fréquence de déploiement : combien par semaine ? week | deployments -----+------------ 42 | 5 43 | 5 (2 lignes) ▸ 2. Délai de mise en production : du premier commit à la production, en heures average_lead_time_hours ----------------------- 12.5 (1 ligne) ▸ 3. Taux d'échec des changements change_failure_rate_percent --------------------------- 20 (1 ligne) ▸ 4. Temps de rétablissement après un échec, en minutes average_recovery_minutes ------------------------ 73 (1 ligne)
- Une moyenne cache les extrêmes : un seul changement resté une semaine en attente fausse tout. La médiane est plus juste, mais SQLite ne la calcule pas directement (PostgreSQL, si :
percentile_cont(0.5)). - Le résultat le plus important des rapports DORA : vitesse et stabilité ne s'opposent pas. Les équipes qui livrent le plus souvent sont aussi celles qui cassent le moins et réparent le plus vite, parce que chaque changement est petit.
- Les noms et les seuils évoluent d'un rapport à l'autre : le temps de rétablissement s'appelle désormais « temps de rétablissement après un déploiement en échec ». Consulte le site de DORA plutôt que des chiffres recopiés.
Dès qu'un indicateur devient un objectif, il cesse d'être une bonne mesure : c'est la loi de Goodhart. Fixe un objectif de « 20 déploiements par semaine », et l'équipe découpera artificiellement ses changements. Utilise ces chiffres pour repérer ce qui ralentit l'équipe (une recette manuelle, des tests trop lents), pas pour comparer ou noter des personnes.
8.Sécuriser le pipeline
Un pipeline a accès au code, aux secrets de production et au droit de déployer. Pour un attaquant, c'est une cible plus intéressante que le serveur lui-même. En mars 2025, une action GitHub très utilisée, tj-actions/changed-files, a été modifiée par un attaquant pour afficher dans les logs les secrets des dépôts qui l'utilisaient. Des milliers de projets étaient concernés.
- Des droits minimaux :
permissions: contents: readpar défaut, et on n'ajoute que ce qu'un job précis demande, commepackages: writepour publier une image. - Épingle les actions tierces sur l'identifiant complet d'un commit plutôt que sur une étiquette comme
@v4: une étiquette peut être déplacée vers un code malveillant, un identifiant de commit non. Dependabot ou Renovate proposent ensuite les mises à jour. - Des secrets par environnement, jamais affichés. GitHub masque les secrets dans les logs, mais une simple transformation (encodage, découpage) contourne ce masque.
- Pas de clé de cloud permanente dans les secrets : avec OIDC, le pipeline obtient du fournisseur cloud un jeton valable quelques minutes (fiche 19).
- Méfie-toi des pull requests venues d'un fork : le déclencheur
pull_request_targets'exécute avec les secrets du dépôt. Combiné avec la récupération du code de la pull request, il donne tes secrets à n'importe quel contributeur extérieur. - Analyse ce que tu livres :
composer auditpour les dépendances PHP, et un outil comme Trivy pour les failles connues de l'image Docker.
Pièges fréquents
| Piège | Ce qui arrive | La parade |
|---|---|---|
| Une seule personne sait déployer | Elle part en congés, plus rien ne sort | Un pipeline que toute l'équipe sait lancer |
| Des branches qui vivent des semaines | Des fusions douloureuses, des combinaisons jamais testées | Des branches courtes, et des feature flags |
| Un pipeline rouge qu'on ignore | Plus personne ne remarque les vraies erreurs | Un pipeline rouge se répare en premier |
| Un pipeline de 40 minutes | L'équipe le contourne ou attend sans rien faire | Paralléliser, mettre en cache, échouer vite |
| Reconstruire l'image pour la production | On livre autre chose que ce qui a été vérifié | Une image par commit, promue d'un environnement à l'autre |
| Une recette différente de la production | Les bugs n'apparaissent qu'en production | Mêmes versions, même image, seule la configuration change |
| Une copie de la production en recette | Des données personnelles exposées à toute l'équipe | Des données anonymisées |
| Des feature flags jamais retirés | Des chemins de code morts que personne n'ose toucher | Une date de fin, et un ticket pour le retrait |
| Fixer un objectif sur un indicateur DORA | Les chiffres montent, la qualité non | Des indicateurs pour comprendre, pas pour noter |
| Des actions tierces non épinglées | Une action compromise vole tes secrets | Un identifiant de commit, et des droits minimaux |
Checklist d'un pipeline
- Chaque push lance le style, l'analyse statique, l'audit des dépendances et les tests.
- Le pipeline dure moins d'une dizaine de minutes, et un échec bloque la fusion.
- L'image est construite une seule fois, étiquetée par son commit, et promue telle quelle.
- Un test de fumée vérifie chaque déploiement avant d'aller plus loin.
- La production est à un bouton, que n'importe qui dans l'équipe sait utiliser.
- Recette et production ont les mêmes versions, et la recette n'a pas de données personnelles réelles.
- Les droits du pipeline sont minimaux, les actions tierces épinglées, et chaque environnement a ses propres secrets.
- Je connais, même approximativement, nos quatre indicateurs DORA.
Exercice : la revue d'un pipeline
Un collègue propose ce fichier pour le dépôt de la boutique. Il « marche » : le site est bien déployé. Ne l'exécute pas : lis-le comme tu lirais une pull request.
name: CI
on:
pull_request_target:
push:
permissions: write-all
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- uses: un-inconnu/setup-everything@main
- run: curl -s https://example.com/install-tools.sh | bash
- run: composer install
- run: 'echo "Clé de déploiement : ${{ secrets.PROD_DEPLOY_KEY }}"'
- run: ./deploy.sh production
env:
DEPLOY_KEY: ${{ secrets.PROD_DEPLOY_KEY }}
- run: vendor/bin/phpunit || true- Trouve au moins huit problèmes, de sécurité ou de fiabilité. Pour chacun, explique ce qui peut arriver concrètement.
- Classe-les : lesquels peuvent faire fuir des secrets ? Lesquels peuvent envoyer en production du code non testé ?
- Réécris le fichier en deux workflows, sur le modèle des sections 2 et 3 : un pour l'intégration continue, un pour la livraison.
- Rédige le commentaire de revue que tu laisserais à ton collègue. Il doit pouvoir corriger sans se sentir jugé (la fiche 15 reviendra sur la revue de code).
- Question de recul : l'équipe déploie aujourd'hui une fois par mois, un vendredi soir, à la main. Par quelle étape de cette fiche commencerais-tu pour changer ça, et pourquoi celle-là ?
Conseils
- Automatise ce qui fait mal en premier. Pas besoin de tout construire d'un coup : commence par l'étape manuelle qui cause le plus d'oublis ou de stress.
- Garde les scripts lisibles hors du pipeline. Un
deploy.shou unMakefilese lance aussi sur ton poste. Le pipeline ne fait que l'appeler, et changer d'outil de CI devient facile. - Lis les journaux de ton pipeline quand il est vert aussi : des avertissements, une étape qui ralentit d'un mois à l'autre, une dépendance qui ne se met plus en cache.
- DevOps, c'est d'abord des conversations. Avant d'écrire une ligne de YAML, demande à la personne qui déploie aujourd'hui ce qui lui fait peur. C'est souvent là qu'il faut commencer.
Documentation officielle
- GitHub Actions, dont le guide de sécurisation
- GitLab CI/CD (en anglais)
- The Twelve-Factor App, en français
- Le programme DORA, ses indicateurs et ses rapports (en anglais)
- OpenFeature, la norme commune des feature flags (en anglais)
- La commande
composer audit(en anglais) - Trivy, pour analyser les images Docker (en anglais)