\newpage
Introduction
Ce laboratoire, le Lab 4, se concentre sur l’intégration de la gestion de version, des systèmes de build et de l’automatisation des tests. L’enjeu est de garantir que chaque modification apportée au code ou à l’infrastructure soit traçable, reproductible et systématiquement validée avant d’atteindre les environnements de production sur AWS.
Maîtrise de la Gestion de Version et Collaboration
Le contrôle de version constitue la chose primordiale de toute une démarche DevOps. Au-delà de la simple sauvegarde, nous avons utilisé Git pour instaurer une stratégie d’isolation des développements. En pratiquant le “Feature Branching”, nous avons appris à diverger de la branche principale pour expérimenter sur une branche testing. Par exemple, après avoir initialisé le dépôt et configuré nos identités (git config —global user.name “Lina”), nous avons exécuté la séquence suivante pour isoler nos changements :
git checkout -b testing
echo 'Modification expérimentale pour le Lab 4' >> example.txt
git add example.txt
git commit -m "feat: ajout de contenu expérimental sur branche testing"
git checkout main
git merge testingCette approche permet de protéger la branche stable tout en permettant une itération rapide. Nous avons également marqué nos étapes clés par des étiquettes de version avec la commande git tag v1.0, facilitant ainsi le suivi des points de livraison.
Automatisation du Build et standardisation via NPM
Configuration du package.json
Le système de build fait le pont entre le code source et la partie exécutable. Nous avons exploité les capacités de NPM pour transformer le fichier package.json en un centre de commande qui sera automatisé. Nous y avons intégré les dépendances nécessaires et défini des scripts personnalisés pour uniformiser les commandes de l’équipe :
"scripts": {
"start": "node server.js",
"dockerize": "./build-docker-image.sh",
"test": "jest --verbose"
},
"dependencies": {
"express": "^4.19.2"
}Script de Build Docker
Nous avons aussi rédigé un script Bash de build Docker (build-docker-image.sh). Ce script automatise la récupération du nom et de la version du projet afin de taguer l’image de manière dynamique, avant de lancer un docker capable de générer des images compatibles avec les architectures Cloud :
#!/usr/bin/env bash
set -e
# Récupération du nom et de la version
name=$(npm pkg get name | tr -d '"')
version=$(npm pkg get version | tr -d '"')
# Build multi-plateforme
docker buildx build \
--platform=linux/amd64,linux/arm64 \
--load \
-t "$name:$version" \Développement Agile et Gestion des Dépendances
Dans une optique d’évolution logicielle, nous avons migré notre serveur d’un modèle HTTP vers un framework Express.js. En réécrivant notre fichier app.js, nous avons implémenté des routes plus complexes, notamment pour l’exercice 7 où nous avons créé un endpoint utilisant des paramètres d’URL :
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('Hello, World!');
});
// Exercice 7 : Implémentation du paramètre :name
app.get('/name/:name', (req, res) => {
res.send(`Hello, ${req.params.name}!`);
});
module.exports = app;Cette modification illustre comment une architecture modulaire permet d’étendre rapidement les fonctionnalités d’une API tout en conservant une structure de code lisible et maintenable.
Stratégie de Tests Applicatifs avec Jest et SuperTest
Refactorisation du code source (app.js)
La fiabilité logicielle repose sur l’automatisation des tests. Nous avons adopté une approche où la logique applicative est séparée du démarrage du serveur, permettant ainsi à Jest et SuperTest d’effectuer des tests d’intégration.
const express = require('express');
const app = express();
// Route racine par défaut
app.get('/', (req, res) => {
res.send('Hello, World!');
});
// Exercice 7 : Paramétrage dynamique de l'endpoint
app.get('/name/:name', (req, res) => {
res.send(`Hello, ${req.params.name}!`);
});
module.exports = app; // Export pour ne pas bloquer le processus de testImplémentation des tests unitaires (app.test.js)
Nous avons écrit des tests pour garantir que nos routes répondent les bons codes HTTP et les bons messages.
const request = require('supertest');
const app = require('./app');
describe('Suite de validation des endpoints API', () => {
test('Réponse nominale sur la racine', async () => {
const response = await request(app).get('/');
expect(response.statusCode).toBe(200);
expect(response.text).toBe('Hello, World!');
});
test('Validation du paramètre dynamique', async () => {
const response = await request(app).get('/name/Lina');
expect(response.text).toBe('Hello, Lina!');
});
});Pour valider l’efficacité de notre filet de sécurité, nous avons délibérément introduit un bug (exercice 6) avant de rétablir la version correcte, garantissant qu’aucune régression n’est introduite lors des futures mises à jour.
Figure 1 : Validation des tests unitaires et d’intégration.
Validation de l’Infrastructure et Tests de Déploiement
En Devops on doit aussi tester l’infrastructure. En utilisant OpenTofu, nous avons mis en œuvre des tests d’infrastructure (“IaC Testing”). Nous avons configuré un fichier deploy.tftest.hcl qui orchestre un scénario complet. Pour ce faire, nous avons créé un module test-endpoint dont le code main.tf utilise une ressource de données HTTP :
data "http" "test_endpoint" {
url = var.endpoint
}
# Assertion dans le fichier de test principal
assert {
condition = data.http.test_endpoint.status_code == 200
error_message = "Échec : L'API Gateway AWS a renvoyé un code ${data.http.test_endpoint.status_code}"
}Cette validation “bout-en-bout” assure que non seulement le code fonctionne, mais que le réseau, les permissions IAM et les services AWS sont correctement interconnectés.
Figure 2 : Pipeline de CI/CD GitHub Actions montrant le succès des tests applicatifs et d’infrastructure.
Problèmes rencontrés et Solutions
Durant ce laboratoire, nous avons été confrontées à plusieurs défis techniques. Le premier concernait la gestion des dépendances lors de la conteneurisation Docker ; l’oubli du fichier package-lock.json provoquait des versions de paquets divergentes entre le local et le conteneur. Nous avons résolu cela en utilisant la commande npm ci au lieu de npm install dans le Dockerfile. Un autre point de blocage est apparu lors de la mise en place des tests OpenTofu : l’API Gateway mettait quelques secondes à être réellement active après le signal de succès du déploiement, provoquant des échecs de test intermittents. Nous avons dû affiner les mécanismes d’attente pour stabiliser la pipeline. Enfin, la gestion des permissions AWS (IAM) a nécessité une attention particulière pour permettre à la Lambda d’écrire ses logs tout en restant accessible via l’API Gateway.
Conclusion
Ce laboratoire nous a permis de comprendre l’importance de l’automatisation dans la vie d’un logiciel. En passant d’un mode de développement manuel à une approche automatisée, nous avons réduit les risques d’erreurs humaines. La mise en place de Git pour la traçabilité, de NPM pour la reproductibilité et de la suite de tests (Jest/OpenTofu) pour la fiabilité constitue le socle d’une démarche DevOps réussie. Les résultats obtenus, visibles sur nos pipelines GitHub Actions et dans la console AWS, démontrent qu’une infrastructure bien testée est le gage d’une livraison continue sereine et performante.