## Intro

Ce guide explique l'architecture Linux en termes pratiques et montre comment construire un petit service HTTP que vous pouvez exécuter localement et étendre vers des conteneurs et l'orchestration. Vous apprendrez comment le noyau, les processus, les systèmes de fichiers, le réseau et le système d'initialisation travaillent ensemble, comment les requêtes traversent la pile, les points de défaillance courants et les compromis opérationnels. À la fin, vous disposerez d'un exemple fonctionnel supervisé par systemd, frontal avec Nginx, conteneurisé avec Docker et, optionnellement, orchestré avec Kubernetes.

## Architecture Linux en un coup d'œil

Du bas vers le haut :

- Matériel exécute les instructions et gère les interruptions des périphériques.

- Noyau Linux gère l'ordonnancement CPU, la mémoire, les périphériques, les systèmes de fichiers et le réseau ; il expose une interface d'appels système.

- Bibliothèque C (glibc) et runtimes de langages encapsulent les appels système.

- Système d'initialisation (systemd) amène la machine à un état utilisable et supervise les services.

- Espace utilisateur contient les shells (Bash), les démons et les applications.

- Espaces de noms de système de fichiers présentent les ressources comme des fichiers sous / , avec /proc et /sys exposant l'état du noyau.

- Réseau fournit des sockets via le noyau, avec interfaces, routes, règles de pare-feu et résolution de noms.

Ces couches forment un modèle cohérent : les processus en espace utilisateur interagissent avec le noyau via des descripteurs de fichiers et des appels système, tandis que le système d'initialisation contrôle les cycles de vie des services.

## Flux de contrôle et flux de données

Flux de contrôle :

- Un processus appelle le noyau via des appels système ( open , read , write , socket , connect , accept , fork , execve ).

- systemd utilise les cgroups pour placer les services dans des groupes à ressources contrôlées et les redémarre en cas d'échec.

- Les signaux ( SIGTERM , SIGKILL ) contrôlent les cycles de vie des processus. Les minuteurs, sockets et unités dans systemd aident à structurer le démarrage des services.

Flux de données :

- L'espace utilisateur lit et écrit des descripteurs de fichiers (fichiers, tubes, sockets). L'I/O de stockage passe par le VFS vers les pilotes de systèmes de fichiers et la couche de blocs. L'I/O réseau passe par l'API socket vers les piles de protocoles (TCP, UDP) et les pilotes de cartes réseau.

- Une requête web typique suit : client → carte réseau → pile TCP/IP noyau → processus serveur accept() → gestionnaire utilisateur → système de fichiers ou service amont → réponse write() → pile TCP/IP noyau → carte réseau → client.

Astuces d'inspection :

uname -a # noyau et plateforme
ps -ef | grep APP # arborescence des processus
ls -l /proc/$$/fd # descripteurs du shell courant
ss -ltnp # sockets et listeners
sudo journalctl -xe # messages système récents 

## Exemple pratique : un petit service HTTP

 Nous allons implémenter un service HTTP JSON minimal écoutant sur 127.0.0.1:5000 , le gérer avec systemd, placer Nginx devant, puis le conteneuriser.

Créez /opt/app/app.py :

#!/usr/bin/env python3
from http.server import BaseHTTPRequestHandler, HTTPServer
import json

class H(BaseHTTPRequestHandler):
 def do_GET(self):
 if self.path == “/healthz”:
 self.send_response(200)
 self.send_header(“Content-Type”, “text/plain”)
 self.end_headers()
 self.wfile.write(b“ok\n”)
 return
 self.send_response(200)
 self.send_header(“Content-Type”, “application/json”)
 self.end_headers()
 body = {“message”: “hello”, “path”: self.path}
 self.wfile.write(json.dumps(body).encode(“utf-8”))

if __name__ == “__main__”:
 HTTPServer((“127.0.0.1”, 5000), H).serve_forever() 
 Installez et testez rapidement :

sudo mkdir -p /opt/app && sudo chown -R "$USER":"$USER" /opt/app
chmod +x /opt/app/app.py
/opt/app/app.py & # test rapide
curl -s http://127.0.0.1:5000/ | jq . || curl -s http://127.0.0.1:5000/
kill %1 
 Cela met en place un chemin de requête simple que vous pouvez observer de bout en bout.

## Gestion avec systemd et Bash

Utilisez systemd pour superviser le service et Bash pour gérer les tâches courantes.

Créez /etc/systemd/system/hello.service :

[Unit]
Description=Hello HTTP service
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/opt/app
ExecStart=/usr/bin/env python3 /opt/app/app.py
Restart=on-failure
RestartSec=2s
AmbientCapabilities=CAP_NET_BIND_SERVICE
NoNewPrivileges=true

[Install]
WantedBy=multi-user.target 
 Activez et démarrez :

sudo systemctl daemon-reload
sudo systemctl enable --now hello.service
sudo systemctl status hello.service --no-pager
curl -s http://127.0.0.1:5000/ | head -n1 
 Assistant Bash pour les opérations courantes, /usr/local/bin/helloctl :

#!/usr/bin/env bash
set -euo pipefail
case "${1:-}" in
 start) sudo systemctl start hello.service ;;
 stop) sudo systemctl stop hello.service ;;
 status) systemctl --no-pager status hello.service ;;
 logs) sudo journalctl -u hello.service -n 200 -f ;;
 reload) sudo systemctl restart hello.service ;;
 *) echo "usage: $0 {start|stop|status|logs|reload}" ; exit 2 ;;
esac 
 Installez l'assistant et inspectez les flux :

sudo install -m 0755 /usr/local/bin/helloctl /usr/local/bin/helloctl
ss -ltnp | grep 5000
ps -o pid,ppid,cmd,pmem,etime -C python3
sudo journalctl -u hello.service -n 50 --no-pager 
 Points de contrôle du flux de contrôle et de données :

- Contrôle : systemd → ExecStart → processus → signaux lors du redémarrage/arrêt.

- Données : client → 127.0.0.1:5000 → application → réponse.

## Mise en place de Nginx en frontal

Placez Nginx devant pour la terminaison TLS et le routage. Installez Nginx via le gestionnaire de paquets de votre distribution, puis créez /etc/nginx/conf.d/hello.conf :

server {
 listen 80;
 server_name _;

 location /healthz {
 proxy_pass http://127.0.0.1:5000/healthz;
 }

 location /api/ {
 proxy_pass http://127.0.0.1:5000/;
 proxy_set_header Host $host;
 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 }

 location / {
 root /usr/share/nginx/html;
 index index.html;
 }
} 
 Testez et rechargez :

sudo nginx -t && sudo systemctl reload nginx
curl -s http://127.0.0.1/api/ | head -n1 
 Le flux de données devient : client → Nginx (port 80) → loopback → application (5000) → Nginx → client.

## Conteneurisation avec Docker

Empaquetez l'application pour la portabilité.

Créez /opt/app/requirements.txt (vide pour la bibliothèque standard) et Dockerfile :

FROM python:3.11-slim
WORKDIR /opt/app
COPY app.py .
EXPOSE 5000
USER 1000:1000
CMD ["python", “/opt/app/app.py”] 
 Construisez et exécutez :

cd /opt/app
sudo docker build -t hello-app:local .
sudo docker run --rm -p 5000:5000 --name hello hello-app:local &
curl -s http://127.0.0.1:5000/ | head -n1
sudo docker stop hello 
 Vous pouvez aussi gérer le conteneur avec systemd pour unifier les opérations :

[Service]
ExecStart=/usr/bin/docker run --rm --name hello -p 5000:5000 hello-app:local
ExecStop=/usr/bin/docker stop hello
Restart=on-failure 

## Orchestration avec Kubernetes (optionnel)

 Si vous utilisez un cluster local (par ex. kind ou minikube), déployez avec :

hello-deploy.yaml :

apiVersion: apps/v1
kind: Deployment
metadata:
 name: hello
spec:
 replicas: 2
 selector:
 matchLabels:
 app: hello
 template:
 metadata:
 labels:
 app: hello
 spec:
 containers:
 - name: hello
 image: hello-app:local
 imagePullPolicy: IfNotPresent
 ports:
 - containerPort: 5000 
 hello-svc.yaml :

apiVersion: v1
kind: Service
metadata:
 name: hello
spec:
 selector:
 app: hello
 ports:
 - name: http
 port: 80
 targetPort: 5000
 protocol: TCP
 type: ClusterIP 
 Appliquez et testez avec un port-forward :

kubectl apply -f hello-deploy.yaml -f hello-svc.yaml
kubectl port-forward svc/hello 8080:80 &
curl -s http://127.0.0.1:8080/ | head -n1 

## Observabilité, points de défaillance, compromis

 Commandes d'observabilité clés :

- État système : uname -a , uptime , dmesg --level err,warn

- Processus : ps -ef , pstree -a , systemctl status , journalctl -u NAME

- Réseau : ip addr , ip route , ss -ltnp , dig , curl -v

- Fichiers et descripteurs : lsof -p PID , ls -l /proc/PID/fd

Points de défaillance courants :

- Ports et liaison : mauvaise adresse ( 0.0.0.0 vs 127.0.0.1 ), port déjà utilisé, règles de pare-feu.

- Permissions : liaison sur ports privilégiés (<1024), permissions de fichiers, refus SELinux/AppArmor.

- Limites de ressources : pression mémoire provoquant des OOM kills, ulimit -n trop faible, throttling CPU.

- Plantages et redémarrages : dépendances manquantes, différences d'environnement, mauvaise gestion des signaux.

- Problèmes de proxy : incompatibilité amont Nginx, timeouts, limites de taille d'en-têtes, limites de taille de corps.

- Conteneurs : image manquante, mauvais tag, mapping de ports, particularités du système de fichiers overlay, DNS dans le conteneur.

- Kubernetes : sondes de readiness échouent, sélecteurs de Service ne correspondent pas, ressources insuffisantes.

Compromis :

- Service direct vs derrière Nginx : simplicité vs TLS centralisé, routage, mise en cache.

- Processus nu vs conteneur : intégration hôte et vitesse vs empaquetage et isolation.

- systemd vs supervision par runtime conteneur : outillage natif OS vs workflows centrés image.

- Orchestration : puissant contrôle de scaling et de déploiement vs complexité ajoutée.

## Aperçu du flux de travail

Suivez ces étapes pour gagner en confiance et en clarté :

- Vérifiez la plateforme

- Noyau et distribution : uname -a; cat /etc/os-release

- Confirmez que les ports sont libres : ss -ltn | grep -E “:(80|5000)” || true

- Construisez l'application

- Créez /opt/app/app.py et exécutez-la au premier plan

- Testez avec curl http://127.0.0.1:5000/

- Ajoutez la supervision

- Créez hello.service , activez et démarrez

- Validez avec systemctl status et journalctl -u hello.service

- Ajoutez le proxy

- Installez Nginx, ajoutez hello.conf , rechargez

- Validez le chemin proxy : curl http://127.0.0.1/api/

- Conteneurisez

- Écrivez Dockerfile , construisez hello-app:local

- Exécutez le conteneur, validez avec curl

- Unifiez les opérations

- Décidez si systemd lance l'application directement ou gère docker run

- Documentez start/stop/logs dans helloctl

- Orchestration optionnelle

- Si nécessaire, déployez sur un cluster local et testez avec port-forward

À chaque étape, privilégiez de petits changements testables avec des retours en arrière clairs.

## Plan pilote local

Objectif : prouver la pile sur un poste de travail unique avec des critères de réussite clairs.

Périmètre (restreint) :

- Un seul hôte, trafic loopback uniquement

- Application sur 127.0.0.1:5000 , Nginx sur :80 proxyant /api/

- Point de santé basique à /healthz

Plan (environ 60 à 90 minutes) :

- Test de l'application

- Exécutez /opt/app/app.py au premier plan ; curl / et /healthz

- Succès si les deux renvoient 200 et les corps attendus

- Supervision systemd

- Installez hello.service ; démarrez ; confirmez le redémarrage après pkill

- Succès si le service redémarre et les logs sont visibles

- Proxy Nginx

- Configurez hello.conf ; curl /api/ et /healthz

- Succès si les chemins proxy renvoient 200 et le bon contenu

- Vérification conteneur

- Construisez hello-app:local ; exécutez ; curl l'endpoint local

- Succès si l'application conteneurisée se comporte de manière identique

Mesures :

- Latence p50 sous 20 ms localement : for i in {1..20}; do time -p curl -s http://127.0.0.1/api/ >/dev/null; done

- Empreinte mémoire sous 100 Mo RSS pour le processus d'application

Critères de sortie :

- Tous les tests de réussite passent ; analyse d'échec documentée avec extraits de sorties de commandes

Ce pilote est volontairement petit, mesurable et facile à inspecter localement avant tout déploiement plus large.

## Conclusion

Vous avez cartographié l'architecture Linux du noyau à l'espace utilisateur, tracé comment le contrôle et les données circulent à travers les processus, les systèmes de fichiers et le réseau, et construit un service HTTP pratique géré par systemd, frontal avec Nginx, empaqueté dans Docker, avec une option d'exécution sous Kubernetes. Vous avez également vu les points de défaillance courants et comment les observer et les déboguer. Prochaine étape : étendez le pilote en ajoutant TLS dans Nginx, une journalisation structurée et une tâche CI basique qui construit et exécute le conteneur localement. Gardez les changements minimes, validez chaque étape et capturez ce qui a fonctionné pour que l'équipe puisse appliquer le patron au service suivant.