Il y a deux conversations différentes qu'on appelle toutes les deux "multi-cluster", et les confondre coûte cher.
La première, c'est découper un cluster physique en plusieurs plans de contrôle logiques, un par équipe ou par environnement. C'est le terrain de vCluster et des clusters virtuels multi-tenant : un seul parc de nœuds, un seul etcd sous-jacent, des frontières administratives par-dessus. Le problème résolu est organisationnel.
La seconde, c'est relier deux ou trois clusters Kubernetes complets, avec chacun son control plane, son etcd, ses nœuds, posés dans des bâtiments séparés par des centaines de kilomètres. Le problème résolu est physique : la panne d'un site. Ce sont des sujets sans intersection, et la deuxième est nettement plus dure.
Pourquoi on ne fait pas un seul cluster étiré
La tentation, quand on a deux datacenters, c'est de monter un unique cluster avec des nœuds des deux côtés. Un seul kubectl, un seul control plane, des workloads qui basculent tout seuls. Sur le papier, c'est élégant.
En pratique, etcd tranche le débat. Le consensus Raft impose que chaque écriture soit acquittée par la majorité des membres. La documentation etcd recommande de caler le heartbeat-interval sur le temps d'aller-retour entre membres, et l'election-timeout à au moins cinq fois cette valeur. Red Hat chiffre la conséquence pour OpenShift : avec l'intervalle de heartbeat par défaut de 100 ms, le RTT entre nœuds du control plane doit rester sous 33 ms, avec un plafond absolu à 66 ms.
Entre le DC Fullsave de Toulouse et le site TDF de Bordeaux, la latence fibre est confortable pour ce seuil. Le problème n'est pas la latence nominale, c'est ce qui se passe quand le lien inter-site se dégrade ou tombe. Un cluster étiré sur deux sites avec trois membres etcd a forcément deux membres d'un côté et un de l'autre. Le site minoritaire perd le quorum : son API server passe en lecture seule, les kubelets locaux continuent de faire tourner les pods existants mais plus rien ne se réconcilie. Et si c'est le site majoritaire qui brûle, il ne reste plus de quorum du tout. On a doublé le nombre de datacenters pour se retrouver avec un domaine de panne unique et un etcd fragile. Un troisième site arbitre résout le quorum, mais il faut vraiment un troisième site.
Le cluster étiré marche dans un campus, entre deux salles reliées en fibre noire. Entre deux villes, non. La règle qu'on applique : un cluster par datacenter, control plane complet des deux côtés, et on traite la liaison comme du réseau, pas comme du bus interne. Les fondamentaux de haute disponibilité d'un cluster Kubernetes restent valables site par site, chacun devant survivre seul.
Ce que la fédération ajoute réellement
Deux clusters indépendants dans deux DC, ça marche déjà. Le déploiement se fait par GitOps sur les deux, les données se répliquent par la couche applicative, et le trafic entrant bascule au niveau DNS ou BGP. Beaucoup d'infras s'arrêtent là et ont raison.
Ce que la fédération réseau apporte, c'est une chose précise : un pod du cluster de Bordeaux peut résoudre et joindre un Service du cluster de Toulouse comme s'il était local. Pas de LoadBalancer public, pas d'Ingress exposé, pas de tunnel bricolé par application. Une IP de pod parle à une IP de pod, à travers le WAN, avec les mêmes noms DNS que d'habitude.
Cette capacité débloque trois usages, et seulement trois. Le failover applicatif partiel, d'abord : un service de paiement ne tourne qu'à Toulouse, et les frontends des deux sites l'appellent, avec bascule automatique si le site principal chute. La réplication de données ensuite, quand un primaire PostgreSQL doit répliquer vers un secondaire sur un cluster distinct sans exposer le port 5432 sur Internet. Et la répartition de charge géographique enfin, quand on veut que chaque site consomme d'abord son instance locale et ne déborde sur l'autre qu'en cas de saturation.
Si aucun de ces trois cas ne correspond à votre besoin, arrêtez la lecture ici et gardez deux clusters indépendants.
Submariner : tunnels chiffrés et Broker central
Submariner, projet sandbox CNCF poussé par Red Hat, prend le problème par le tunnel. Son architecture repose sur quatre composants : le Gateway Engine, qui monte les tunnels sécurisés vers les autres clusters, le Route Agent, qui achemine le trafic inter-cluster depuis chaque nœud vers le Gateway actif, le Broker, un cluster Kubernetes qui sert de point d'échange de métadonnées, et Lighthouse pour la découverte de services.
Le Gateway Engine tourne sur des nœuds explicitement désignés. On peut en désigner plusieurs pour la tolérance de panne, mais un seul est actif à la fois : c'est de l'actif/passif, pas de la répartition de charge. La couche câble est pluggable, avec IPsec via Libreswan par défaut et WireGuard en alternative.
Côté DNS, Lighthouse implémente l'API Multi-Cluster Services de Kubernetes, spécifiée par le KEP-1645. Deux objets seulement : ServiceExport, créé dans le cluster qui possède le Service et qui l'expose au clusterset, et ServiceImport, créé automatiquement dans les autres clusters. La résolution passe par une zone dédiée, clusterset.local, vers laquelle CoreDNS forwarde. Un service devient joignable en monservice.monnamespace.svc.clusterset.local. C'est un standard Kubernetes, pas une invention propriétaire, et c'est le principal argument de Submariner.
L'autre argument, c'est Globalnet. Si vos deux clusters ont été montés avec le même PodCIDR, ce qui arrive très souvent quand ils sortent du même playbook, Submariner fait de la traduction d'adresses via un CIDR global, 242.0.0.0/8 par défaut, avec 64 000 IP globales allouées par cluster. Toute la traduction se fait sur le nœud Gateway actif. Ça sauve un déploiement mal planifié, au prix d'une couche de NAT de plus à déboguer.
Cilium ClusterMesh : pas de tunnel, du routage
Cilium ClusterMesh part de l'hypothèse inverse. Il ne monte pas de tunnel dédié : il exige que les nœuds des différents clusters aient une connectivité IP directe entre eux via leur InternalIP. Autrement dit, le lien inter-DC doit déjà exister et être routé, typiquement un VPN site à site ou un lien opérateur privé. Cilium ne fait pas le transport, il fait la fédération d'identités et de services par-dessus.
Les prérequis sont stricts et non négociables. Chaque cluster porte un nom unique et un ID unique compris entre 1 et 255. Les PodCIDR ne doivent jamais se chevaucher, contrairement aux ServiceCIDR qui peuvent se recouvrir. Tous les clusters doivent tourner dans le même mode datapath. La limite par défaut est de 255 clusters connectés, extensible à 511 via maxConnectedClusters, au prix d'une réduction du nombre d'identités locales, et cette valeur se fige à l'installation : elle ne se change pas sur un cluster existant.
L'exposition d'un service se fait par une simple annotation, service.cilium.io/global: "true". À partir de là, le service est résolu par son nom habituel et le load balancing eBPF répartit vers les backends de tous les clusters du mesh. La contrepartie, c'est que le comportement par défaut est global : sans réglage explicite d'affinité locale, un pod de Bordeaux peut se retrouver à taper un backend de Toulouse pour un appel qui aurait dû rester local. C'est le piège classique de ClusterMesh, et il se paie en latence sur des chemins d'appel chaînés.
Si vous tournez déjà sur Cilium, l'incrément est faible et la maîtrise d'eBPF pour la sécurité réseau du cluster se prolonge naturellement au multi-cluster : les NetworkPolicies deviennent applicables à travers le mesh. Si votre CNI est un autre, changer de CNI pour faire du multi-cluster est un chantier bien plus lourd que déployer Submariner.
Ce que ça complique, sans enrobage
Le debug devient distribué. Un appel qui échoue traverse le CoreDNS local, la zone clusterset.local, le Route Agent, le Gateway actif, un tunnel IPsec, le WAN, puis le chemin symétrique en face. Six endroits où regarder au lieu d'un, et les outils habituels ne suivent pas la trace au-delà de la frontière du cluster. Sans traçage distribué installé avant la fédération, le premier incident inter-site vous coûtera une nuit.
Les politiques réseau doivent rester cohérentes. Deux clusters, deux jeux de NetworkPolicies, gérés par deux pipelines. La dérive est mécanique. Ça se pilote depuis un dépôt unique avec FluxCD qui réconcilie les deux clusters, jamais à la main, jamais avec deux dépôts.
La latence n'est plus un détail d'implémentation. Un appel local coûte des microsecondes, un appel inter-DC des millisecondes. Une chaîne de cinq microservices qui traverse le WAN à chaque saut fabrique une latence utilisateur intenable. La fédération rend l'appel distant possible, elle ne le rend pas gratuit, et rien dans Kubernetes ne vous empêchera de construire un chemin critique qui zigzague entre deux villes.
Le Gateway est un goulot. Chez Submariner, tout le trafic inter-cluster d'un site passe par le nœud Gateway actif. Sa bande passante, sa CPU pour le chiffrement IPsec et son basculement en cas de panne deviennent des paramètres de capacity planning, pas des détails de déploiement.
La recommandation
Commencez par ne pas fédérer. Montez deux clusters autonomes, un par site, chacun capable de servir seul, et faites basculer le trafic entrant en amont, par DNS à TTL court ou par annonce BGP anycast si vous maîtrisez votre AS. Répliquez les données par la couche applicative, qui sait ce qu'est une transaction, ce que le réseau ignorera toujours. Cette architecture couvre la perte complète d'un site et se débogue avec les compétences que vous avez déjà.
Passez à la fédération le jour où vous identifiez un service qui ne peut exister qu'en un exemplaire et que les deux sites doivent joindre. Pas avant. Et alors : Cilium ClusterMesh si votre CNI est déjà Cilium et que le lien inter-DC est un routage privé stable, Submariner si les CNI diffèrent, si vous partez d'un existant avec des PodCIDR qui se chevauchent, ou si vous voulez rester sur le standard MCS API.
Dans les deux cas, la validation ne se négocie pas : coupez le lien inter-DC en préproduction, pendant que du trafic tourne, et regardez ce qui se passe. Les timeouts observés, les pods qui redémarrent, le temps de reconvergence au retour du lien. Test grandeur nature, ou rien. Une fédération dont le scénario de rupture n'a jamais été joué est une hypothèse déguisée en architecture.
Relier deux clusters, c'est d'abord un chantier réseau : transit, routage inter-site, MTU, chiffrement, supervision du lien lui-même. C'est le travail qu'on fait sur les infrastructures réparties entre le DC Fullsave de Toulouse et le site TDF de Bordeaux, avec une réplication géographique à plus de 200 km et un backbone AS41652 qui porte le lien inter-site. Si vous hésitez entre deux clusters autonomes et un mesh fédéré, on peut cadrer l'architecture multi-site et l'opérer plutôt que de vous laisser arbitrer pendant l'incident.
Sources
- Submariner Architecture : rôle du Gateway Engine, du Route Agent, du Broker et de Lighthouse, mode actif/passif et implémentations IPsec ou WireGuard.
- Globalnet Controller, Submariner : traduction d'adresses pour CIDR qui se chevauchent, CIDR global
242.0.0.0/8et allocation par cluster. - Setting up Cluster Mesh, documentation Cilium : prérequis d'ID unique, PodCIDR non chevauchants, limite de 255 clusters et option
maxConnectedClusters. - KEP-1645 Multi-Cluster Services API : spécification officielle de
ServiceExport,ServiceImportet de la zone DNSclusterset.local. - etcd Tuning : relation entre heartbeat, election timeout et temps d'aller-retour entre membres.
- etcd, documentation OpenShift Container Platform : seuils de RTT recommandés entre nœuds du control plane et conséquences d'un dépassement.


