Exposer une application en interne via un load balancer privé
Par défaut, les applications d'un cluster Kubernetes sont exposées vers Internet via l'ingress public géré par la plateforme. Lorsque les outils de monitoring ou d'alerting sont hébergés dans un autre VPC (Virtual Private Cloud) — ou sur site via un peering (appairage) réseau —, il est préférable de les joindre par un endpoint privé, sans exposition publique.
Ce guide décrit la création d'un Service de type LoadBalancer interne : la plateforme provisionne un load balancer (équilibreur de charge) privé qui attribue des adresses IP (Internet Protocol) privées à l'application, joignables depuis le réseau du cluster et les réseaux appairés.
Prérequis
- Avoir un cluster Kubernetes Numspot opérationnel ↗
- Télécharger le fichier kubeconfig ↗
kubectlinstallé et configuré- Un peering actif entre le réseau des outils de monitoring et le réseau du cluster
- Un security group dédié au load balancer ↗
Load balancer public et load balancer interne
Par défaut, un Service de type LoadBalancer provisionne un load balancer public : la plateforme lui attribue des adresses IP publiques et l'expose vers Internet.
L'annotation service.beta.kubernetes.io/osc-load-balancer-internal: "true" crée un load balancer interne : il reçoit des adresses IP privées dans le subnet (sous-réseau) indiqué et n'est joignable que depuis le réseau du cluster et les réseaux appairés. La plateforme s'appuie sur ce même mécanisme pour ses propres composants internes.
Cycle de vie des adresses IP
| Type d'adresse IP | Attribution | Stabilité |
|---|---|---|
| IP privée (interne) | Attribuée automatiquement dans le subnet au moment de la création | Stable pendant toute la vie du load balancer, non épinglable, modifiée si le Service est recréé |
| IP pré-allouée statique | Adresse IP du compte référencée par annotation avant la création | Conserve la même adresse IP même si le load balancer est recréé |
Les règles firewall ne doivent donc pas cibler une adresse IP privée en dur : préférez un filtrage par security group (groupe de sécurité) — une règle entrante autorisant le security group du load balancer — ou par CIDR (Classless Inter Domain Routing) — les plages des réseaux appairés.
Pour un endpoint privé avec une référence stable côté clients, utilisez un nom DNS (Domain Name System) privé : un enregistrement CNAME isole la valeur de l'adresse IP, et une recréation du load balancer ne demande la mise à jour que d'une seule entrée DNS.
Procédure
Les clés d'annotation de ce guide sont définies par le cloud controller manager de la plateforme : utilisez-les telles quelles, en respectant la casse. N'utilisez que les clés documentées sur cette page.
Étape 1 : Vérifier le peering réseau
Vérifiez que le VPC des outils de monitoring est appairé au réseau du cluster et que les route table (table de routage) des deux réseaux autorisent le trafic entre les plages CIDR concernées.
Étape 2 : Préparer le subnet et le security group
- Identifiez le subnet du réseau du cluster dans lequel le load balancer sera créé : c'est dans ce subnet que les adresses IP privées seront attribuées. Récupérez son identifiant depuis la console ou l'API réseau.
- Créez un security group dédié au load balancer et ajoutez une règle entrante autorisant les CIDR des réseaux appairés vers le port d'écoute du Service. Consultez Créer un security group ↗ et Ajouter une règle à un security group ↗.
- Si le trafic est filtré entre le load balancer et les nodes (nœuds) du cluster, ajoutez une règle autorisant le security group du load balancer à joindre le port cible de l'application.
Étape 3 : Déclarer le Service
Créez le namespace si nécessaire, appliquez le manifest décrit dans la section Manifestes d'exemple puis vérifiez le résultat :
kubectl create namespace demo
kubectl apply -f service-interne.yaml
Annotations principales
| Annotation | Valeur d'exemple | Description |
|---|---|---|
service.beta.kubernetes.io/osc-load-balancer-internal | "true" | Crée un load balancer interne : adresses IP privées dans le subnet indiqué |
service.beta.kubernetes.io/osc-load-balancer-subnet-id | "11111111-2222-3333-4444-…" | UUID (Universally Unique Identifier) du subnet de création du load balancer |
service.beta.kubernetes.io/osc-load-balancer-name | "lb-demo-interne" | Nom fixe du load balancer, 32 caractères maximum |
service.beta.kubernetes.io/osc-load-balancer-security-group | "aaaaaaaa-bbbb-cccc-dddd-…" | Security group principal du load balancer |
service.beta.kubernetes.io/osc-load-balancer-extra-security-groups | "11111111-…, 22222222-…" | Security groups additionnels, séparés par des virgules |
service.beta.kubernetes.io/load-balancer-source-ranges | "198.51.100.0/24, 203.0.113.0/24" | CIDR sources autorisés à joindre le load balancer, sans préfixe supplémentaire |
Annotations complémentaires
| Annotation | Valeur d'exemple | Description |
|---|---|---|
service.beta.kubernetes.io/osc-load-balancer-healthcheck-protocol | "HTTP" | Protocole du health check (vérification d'état) : HTTP ou TCP |
service.beta.kubernetes.io/osc-load-balancer-healthcheck-port | "8080" | Port interrogé par le health check |
service.beta.kubernetes.io/osc-load-balancer-healthcheck-path | "/healthz" | Chemin interrogé, pour un health check en HTTP |
service.beta.kubernetes.io/osc-load-balancer-healthcheck-interval | "30" | Intervalle entre deux health checks, en secondes |
service.beta.kubernetes.io/osc-load-balancer-healthcheck-timeout | "5" | Délai d'attente de chaque health check, en secondes |
service.beta.kubernetes.io/osc-load-balancer-healthcheck-healthy-threshold | "2" | Nombre de succès consécutifs avant de déclarer la cible saine |
service.beta.kubernetes.io/osc-load-balancer-healthcheck-unhealthy-threshold | "3" | Nombre d'échecs consécutifs avant de retirer la cible |
service.beta.kubernetes.io/osc-load-balancer-ip-id | "ffffffff-…" | Adresse IP publique pré-allouée du compte, associée au load balancer |
service.beta.kubernetes.io/osc-load-balancer-ip-pool | "mon-pool-prod" | Sélectionne une adresse IP du compte portant le tag (étiquette) OscK8sIPPool:<nom-du-pool> |
service.beta.kubernetes.io/osc-load-balancer-ingress-address | "ip" | Adresse exposée par le Service : ip, hostname ou both |
service.beta.kubernetes.io/osc-load-balancer-ingress-ipmode | "Proxy" | Mode d'adressage des cibles : Proxy ou VIP |
Manifestes d'exemple
Load balancer interne complet
apiVersion: v1
kind: Service
metadata:
name: demo-interne
namespace: demo
annotations:
# Load balancer interne : adresses IP privées dans le subnet indiqué
service.beta.kubernetes.io/osc-load-balancer-internal: "true"
service.beta.kubernetes.io/osc-load-balancer-subnet-id: "11111111-2222-3333-4444-555555555555"
service.beta.kubernetes.io/osc-load-balancer-name: "lb-demo-interne"
service.beta.kubernetes.io/osc-load-balancer-security-group: "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
# CIDR sources autorisés à joindre le load balancer
service.beta.kubernetes.io/load-balancer-source-ranges: "198.51.100.0/24, 203.0.113.0/24"
# Health check ajusté pour l'application
service.beta.kubernetes.io/osc-load-balancer-healthcheck-protocol: "HTTP"
service.beta.kubernetes.io/osc-load-balancer-healthcheck-port: "8080"
service.beta.kubernetes.io/osc-load-balancer-healthcheck-path: "/healthz"
service.beta.kubernetes.io/osc-load-balancer-healthcheck-interval: "30"
service.beta.kubernetes.io/osc-load-balancer-healthcheck-timeout: "5"
service.beta.kubernetes.io/osc-load-balancer-healthcheck-healthy-threshold: "2"
service.beta.kubernetes.io/osc-load-balancer-healthcheck-unhealthy-threshold: "3"
spec:
type: LoadBalancer
selector:
app: demo
ports:
- name: http
port: 8080
targetPort: 8080
protocol: TCP
Variante : IP pré-allouée statique
Cette variante répond au besoin d'une adresse IP fixe pour les règles firewall : l'adresse IP pré-allouée du compte est conservée même si le load balancer est recréé. L'exposition reste toutefois publique : appliquez un filtrage strict par load-balancer-source-ranges et par security group.
apiVersion: v1
kind: Service
metadata:
name: demo-statique
namespace: demo
annotations:
# Nom fixe et adresse IP pré-allouée : la valeur survit à la recréation du load balancer
service.beta.kubernetes.io/osc-load-balancer-name: "lb-demo-statique"
service.beta.kubernetes.io/osc-load-balancer-ip-id: "ffffffff-8888-9999-aaaa-bbbbbbbbbbbb"
spec:
type: LoadBalancer
selector:
app: demo
ports:
- name: https
port: 443
targetPort: 8443
protocol: TCP
L'adresse IP doit être pré-allouée avant la création du Service : consultez Allouer une IP publique ↗. À la place d'une adresse unique, l'annotation osc-load-balancer-ip-pool sélectionne automatiquement une adresse IP du compte portant le tag OscK8sIPPool:<nom-du-pool>.
Vérification
Récupérer l'adresse du load balancer
kubectl get service demo-interne -n demo
Pendant la création du load balancer, la colonne EXTERNAL-IP affiche <pending> puis l'adresse IP privée attribuée :
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
demo-interne LoadBalancer 10.100.0.42 192.0.2.17 8080:30691/TCP 2m
Pour consulter les annotations appliquées et les événements de création :
kubectl describe service demo-interne -n demo
Vérifier les cibles du load balancer
Les endpoints du Service doivent référencer les adresses IP des pods de l'application :
kubectl get endpoints demo-interne -n demo
Tester l'accès depuis un réseau appairé
Depuis une VM (Virtual Machine) du VPC distant, ou depuis le réseau sur site via le peering :
curl http://192.0.2.17:8080/healthz
Une réponse HTTP 200 confirme que l'application est joignable par le load balancer interne. Si le Service est exposé via un nom d'hôte (osc-load-balancer-ingress-address), testez la résolution DNS depuis le réseau appairé.
Limitations et bonnes pratiques
- Créez un Service de type
LoadBalancerdédié à chaque exposition interne : ne modifiez pas le Service géré par la plateforme pour l'ingress public du cluster. - Les adresses IP privées du load balancer interne sont stables pendant toute sa vie, mais ne sont pas épinglables : elles changent si le Service est supprimé puis recréé.
- Ne ciblez pas une adresse IP privée en dur dans vos règles firewall : ciblez des security groups ou des plages CIDR.
- Référencez l'adresse IP par un enregistrement CNAME dans une zone DNS privée plutôt que de la communiquer aux configurations clientes.
- Fixez le nom du load balancer avec l'annotation
osc-load-balancer-namepour garantir la reproductibilité avec vos outils d'automatisation. - Déclarez systématiquement
load-balancer-source-rangespour limiter l'accès aux seuls réseaux autorisés.
L'adresse IP privée d'un load balancer interne change si le Service est supprimé puis recréé. Une règle firewall ciblant cette adresse en dur deviendra silencieusement obsolète : utilisez un filtrage par security group ou par plage CIDR.
Dépannage
Le Service reste en attente
Cause : une annotation est invalide — subnet inexistant, nom de load balancer de plus de 32 caractères, adresse IP non pré-allouée ou déjà associée à une autre ressource.
Solution : consultez les événements avec kubectl describe service demo-interne -n demo, corrigez l'annotation concernée puis recréez le Service.
Connexion impossible depuis le VPC distant
Cause : le peering, le routage ou le filtrage bloque le trafic entre le réseau distant et le load balancer.
Solution : vérifiez dans l'ordre :
- le peering entre les deux réseaux et les route tables associées ;
- la règle entrante du security group du load balancer (port d'écoute et CIDR source) ;
- la valeur de
load-balancer-source-ranges, qui doit inclure le CIDR du réseau source ; - l'état des cibles avec
kubectl get endpoints demo-interne -n demo: des endpoints vides indiquent un health check en échec.
Le health check échoue
Cause : les annotations osc-load-balancer-healthcheck-* ne correspondent pas à l'application — protocole, port ou chemin incorrects.
Solution : alignez les annotations du health check sur l'application, par exemple HTTP, le port 8080 et le chemin /healthz, puis vérifiez que les endpoints se repeuplent.
L'adresse IP a changé
Cause : le Service a été supprimé puis recréé — comportement attendu pour une adresse IP privée, qui n'est pas épinglable.
Solution : utilisez un enregistrement CNAME dans une zone DNS privée et automatisez la mise à jour de l'adresse. Pour une adresse réellement fixe, utilisez la variante IP pré-allouée statique.