Exposer un service avec un nom de domaine personnalisé
Votre app tourne sur le cluster Kubernetes France Nuage. Vous voulez qu'elle soit accessible via HTTPS, sur un vrai nom de domaine. Ce tutoriel couvre deux cas : le sous-domaine *.apps.france-nuage.fr (fourni par défaut) et votre propre domaine.
Ce qu'il vous faut
- Un namespace sur votre cluster Kubernetes France Nuage
- Un Service Kubernetes qui expose votre app sur le port 80
- (Optionnel) Un nom de domaine dont vous contrôlez le DNS
Comment ça marche
France Nuage utilise Kingress comme contrôleur Ingress et cert-manager pour les certificats TLS. Vous déclarez un Ingress, cert-manager obtient le certificat Let's Encrypt, Kingress route le trafic. Donc pas de tickets à des ops, pas d'intervention manuelle, bienvenu dans le monde moderne !
Étape 1 : vérifier votre Service
Kingress exige que le backend pointe vers le port 80. Si votre app écoute sur un autre port (3000, 8080, etc.), le Service doit faire la traduction :
apiVersion: v1
kind: Service
metadata:
name: mon-app
spec:
selector:
app: mon-app
ports:
- port: 80 # Kingress exige le port 80 ici
targetPort: 3000 # le port réel de votre app
Si le port du Service n'est pas 80, Kingress retourne une erreur 503 sans message explicite. C'est l'erreur la plus fréquente. Votre app peut écouter sur n'importe quel port, mais le Service Kubernetes doit exposer le port 80.
Étape 2 : créer l'Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: mon-app
annotations:
ingress.kubernetes.io/ssl-redirect: "true"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
acme.cert-manager.io/http01-edit-in-place: "true"
spec:
ingressClassName: traefik # une classe autorisée par votre tenant (souvent traefik ou nginx)
tls:
- hosts:
- mon-app.apps.france-nuage.fr
secretName: mon-app-tls
rules:
- host: mon-app.apps.france-nuage.fr
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
service:
name: mon-app
port:
number: 80
Sur un cluster multi-tenant, le webhook d'admission refuse tout Ingress sans ingressClassName autorisé : admission webhook denied: use one matching the regex ^(nginx|traefik)$. Deux champs sont donc obligatoires dans l'exemple ci-dessus.
spec.ingressClassName: une classe autorisée par votre tenant. Sur le cluster France Nuage, ce sonttraefiketnginx. Vous ne pouvez pas les lister vous-même (kubectl get ingressclassrenvoieForbiddendans un namespace scopé) ; en cas de doute, demandez-les à votre administrateur.- L'annotation
acme.cert-manager.io/http01-edit-in-place: "true": sans elle, cert-manager crée un Ingress « solver » temporaire (sans classe) pour le challenge HTTP-01, refusé par le même webhook. Le certificat reste alorsREADY=Falseindéfiniment, sans erreur visible. L'annotation résout le challenge directement sur l'Ingress déjà accepté.
Trois choses se passent alors automatiquement :
- cert-manager lit l'annotation
cert-manager.io/cluster-issuer: "letsencrypt-prod"et demande un certificat à Let's Encrypt - Le certificat est stocké dans le Secret
mon-app-tls, dans votre namespace Kubernetes - Kingress termine le TLS et route le trafic HTTP vers votre Service
Après l'exécution de kubectl apply, attendez 30 à 90 secondes que le certificat soit émis.
Vous pourrez ensuite suivre la progression via la commande :
kubectl get certificate -n mon-namespace
Quand READY passe à True, c'est bon :).
Étape 3 : utiliser votre propre nom de domaine
Vous n'êtes pas limité à *.apps.france-nuage.fr. Pour utiliser app.votre-domaine.com :
1. Configurez votre DNS
Créez un enregistrement CNAME (ou A via un proxy DNS) qui pointe vers :
app.votre-domaine.com → zero-trust.france-nuage.fr
2. Mettez à jour l'Ingress
Remplacez le champs host par votre nom de domaine :
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: mon-app
annotations:
ingress.kubernetes.io/ssl-redirect: "true"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
acme.cert-manager.io/http01-edit-in-place: "true"
spec:
ingressClassName: traefik # une classe autorisée par votre tenant (souvent traefik ou nginx)
tls:
- hosts:
- app.votre-domaine.com
secretName: mon-app-tls
rules:
- host: app.votre-domaine.com
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
service:
name: mon-app
port:
number: 80
cert-manager gère le certificat pour votre domaine de la même façon. Le CNAME vers zero-trust.france-nuage.fr fait arriver le trafic sur l'Ingress du cluster, et Kingress le route grâce au header Host.
Dépannage
Erreur 503 sans message
Votre Service n'expose pas le port 80. Vérifiez avec :
kubectl get svc mon-app -n mon-namespace -o yaml
Le champ ports[0].port doit être 80. Si votre app écoute sur 8080, utilisez targetPort: 8080 avec port: 80.
Le certificat reste "Not Ready"
kubectl describe certificate mon-app-tls -n mon-namespace
kubectl describe certificaterequest -n mon-namespace
kubectl describe order -n mon-namespace
Souvent cela veut dire que le DNS ne pointe pas encore vers le cluster (propagation), ou le host dans l'Ingress ne correspond pas au DNS.
Sur un namespace scopé à un tenant (Capsule), le challenge HTTP-01 peut aussi être rejeté par le webhook d'admission. Cherchez sur l'order ou le challenge un message admission webhook denied: use one matching the regex ^(nginx|traefik)$. Il faut alors l'annotation acme.cert-manager.io/http01-edit-in-place: "true" sur l'Ingress (déjà présente dans les exemples ci-dessus) pour que cert-manager résolve le challenge sur l'Ingress déjà accepté au lieu d'en créer un temporaire sans classe.
"Connection refused" sur le domaine custom
"Connection refused" signifie que CNAME n'est pas encore propagé, vérifiez la propagation via la commande :
dig app.votre-domaine.com CNAME
La réponse de dig doit contenir zero-trust.france-nuage.fr. La propagation DNS prend de quelques secondes à 48h selon les registrars.
Exemple YAML complet
Voici un exemple de déploiement Kubernetes avec Service et Ingress et l'usage d'un domain personnalisé :
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mon-app
spec:
replicas: 2
selector:
matchLabels:
app: mon-app
template:
metadata:
labels:
app: mon-app
spec:
containers:
- name: mon-app
image: registry.gitlab.com/mon-org/mon-app:latest
ports:
- containerPort: 3000
---
apiVersion: v1
kind: Service
metadata:
name: mon-app
spec:
selector:
app: mon-app
ports:
- port: 80
targetPort: 3000
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: mon-app
annotations:
ingress.kubernetes.io/ssl-redirect: "true"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
acme.cert-manager.io/http01-edit-in-place: "true"
spec:
ingressClassName: traefik # une classe autorisée par votre tenant (souvent traefik ou nginx)
tls:
- hosts:
- app.votre-domaine.com
secretName: mon-app-tls
rules:
- host: app.votre-domaine.com
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
service:
name: mon-app
port:
number: 80
Pour aller plus loin
- Déployer sur Kubernetes depuis GitLab CI - automatiser le déploiement avec un pipeline
- cert-manager - documentation officielle