Un lab clé en main de 40 minutes pour démystifier GitHub Actions et Azure Container Instances.
J’ai préparé ce lab pour un Knowledge Sharing interne chez Devoteam. L’objectif : montrer concrètement comment fonctionne le déploiement automatisé avec des containers, de A à Z, en partant de zéro avec un site imaginaire simpliste. Pas de théorie interminable, juste du concret.
On crée un site, on le containerise, on pousse sur GitHub, et ça se déploie tout seul sur Azure. Le tout en 40 minutes. Je partage ici le déroulé complet pour ceux qui voudraient le reproduire ou l’adapter. ⬇️
Si vous avez envie de voir l’ensemble du code de test immédiatement, je vous invite à consulter le repository GitHub qui est disponible à l’adresse suivante.
Beaucoup de développeurs et administrateurs système n’ont jamais touché aux containers. Ils en entendent parler, voient passer des mots comme Docker, Kubernetes, CI/CD, mais n’ont jamais franchi le pas. La raison ? Une impression de complexité et un manque de cas d’usage concret pour démarrer.
Au travers un exemple ultra basique, nous allons dérouler un exemple concret et visuel que vous pourrez reproduire de votre côté.
À la fin du lab, l’idée c’est de pouvoir faire les choses suivantes :
Les 2 briques Azures que nous allons utiliser :
Avant de commencer, assurez-vous d’avoir :
On part sur une structure classique que tout le monde connaît : HTML, CSS et JavaScript séparés. Pas de framework, pas de complexité. L’objectif est que les participants se concentrent sur le déploiement, pas sur le code. Tout en ayant quelque-chose de visuel à observer.
<!DOCTYPE html>
<html>
<head>
<title>Demo GitHub Actions - Devoteam</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<img src="https://upload.wikimedia.org/wikipedia/commons/7/79/Dev_logo_rgb.png" alt="Devoteam" class="logo">
<h1>Hello Devoteam!</h1>
<p>Déploiement automatique via GitHub Actions</p>
<div class="version">Version: 1.0.0</div>
<div class="tech-stack">Node.js + Docker + Azure Container Instances</div>
</div>
</body>
</html>
* {
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
margin: 0;
background: linear-gradient(135deg, #f8485e 0%, #3c3c3a 100%);
color: white;
}
.container {
text-align: center;
padding: 2rem;
}
.logo {
width: 200px;
margin-bottom: 2rem;
}
h1 {
font-size: 2.5rem;
margin-bottom: 0.5rem;
font-weight: 600;
}
p {
font-size: 1.2rem;
opacity: 0.9;
color: #fca2ae;
}
.version {
margin-top: 2rem;
padding: 1rem 2rem;
background: rgba(255,255,255,0.15);
border-radius: 8px;
border: 1px solid rgba(255,255,255,0.2);
}
.tech-stack {
margin-top: 1.5rem;
font-size: 0.9rem;
color: #d7ebe7;
}
Le fichier JavaScript qui sert nos fichiers statiques :
const http = require('http');
const fs = require('fs');
const path = require('path');
const server = http.createServer((req, res) => {
// Déterminer le fichier à servir
let filePath = req.url === '/' ? 'index.html' : req.url.substring(1);
// Déterminer le type de contenu
const ext = path.extname(filePath);
const contentTypes = {
'.html': 'text/html',
'.css': 'text/css',
'.js': 'application/javascript'
};
const contentType = contentTypes[ext] || 'text/plain';
// Lire et servir le fichier
fs.readFile(filePath, (err, content) => {
if (err) {
res.writeHead(404);
res.end('File not found');
} else {
res.writeHead(200, { 'Content-Type': contentType + '; charset=utf-8' });
res.end(content);
}
});
});
const port = process.env.PORT || 3000;
server.listen(port, () => {
console.log('Server running on port ' + port);
});
{
"name": "devo-tribe-azure-ks-dec-2025",
"version": "1.0.0",
"main": "server.js",
"scripts": {
"start": "node server.js"
}
}
Evidemment, n’hésitez pas à renommer les fichiers selon vos envies ou à changer le code HTML. J’ai séparé l’ensemble du code en plusieurs fichiers distincts afin de retrouver la logique standard du développement web à savoir un fichier CSS, HTML et JavaScript.
A ce moment-là vous pouvez déjà vérifier dans vos navigateur le look de notre page de test – mais nous allons plus loin afin de pouvoir mettre note site en container. ⬇️
Nous allons ajouter un nouveau fichier qui va nous permettre de créer un container. Pour que ça marche, vous devez avoir installé et démarré Docker Desktop sur votre ordinateur.
C’est ce fichier qui va nous permettre de créer un container de notre site.
FROM node:20-alpine
WORKDIR /app
COPY package.json ./
RUN npm install --production
COPY server.js ./
COPY index.html ./
COPY style.css ./
EXPOSE 3000
CMD ["npm", "start"]
Ligne par ligne, voici ce que cela dit :
FROM node:20-alpine : Part d’une image Linux légère avec Node.js préinstalléWORKDIR /app : Crée et se place dans le dossier /appCOPY package.json : Copie la config des dépendancesRUN npm install : Installe les dépendancesCOPY ... : Copie nos fichiersEXPOSE 3000 : Documente le port utilisé (sur lequel notre site sera visible)CMD : Commande lancée au démarrageExécutez les commandes suivantes :
docker build -t devo-tribe-azure-ks-dec-2025 .
docker run -d -p 3000:3000 --name devo-tribe-azure-ks-dec-2025 devo-tribe-azure-ks-dec-2025
Vous devriez avoir le rendu suivant dans votre terminal :
Et dans Docker Desktop, vous verrez que vous avez 1 image et 1 container en cours d’exécution basé sur cette image.
Par défaut, notre site sera accessible sur le port 3000. Donc ouvrez http://localhost:3000 pour votre vote site et vérifiez que ça fonctionne bien.
Point important : je n’ai même pas Node.js installé sur ma machine. Tout est dans le container. C’est justement ça tout l’intérêt de Docker dans notre cas d’usage. 👍
Voici ce que j’ai dans mon VS Code :
A ce niveau, vous pouvez donc modifier votre site internet, ajouter des pages, transformer le code, créer une nouvelle version et valider localement sur votre ordinateur que le rendu est conforme à vos attentes. Quand vous êtes prêt, n’oubliez pas commit et push votre code au sein de votre repos GitHub (nous en aurons besoin pour utiliser GitHub Actions).
Connectez-vous en Azure CLI à votre Tenant et souscription. Commençons par créer une Resource Group de test et notre objet Azure Container Registry.
$RG_NAME="RG-Demo-CICD"
$ACR_NAME="acrdevoteamdemo"
az acr create --resource-group $RG_NAME --name $ACR_NAME --sku Basic
Note : le nom de l’ACR doit être unique et en minuscules.
Le Service Principal permet à GitHub de s’authentifier à Azure (nous en aurons besoin afin de permettre à GitHub Actions de gérer notre code et mettre à jour notre code tout seul) :
$RG_NAME="RG-Demo-CICD"
$SUBSCRIPTION_ID="votre-subscription-id"
az ad sp create-for-rbac --name "sp-github-actions-demo" --role contributor --scopes /subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RG_NAME
Cette commande retourne un JSON avec 4 valeurs importantes :
appId : AZURE_CLIENT_IDpassword : AZURE_CLIENT_SECRETtenant : AZURE_TENANT_IDGardez les de côté car nous allons créer des GitHub Secrets pour chacune de ces infos. Si vous le souhaitez, vous pouvez également aller vérifier dans Entra ID et vous verrez que vous disposez d’une nouvelle App Registration correspondant au nom de notre Service Principal : sp-github-actions-demo.
Dans votre repo GitHub : Settings → Secrets and variables → Actions → New repository secret
Créez ces 4 secrets :
AZURE_CLIENT_IDAZURE_CLIENT_SECRETAZURE_TENANT_IDAZURE_SUBSCRIPTION_IDToujours dans votre dossier de travail, nous allons générer un dossier ainsi qu’un fichier avec l’extension YML à un emplacement bien particulier. Ne vous trompez pas car c’est ce qui permet à GitHub de savoir qu’il va devoir réaliser des tâches seul (ce que l’on appelle un workflow).
Dans notre scénario de test, je vous rappelle que l’objectif c’est que dès que nous réalisons un commit + push de notre code et bien cela soit mis à jour tout seul dans Azure ! ♾️
Créez le fichier .github/workflows/deploy.yml :
name: Build and Deploy to Azure
on:
push:
branches:
- main
workflow_dispatch:
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Azure login
uses: azure/login@v2
with:
creds: |
{
"clientId": "${{ secrets.AZURE_CLIENT_ID }}",
"clientSecret": "${{ secrets.AZURE_CLIENT_SECRET }}",
"subscriptionId": "${{ secrets.AZURE_SUBSCRIPTION_ID }}",
"tenantId": "${{ secrets.AZURE_TENANT_ID }}"
}
- name: Login to Azure Container Registry
run: |
az acr login --name acrdevoteamdemo
- name: Build and push image to ACR
run: |
az acr build \
--registry acrdevoteamdemo \
--image devo-tribe-azure-ks-dec-2025:${{ github.sha }} \
--image devo-tribe-azure-ks-dec-2025:latest \
--file Dockerfile \
.
- name: Deploy to Azure Container Instances
run: |
az container create \
--resource-group RG-Demo-CICD \
--name devo-tribe-azure-ks-dec-2025 \
--image acrdevoteamdemo.azurecr.io/devo-tribe-azure-ks-dec-2025:latest \
--registry-login-server acrdevoteamdemo.azurecr.io \
--registry-username ${{ secrets.AZURE_CLIENT_ID }} \
--registry-password ${{ secrets.AZURE_CLIENT_SECRET }} \
--dns-name-label devo-tribe-azure-ks-dec-2025 \
--ports 80 \
--os-type Linux \
--cpu 1 \
--memory 1 \
--environment-variables PORT=80
Ce que fait ce workflow ↙️
➡️ Le bloc on définit les déclencheurs : le workflow s’exécute à chaque push sur la branche main, ou manuellement via l’interface GitHub (c’est le workflow_dispatch).
➡️ Les variables d’environnement (env) centralisent la configuration : nom du registry, de l’image, du resource group, etc. Ça évite de répéter ces valeurs partout et facilite l’adaptation à d’autres projets.
➡️ Le job build-and-deploy tourne sur une machine Ubuntu hébergée par GitHub. Les steps s’enchaînent :
az acr build) et la stocke dans l’ACRLe container est configuré avec 1 CPU, 1 Go de RAM, et expose le port 80. La variable d’environnement PORT=80 est passée au container pour que notre serveur Node.js écoute sur le bon port.
Tout est prêt – il ne nous reste plus qu’à tester ! 🤯
Une fois que vous êtes prêt, il ne vous reste plus qu’à commit & push votre code sur GitHub. Si votre workflow est bon, cela aura pour effet d’exécuter notre workflow GitHub Actions qui doit créer notre Azure Container Instance et publier notre code. Notre site devrait alors être accessible via une URL générée par Azure. 😉
Que vous fassiez votre push & commit via VS Code ou en CLI, vous pourrait observer l’effet dans GitHub Actions :
Notre workflow s’est correctement exécuté. Aucune erreur. ✅
Nous pouvons maintenant aller dans notre Resource Group de test et voir si notre ACI a été créé :
Et retrouver l’URL d’accès : devo-tribe-azure-ks-dec-2025.francecentral.azurecontainer.io dans mon cas.
Attention lors du test, notre site écoute sur le port 80 et les nouveaux navigateurs d’aujourd’hui ont tendance à forcer le https sur le port 443/TCP. Donc forcez bien http sans le S dans l’URL. 😉
Bravo, notre site est fonctionnel ! ✅
Maintenant ce qui est intéressant : imaginez que vous avez des mises à jour à effectuer sur votre site. Dans mon exemple, je vais juste changer dans index.html le Version 1.0.0 en 2.1.0 par exemple (ou même un couleur dans le CSS).
Il vous suffit de faire vos modifications et quand vous avez terminé, sauvegardez et faîtes un commit + push de votre code sur GitHub. Cela aura pour effet automatique de déclencher notre workflow et mettre à jour notre site. 😎
git add .
git commit -m "Update to version 2.0.0"
git push
Rafraîchissez la page Azure après 2 minutes : la version a changé automatiquement. Pas de FTP, pas de copier-coller, pas d’intervention manuelle. Votre site est à jour. 👍
Nous pouvons voir que notre site a bien été mis à jour !
Ce que nous avons compris :
Ce lab utilise Azure Container Instances (ACI) qui est parfait pour une démo ou du dev. Pour la production, explorez :
Cet article est basé sur une présentation / démo interne réalisée au sein de Devoteam M Cloud en décembre 2025. Vous pouvez retrouver le repository Github avec le code en suivant ce lien. Ainsi qu’une copie de la présentation PowerPoint ci-dessous.
MCT 2025-2026 : renouvellement de mon statut Microsoft Certified Trainer Mon statut Microsoft Certified Trainer…
S3NS Obtient la Qualification SecNumCloud : Un pas de géant pour la Sécurité du Cloud…
Déployer automatiquement son site avec GitHub Actions et SFTP Il y a quelques temps j'ai…
Proton Sheets : Une Nouvelle Alternative à Excel Online et Google Sheets Introduction Proton Sheets,…
Azure Bastion : authentification Entra ID en preview pour les connexions RDP via le portail…
Plex met fin à la gratuité : Ce que cela signifie pour les utilisateurs Introduction…