Aller au contenu principal
KubernetesDevOpsFormation

Services : exposer tes applications

30 min de lecture Apprendre Kubernetes — Chapitre 4

Expose tes applications avec les Services, le DNS interne, Ingress et les NetworkPolicies.

📖 Rappel : Dans le chapitre précédent, on a vu les Deployments, les rolling updates et le scaling. Tes Pods tournent, mais personne ne peut les joindre. C’est exactement le problème qu’on résout ici.

Tu as déployé ton application sur Kubernetes. Elle tourne, elle scale. Mais comment un autre service — ou un utilisateur — peut-il y accéder ? Les Pods sont éphémères : à chaque restart, leur IP change. Impossible de compter dessus. C’est là qu’interviennent les Services — le mécanisme de Kubernetes pour fournir une adresse réseau stable à un ensemble de Pods.

Dans ce chapitre, tu vas comprendre les différents types de Services, le DNS interne, l’Ingress pour le routage HTTP, et les NetworkPolicies pour verrouiller le trafic.

Pourquoi c’est important

Sans Services, tes Pods sont des îles isolées. Chaque redémarrage, chaque scaling change les adresses IP. Imagine un frontend qui doit parler à une API : tu ne vas pas hardcoder une IP qui change toutes les 5 minutes.

Les Services résolvent ce problème fondamental :

  • Adresse stable — une IP virtuelle (ClusterIP) qui ne change jamais tant que le Service existe
  • Load balancing intégré — le trafic est réparti entre tous les Pods sélectionnés
  • Découverte automatique — grâce au DNS interne, chaque Service est accessible par son nom

🔥 Cas réel : Une équipe déploie 12 microservices sur Kubernetes. Sans Services, chaque déploiement casserait les connexions inter-services. Avec les Services et le DNS interne, les applications se découvrent par nom (api-svc, auth-svc, payment-svc) — aucune configuration réseau manuelle.

Comprendre les Services Kubernetes

Un Service utilise un selector pour cibler les Pods. Tout Pod dont les labels correspondent reçoit du trafic. Il existe quatre types de Services, chacun avec son cas d’usage.

ClusterIP (par défaut) — accessible uniquement depuis l’intérieur du cluster. C’est le type que tu utiliseras 90% du temps pour la communication inter-services.

NodePort — expose le Service sur un port statique (30000-32767) de chaque nœud. Utile en dev/test, rarement en production.

LoadBalancer — provisionne un load balancer externe via ton cloud provider (AWS ELB, GCP LB, Azure LB). Le choix standard pour exposer un service en production.

ExternalName — un simple alias DNS vers un service externe. Pratique pour intégrer un service managé (RDS, Cloud SQL) dans le mesh Kubernetes.

Pour créer un Service ClusterIP qui expose une webapp sur le port 80 :

apiVersion: v1
kind: Service
metadata:
  name: webapp-svc
spec:
  type: ClusterIP
  selector:
    app: webapp
  ports:
    - port: 80
      targetPort: 8080
      protocol: TCP

💡 Tip DevOps : port est le port du Service (ce que les clients utilisent), targetPort est le port du container. Ils peuvent être différents — et c’est souvent le cas. Ton app écoute sur 8080, mais le Service expose le port 80.

Le DNS interne (CoreDNS) enregistre automatiquement chaque Service. La convention de nommage suit ce pattern :

<service>.<namespace>.svc.cluster.local

Depuis le même namespace, webapp-svc suffit. Depuis un autre namespace, utilise webapp-svc.production. Ne hardcode jamais d’IP dans tes applications — toujours le nom DNS du Service.

🧠 À retenir : Le DNS interne est la colonne vertébrale de la communication entre microservices. Si ton app utilise une IP en dur, c’est un bug.

L’Ingress ajoute une couche au-dessus des Services : le routage HTTP/HTTPS intelligent. Un seul point d’entrée, un seul LoadBalancer, et le trafic est routé vers différents Services selon le hostname ou le path. Il nécessite un Ingress Controller (nginx, Traefik) installé dans le cluster.

Commandes essentielles

Pour créer, inspecter et débugger tes Services, voici les commandes que tu utiliseras quotidiennement.

Déployer un Service et vérifier qu’il fonctionne :

# Créer le Service
kubectl apply -f webapp-svc.yaml

# Lister les Services
kubectl get svc

# Détails complets (endpoints, events)
kubectl describe svc webapp-svc

# Vérifier que les endpoints sont bien associés
kubectl get endpoints webapp-svc

⚠️ Attention : Si kubectl get endpoints montre une liste vide, c’est que le selector du Service ne match aucun Pod. Vérifie tes labels avec kubectl get pods --show-labels.

Pour tester la connectivité réseau et le DNS depuis l’intérieur du cluster :

# Pod éphémère pour tester le DNS et la connectivité
kubectl run debug --rm -it --image=busybox:1.36 -- sh

# Dans le pod :
nslookup webapp-svc
wget -qO- http://webapp-svc

Pour exposer rapidement un Deployment sans écrire de YAML (prototypage) :

# ClusterIP rapide
kubectl expose deployment webapp --port=80 --target-port=8080

# NodePort pour accès externe immédiat
kubectl expose deployment webapp --type=NodePort --port=80 --target-port=8080

💡 Tip DevOps : kubectl expose est parfait pour le prototypage, mais en production, gère toujours tes Services en YAML versionné dans Git. L’infra-as-code, ça ne se négocie pas.

Cas concret entreprise

🔥 Cas réel : Tu bosses sur une plateforme e-commerce avec trois composants — un frontend React, une API Node.js et une base PostgreSQL. Voici comment structurer le réseau avec les Services, l’Ingress et les NetworkPolicies.

L’architecture réseau complète en un seul fichier :

---
apiVersion: v1
kind: Service
metadata:
  name: frontend-svc
  namespace: ecommerce
spec:
  type: ClusterIP
  selector:
    app: frontend
  ports:
    - port: 80
      targetPort: 3000
---
apiVersion: v1
kind: Service
metadata:
  name: api-svc
  namespace: ecommerce
spec:
  type: ClusterIP
  selector:
    app: api
  ports:
    - port: 80
      targetPort: 4000
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ecommerce-ingress
  namespace: ecommerce
spec:
  ingressClassName: nginx
  rules:
    - host: shop.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: frontend-svc
                port:
                  number: 80
          - path: /api
            pathType: Prefix
            backend:
              service:
                name: api-svc
                port:
                  number: 80

Un seul Ingress, un seul LoadBalancer cloud, deux backends. Le frontend est servi sur /, l’API sur /api. Simple, efficace, économique.

Pour sécuriser le tout, on verrouille le trafic avec une NetworkPolicy deny-all, puis on ouvre uniquement ce qui est nécessaire :

---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all
  namespace: ecommerce
spec:
  podSelector: {}
  policyTypes:
    - Ingress
  ingress: []
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend-to-api
  namespace: ecommerce
spec:
  podSelector:
    matchLabels:
      app: api
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: frontend
      ports:
        - protocol: TCP
          port: 4000

Résultat : le frontend peut appeler l’API, mais un Pod random ne peut contacter ni le frontend ni l’API directement. C’est de la microsegmentation réseau — le principe du moindre privilège appliqué au réseau.

⚠️ Attention : Les NetworkPolicies nécessitent un CNI compatible (Calico, Cilium, Weave). Flannel seul ne les supporte pas — tes règles seront ignorées silencieusement.

Pièges fréquents

1. Selector qui ne match rien — Le piège n°1. Ton Service existe, mais kubectl get endpoints est vide. Le label dans le selector ne correspond à aucun Pod. Vérifie toujours avec kubectl get pods --show-labels.

2. Confondre port et targetPortport = ce que les clients utilisent pour joindre le Service. targetPort = le port sur lequel ton container écoute. Si ton app écoute sur 3000 et que tu mets targetPort: 80, rien ne marchera.

3. NodePort en production — NodePort expose un port sur TOUS les nœuds et bypass le load balancing intelligent. En prod, utilise un LoadBalancer ou un Ingress.

4. Oublier l’Ingress Controller — Créer un objet Ingress sans avoir installé d’Ingress Controller = rien ne se passe. Pas d’erreur, juste du silence. Vérifie avec kubectl get pods -n ingress-nginx.

5. NetworkPolicy ignorée — Tu appliques une deny-all mais le trafic passe toujours ? Ton CNI ne supporte probablement pas les NetworkPolicies. kubectl get networkpolicy ne valide pas que le CNI les applique réellement.

🧠 À retenir : Quand un Service ne fonctionne pas, debug dans cet ordre — labels → endpoints → ports → DNS → NetworkPolicy. 90% des problèmes sont dans les deux premiers.

Exercice pratique

Mets en place cette architecture de zéro :

  1. Crée un namespace tp-services
  2. Déploie deux applications : frontend (nginx, 3 replicas) et api (httpbin, 2 replicas)
  3. Crée un Service ClusterIP pour chacune
  4. Vérifie la résolution DNS depuis un Pod éphémère : kubectl run test --rm -it --image=busybox -- nslookup api-svc.tp-services
  5. Crée un Ingress qui route / vers le frontend et /api vers l’API
  6. Applique une NetworkPolicy deny-all, puis autorise uniquement frontend → api sur le port 80
  7. Teste qu’un Pod non-autorisé ne peut plus contacter l’API

💡 Tip DevOps : Écris tout dans un seul fichier YAML multi-documents (séparés par ---). C’est plus facile à versionner et à déployer d’un coup avec kubectl apply -f.

À retenir

  • Service ClusterIP → adresse interne stable pour la communication inter-services (90% des cas)
  • Service NodePort → accès externe rapide pour dev/test, jamais en production
  • Service LoadBalancer → exposition production via le cloud provider
  • Ingress → routage HTTP/HTTPS intelligent, un seul point d’entrée pour N services
  • DNS interne<service>.<namespace>.svc.cluster.local — toujours utiliser les noms, jamais les IP
  • NetworkPolicy → deny-all par défaut, puis whitelister explicitement chaque flux autorisé
  • Debug → labels → endpoints → ports → DNS → NetworkPolicy

➡️ La suite

Dans le prochain chapitre, on attaque les Volumes et le stockage persistant — PersistentVolumes, PersistentVolumeClaims et StorageClasses. Parce que des Pods sans données persistantes, c’est comme un serveur sans disque dur.

🖥️ Pratique sur ton propre serveur

Pour suivre Apprendre Kubernetes en conditions réelles, tu as besoin d'un VPS. DigitalOcean offre 200$ de crédit gratuit pour démarrer.

Obtenir 200$

Articles liés