Comment fonctionne ce site ?
Le site Hugo sur KubernetesPrésentation du projet
Ce site a été créé pour vous offrir un aperçu clair et complet de mes compétences et de mon travail. Mon but est de vous présenter mes projets, les technologies que je maîtrise, et comment je les utilise pour résoudre des problèmes concrets.
Ce portfolio a plusieurs objectifs :
- Mettre en avant mes projets : Vous y trouverez des détails sur les projets sur lesquels j’ai travaillé, montrant comment j’ai appliqué mes compétences pour atteindre des résultats tangibles.
- Illustrer mes compétences : Le site présente les technologies et outils que j’utilise, ainsi que mon approche pour les intégrer efficacement dans mes projets.
- Partager mon expérience : À travers des articles et des études de cas, je décris les défis que j’ai rencontrés et les solutions que j’ai mises en place, offrant ainsi un aperçu de mon processus de travail.
En utilisant Hugo pour créer ce site statique et en le déployant sur Kubernetes, j’ai non seulement développé un espace pour partager mon travail, mais aussi démontré ma capacité à gérer des projets techniques de bout en bout.
Choix de technologies et architecture
Hébergement
Pour rendre le site accessible, j’utilise un VPS (Infrastructure as a Service), ce qui me donne un contrôle total sur l’environnement d’exécution et me permet d’expérimenter des technologies comme Kubernetes en conditions réelles.
Générateur de site
Le site est un site statique généré avec Hugo, couplé au moteur de template Hugo Blox. Hugo compile l’ensemble du site en fichiers HTML/CSS statiques, ce qui le rend rapide et simple à servir.
Stack de déploiement : Kubernetes avec k3s
La grande évolution de ce site est la migration vers k3s, une distribution légère de Kubernetes parfaitement adaptée à un VPS. L’objectif était de remplacer une stack Docker Compose + Apache + Certbot par une architecture moderne, déclarative et automatisée.
Voici l’architecture cible :
Internet
│
▼
Traefik (Ingress Controller) ← intégré dans k3s, écoute sur :80 et :443
│
├── HTTP :80 → Middleware (redirection automatique vers HTTPS)
│
└── HTTPS :443 → Service portfolio
│
▼
Pod nginx (site statique)
Les composants Kubernetes
Dockerfile - l’image est le site
Le changement de paradigme principal par rapport à Docker Compose : plutôt que de monter un volume contenant les sources, l’image Docker embarque directement le site compilé. Cela garantit que chaque déploiement est reproductible et immutable.
# Stage 1 : build Hugo
FROM hugomods/hugo:nightly AS builder
WORKDIR /site
RUN npm install -g hugoblox tailwindcss
ENV PATH=/site/node_modules/.bin:/usr/local/bin:$PATH
COPY package.json .
RUN npm install
COPY . .
RUN hugoblox build
# Stage 2 : serveur nginx léger
FROM nginx:alpine
COPY --from=builder /site/public /usr/share/nginx/html
Ce build multi-stage permet de garder une image finale légère : seul nginx et les fichiers statiques compilés sont embarqués.
Deployment
Le Deployment est le chef d’orchestre des pods. Il garantit qu’un nombre défini de réplicas tourne en permanence, et gère les mises à jour sans interruption de service (Rolling Update).
apiVersion: apps/v1
kind: Deployment
metadata:
name: portfolio
spec:
replicas: 2
selector:
matchLabels:
app: portfolio
template:
metadata:
labels:
app: portfolio
spec:
containers:
- name: portfolio
image: registry.gitlab.com/USER/REPO:latest
ports:
- containerPort: 80
imagePullSecrets:
- name: gitlab-registry-secret
Avec replicas: 2, Kubernetes maintient deux pods actifs en permanence. Lors d’un déploiement, il démarre le nouveau pod, attend qu’il soit prêt, puis coupe l’ancien — garantissant ainsi zéro downtime.
Service
Le Service de type ClusterIP expose les pods en interne au cluster avec une adresse IP stable. Les pods peuvent mourir et redémarrer avec de nouvelles IP, le Service reste toujours le même point d’entrée. Il assure également le load balancing entre les réplicas automatiquement.
Ingress
L’Ingress définit les règles de routage HTTP/HTTPS. Il indique à Traefik quel domaine diriger vers quel Service, et déclare la gestion du TLS :
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: portfolio
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
traefik.ingress.kubernetes.io/router.entrypoints: web,websecure
traefik.ingress.kubernetes.io/router.middlewares: default-redirect-https@kubernetescrd
spec:
tls:
- hosts:
- martin-genereux.fr
secretName: portfolio-tls
rules:
- host: martin-genereux.fr
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: portfolio
port:
number: 80
Certificat SSL — cert-manager remplace Certbot
L’ancien setup nécessitait de lancer manuellement un conteneur Certbot tous les 3 mois via un cron. Avec cert-manager, la gestion des certificats Let’s Encrypt est entièrement automatisée et native à Kubernetes.
Un ClusterIssuer configure cert-manager pour communiquer avec l’API Let’s Encrypt :
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
email: martingenereuxccl@gmail.com
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-prod-key
solvers:
- http01:
ingress:
class: traefik
Dès que l’Ingress est créé avec l’annotation cert-manager.io/cluster-issuer, cert-manager détecte automatiquement le besoin d’un certificat, effectue le challenge HTTP-01 via Traefik, et stocke le certificat dans un Secret Kubernetes. Le renouvellement est également automatique.
Middleware — redirection HTTP vers HTTPS
Un Middleware Traefik intercepte toutes les requêtes HTTP et les redirige en HTTPS de manière permanente (301) :
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: redirect-https
namespace: default
spec:
redirectScheme:
scheme: https
permanent: true
Pipeline CI/CD
Le pipeline GitLab CI a été entièrement revu. L’ancienne approche copiait les fichiers via SSH sur le serveur. La nouvelle approche build une image Docker, la pousse sur la GitLab Registry, puis déclenche un Rolling Update sur le cluster k3s.
stages:
- build-image
- deploy
variables:
IMAGE_LATEST: $CI_REGISTRY_IMAGE:latest
build-image:
tags:
- docker
stage: build-image
image: docker:24
services:
- docker:dind
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
script:
- docker build -t $IMAGE_LATEST .
- docker push $IMAGE_LATEST
deploy:
tags:
- springVps
stage: deploy
image: alpine:latest
before_script:
- apk update
- apk add --no-cache openssh-client
- chmod 400 $SSHVPS
- mkdir -p ~/.ssh
- chmod 700 ~/.ssh
script:
- ssh -i $SSHVPS -o StrictHostKeyChecking=no -p 2879 root@martin-genereux.fr "kubectl set image deployment/portfolio portfolio=$IMAGE_LATEST"
Le flux complet lors d’un git push :
- GitLab CI build une nouvelle image Docker contenant le site compilé
- L’image est poussée sur la GitLab Container Registry
kubectl set imagedéclenche un Rolling Update sur k3s- Kubernetes démarre un nouveau pod avec la nouvelle image, attend qu’il soit prêt, puis coupe l’ancien
- Zéro downtime, zéro intervention manuelle
Bénéfices de la migration
| Ancienne stack | Nouvelle stack | |
|---|---|---|
| Serveur web | Apache | nginx |
| SSL | Certbot (cron manuel) | cert-manager (automatique) |
| Déploiement | Copie SSH des fichiers | Rolling Update Kubernetes |
| Haute disponibilité | ✗ | ✓ (2 réplicas) |
| Load balancing | ✗ | ✓ (natif Kubernetes) |
| Infrastructure as Code | Docker Compose | Manifests Kubernetes versionnés |
Évolutions futures
- Migration des autres projets (API FastAPI, base de données MySQL, application Vue.js) vers le même cluster k3s
- Utilisation de Helm pour simplifier le déploiement des composants complexes comme MySQL
- Mise en place de Liveness & Readiness Probes pour une meilleure gestion de la santé des pods
- Séparation des environnements par Namespaces Kubernetes

Développeur backend et DevOps avec 4 ans d’expérience en conception et déploiement de systèmes en production. J’ai travaillé sur des APIs REST, des pipelines de données et de l’automatisation CI/CD sur environnements conteneurisés (Docker, GitLab CI).
À l’aise sur C#/.NET, Python et PostgreSQL, j’interviens aussi bien sur le code que sur l’infrastructure — Ansible, Linux, monitoring.
Curieux des architectures microservices et du cloud Azure, je cherche un environnement technique exigeant où backend et DevOps se rejoignent.