De Docker Compose à Kubernetes : architecture complète, distributions (K8s, K3s, K0s, MicroK8s), objets fondamentaux, networking, Ingress, scaling automatique et déploiement en production.
Dans un cluster Kubernetes, chaque pod a une IP privée interne. Pour exposer une application à l'extérieur — avec un vrai domaine et du HTTPS — il faut un Ingress Controller. Ce chapitre installe NGINX Ingress, configure des règles de routage, et automatise les certificats TLS avec cert-manager.
Chaque pod obtient une IP unique dans le réseau du cluster (généralement 10.244.x.x ou 10.42.x.x pour K3s). Ces IPs ne sont pas accessibles de l'extérieur.
Internet
│
▼
Load Balancer / IP publique (port 80/443)
│
▼
Ingress Controller (pod NGINX)
│
├── /api/* → Service api-service:80 → Pods api (10.42.1.x)
├── / → Service web-service:80 → Pods web (10.42.2.x)
└── admin.example.com → Service admin-service:80K8s configure CoreDNS pour que les services se trouvent par nom :
Format : <service>.<namespace>.svc.cluster.local
Exemples :
- postgres.production.svc.cluster.local
- redis.production.svc.cluster.local
- mon-api.default.svc.cluster.local
Depuis le même namespace, le nom court suffit :
- postgres
- redis# Tester la résolution DNS depuis un pod
kubectl run debug --image=busybox --restart=Never -it --rm -- \
nslookup postgres.production.svc.cluster.localK3s est livré avec Traefik. On installe NGINX à la place (plus documenté, plus de fonctionnalités) :
# Via Helm
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install ingress-nginx ingress-nginx/ingress-nginx \
--namespace ingress-nginx \
--create-namespace \
--set controller.service.type=LoadBalancerSur K3s avec un VPS, K3s provisionne automatiquement un LoadBalancer via son composant Klipper. Vérifier :
kubectl get service -n ingress-nginx
# NAME TYPE CLUSTER-IP EXTERNAL-IP
# ingress-nginx-controller LoadBalancer 10.43.x.x <IP-VPS>apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: mon-app-ingress
namespace: production
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/proxy-body-size: "10m"
spec:
ingressClassName: nginx
rules:
- host: mon-app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: mon-app
port:
number: 80
- host: api.example.com
http:
paths:
- path: /v1
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80kubectl apply -f ingress.yaml
kubectl get ingress -n production
# NAME CLASS HOSTS ADDRESS
# mon-app-ingress nginx mon-app.example.com,... <IP-VPS>Pointer les enregistrements DNS de vos domaines vers <IP-VPS>.
cert-manager provisionne et renouvelle automatiquement les certificats TLS.
helm repo add jetstack https://charts.jetstack.io
helm repo update
helm install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--set crds.enabled=trueapiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: votre@email.com
privateKeySecretRef:
name: letsencrypt-prod-key
solvers:
- http01:
ingress:
ingressClassName: nginxkubectl apply -f clusterissuer.yaml
kubectl get clusterissuer
# NAME READY
# letsencrypt-prod TrueapiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: mon-app-ingress
namespace: production
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- mon-app.example.com
secretName: mon-app-tls # cert-manager crée ce secret
rules:
- host: mon-app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: mon-app
port:
number: 80cert-manager détecte l'annotation, provisionne le certificat via le challenge HTTP-01, et le renouvelle automatiquement avant expiration. Le certificat apparaît dans le namespace production sous le nom mon-app-tls.
# Suivre la provision du certificat
kubectl describe certificate mon-app-tls -n production
kubectl get certificate -n production
# NAME READY SECRET AGE
# mon-app-tls True mon-app-tls 2mannotations:
# Taille max des requêtes
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
# Timeout (en secondes)
nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
nginx.ingress.kubernetes.io/proxy-send-timeout: "300"
# Rate limiting
nginx.ingress.kubernetes.io/limit-rps: "10"
nginx.ingress.kubernetes.io/limit-connections: "5"
# CORS
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-origin: "https://mon-app.com"
# Basic auth
nginx.ingress.kubernetes.io/auth-type: basic
nginx.ingress.kubernetes.io/auth-secret: basic-auth
nginx.ingress.kubernetes.io/auth-realm: "Zone protégée"
# Réécriture de chemin
nginx.ingress.kubernetes.io/rewrite-target: /$2Par défaut, tous les pods peuvent communiquer entre eux quelle que soit le namespace. NetworkPolicy restreint ça.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: backend-isolation
namespace: production
spec:
podSelector:
matchLabels:
app: postgres
policyTypes:
- Ingress
ingress:
- from:
# Uniquement les pods avec le label app: mon-api dans le même namespace
- podSelector:
matchLabels:
app: mon-api
ports:
- protocol: TCP
port: 5432Cette policy bloque tout accès à PostgreSQL sauf depuis les pods mon-api du namespace production. Les autres pods — même dans le même namespace — ne peuvent pas se connecter à PostgreSQL.
Le networking est opérationnel. Le dernier chapitre couvre le scaling automatique, les rolling updates, RBAC, Helm et le monitoring en production.