K8s Services & Ingress
Exposition des applications et réseau interne Kubernetes.
Les 4 Types de Services
Vue d'Ensemble
flowchart TB
subgraph Internet
USER[Utilisateur]
end
subgraph Cloud
LB[LoadBalancer<br/>IP Externe]
end
subgraph Cluster K8s
subgraph Node1
NP1[NodePort :30080]
POD1[Pod App]
end
subgraph Node2
NP2[NodePort :30080]
POD2[Pod App]
end
CIP[ClusterIP<br/>10.96.x.x]
ING[Ingress Controller]
end
USER -->|HTTPS| LB
LB --> ING
ING --> CIP
USER -->|NodeIP:30080| NP1
USER -->|NodeIP:30080| NP2
CIP --> POD1
CIP --> POD2
NP1 --> POD1
NP2 --> POD2
Comparatif
| Type | Accessibilité | Port | Cas d'Usage |
|---|---|---|---|
| ClusterIP | Interne uniquement | Service port | Communication inter-pods |
| NodePort | Node IP + Port fixe | 30000-32767 | Dev, on-prem sans LB |
| LoadBalancer | IP externe cloud | Service port | Production cloud |
| ExternalName | Alias DNS | - | Service externe (AWS RDS) |
ClusterIP (Défaut)
Accessible uniquement depuis l'intérieur du cluster.
apiVersion: v1
kind: Service
metadata:
name: backend-api
spec:
type: ClusterIP # Défaut, peut être omis
selector:
app: backend
ports:
- port: 80 # Port du service
targetPort: 8080 # Port du container
# Accessible depuis un autre pod :
curl http://backend-api.default.svc.cluster.local
curl http://backend-api # Même namespace
NodePort
Ouvre un port sur tous les nodes du cluster.
apiVersion: v1
kind: Service
metadata:
name: frontend
spec:
type: NodePort
selector:
app: frontend
ports:
- port: 80
targetPort: 80
nodePort: 30080 # Optionnel (auto-assigné si omis)
NodePort en production
Rarement utilisé en production :
- Ports non standards (30000-32767)
- Nécessite de connaître les IPs des nodes
- Pas de load balancing externe
LoadBalancer
Provisionne un Load Balancer cloud (AWS ELB, GCP LB, Azure LB).
apiVersion: v1
kind: Service
metadata:
name: webapp
annotations:
# AWS-specific
service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
spec:
type: LoadBalancer
selector:
app: webapp
ports:
- port: 443
targetPort: 8443
# Récupérer l'IP externe
kubectl get svc webapp
# NAME TYPE EXTERNAL-IP PORT(S)
# webapp LoadBalancer 52.123.45.67 443:31234/TCP
ExternalName
Crée un alias DNS (CNAME) vers un service externe.
apiVersion: v1
kind: Service
metadata:
name: database
spec:
type: ExternalName
externalName: prod-db.abc123.us-east-1.rds.amazonaws.com
# Depuis un pod, le DNS "database" résout vers le CNAME
nslookup database
# → prod-db.abc123.us-east-1.rds.amazonaws.com
Ingress : La Porte d'Entrée
Concept
Ingress gère le routage HTTP/HTTPS (Layer 7) basé sur :
- Host :
api.example.comvsapp.example.com - Path :
/api/*vs/admin/*

Ingress Controller (Prérequis)
La ressource Ingress ne fait RIEN sans Controller
L'Ingress est juste une configuration. Il faut un Controller pour l'appliquer.
| Controller | Description |
|---|---|
| ingress-nginx | Officiel NGINX, le plus commun |
| Traefik | Cloud-native, dashboard intégré |
| HAProxy | Performance |
| AWS ALB | Natif AWS |
| GKE Ingress | Natif GCP |
# Installer nginx-ingress (Helm)
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm install ingress-nginx ingress-nginx/ingress-nginx
# Vérifier
kubectl get pods -n ingress-nginx
kubectl get svc -n ingress-nginx
Exemple Ingress avec TLS
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: main-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- app.example.com
- api.example.com
secretName: tls-secret # Secret contenant le certificat
rules:
# Rule 1 : app.example.com
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend-svc
port:
number: 80
# Rule 2 : api.example.com
- host: api.example.com
http:
paths:
- path: /v1
pathType: Prefix
backend:
service:
name: api-v1-svc
port:
number: 80
- path: /v2
pathType: Prefix
backend:
service:
name: api-v2-svc
port:
number: 80
Créer le Secret TLS
# À partir de certificats existants
kubectl create secret tls tls-secret \
--cert=fullchain.pem \
--key=privkey.pem
# Avec cert-manager (automatique Let's Encrypt)
# Voir docs cert-manager
Annotations Utiles (nginx-ingress)
annotations:
# Redirection HTTP → HTTPS
nginx.ingress.kubernetes.io/ssl-redirect: "true"
# Réécriture de path
nginx.ingress.kubernetes.io/rewrite-target: /$1
# Timeout
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
# Limite de taille upload
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
# Auth basique
nginx.ingress.kubernetes.io/auth-type: basic
nginx.ingress.kubernetes.io/auth-secret: basic-auth
# Whitelist IP
nginx.ingress.kubernetes.io/whitelist-source-range: "10.0.0.0/8,192.168.0.0/16"
Troubleshooting DNS (CoreDNS)
Format DNS Kubernetes
<service>.<namespace>.svc.cluster.local
# Exemples :
postgres.database.svc.cluster.local
backend-api.default.svc.cluster.local
Le Problème Classique
Debug avec un Pod dnsutils
# Lancer un pod de debug
kubectl run dnsutils --image=tutum/dnsutils --restart=Never -- sleep 3600
# Ou avec busybox
kubectl run debug --image=busybox:1.28 --restart=Never -- sleep 3600
# Entrer dans le pod
kubectl exec -it dnsutils -- /bin/sh
Vérifier la Résolution DNS
# Dans le pod de debug :
# Résolution basique
nslookup postgres
nslookup postgres.database
nslookup postgres.database.svc.cluster.local
# Avec dig (plus détaillé)
dig postgres.database.svc.cluster.local
# Vérifier le serveur DNS utilisé
cat /etc/resolv.conf
# Output typique :
# nameserver 10.96.0.10
# search default.svc.cluster.local svc.cluster.local cluster.local
# options ndots:5
Le Piège ndots:5
Avec ndots:5, si le nom a moins de 5 points, Kubernetes ajoute les suffixes de recherche AVANT de résoudre.
nslookup postgres
# Essaie dans l'ordre :
# 1. postgres.default.svc.cluster.local
# 2. postgres.svc.cluster.local
# 3. postgres.cluster.local
# 4. postgres (domaine absolu)
Forcer la résolution absolue
Ajoutez un point final pour éviter les recherches :
Vérifier CoreDNS
# Pods CoreDNS
kubectl get pods -n kube-system -l k8s-app=kube-dns
# Logs CoreDNS
kubectl logs -n kube-system -l k8s-app=kube-dns
# ConfigMap CoreDNS
kubectl get configmap coredns -n kube-system -o yaml
# Service DNS
kubectl get svc -n kube-system kube-dns
# → 10.96.0.10 (doit matcher /etc/resolv.conf des pods)
Checklist DNS
| Problème | Vérification |
|---|---|
| Service existe ? | kubectl get svc -A |
| Endpoints ? | kubectl get endpoints <svc> |
| Pod DNS fonctionne ? | nslookup kubernetes.default |
| CoreDNS running ? | kubectl get pods -n kube-system -l k8s-app=kube-dns |
| Bon namespace ? | nslookup svc.namespace |
Référence Rapide
# === SERVICES ===
kubectl get svc -A
kubectl describe svc myservice
kubectl get endpoints myservice
# Types :
# ClusterIP → Interne
# NodePort → Node:30000-32767
# LoadBalancer → IP externe cloud
# ExternalName → CNAME externe
# === INGRESS ===
kubectl get ingress -A
kubectl describe ingress myingress
# === DNS DEBUG ===
kubectl run debug --image=busybox:1.28 --restart=Never -- sleep 3600
kubectl exec -it debug -- nslookup myservice.mynamespace
kubectl exec -it debug -- cat /etc/resolv.conf
# CoreDNS
kubectl logs -n kube-system -l k8s-app=kube-dns
# === FORMAT DNS ===
# <service>.<namespace>.svc.cluster.local
# postgres.database.svc.cluster.local