À retenir

  • Le Kubernetes as a Service transforme un cluster de management en control plane universel : les développeurs déclarent l’infrastructure comme des custom resources, les contrôleurs réconcilient le cloud réel.
  • La plateforme est modélisée par des CRD KRM cloud-agnostiquesLandingZone, KubernetesCluster, ServiceExposure — chacune portée par un contrôleur Go custom sur controller-runtime.
  • Crossplane et les opérateurs des hyperscalers (Config Connector, ACK, Azure Service Operator) traduisent ces ressources en vraies API cloud, pendant que la réconciliation continue corrige la dérive automatiquement.
  • Le multi-tenant (tenants isolés), le RBAC agrégé et l’identité fédérée permettent aux équipes de se servir seules sans que l’équipe plateforme perde la gouvernance.
  • Côté exploitation, le control plane passe à l’échelle par sharding des contrôleurs par environnement et une surface API-first (REST, gRPC, SDK et proxy d’API Kubernetes).

Dans un article précédent, nous expliquions pourquoi Terraform ne suffit pas pour le platform engineering et pourquoi Kubernetes s’impose comme moteur d’une plateforme self-service. Cet article-là répondait au pourquoi. Celui-ci répond au comment : l’architecture concrète derrière une plateforme Kubernetes as a Service de production — ce schéma unique qui laisse les équipes produit créer et exploiter des clusters managés de façon autonome, pendant que sécurité, coût et fiabilité restent gouvernés au centre.

Tout ce qui suit provient de la construction de vrais control planes. Les noms et identifiants sont génériques à dessein ; c’est l’architecture qui compte.

Ce que « Kubernetes as a Service » veut vraiment dire

Le Kubernetes as a Service est une plateforme self-service où un cluster de management central est le control plane de toute l’infrastructure. Un développeur déclare un cluster, une base ou un service exposé comme une custom resource Kubernetes ; un contrôleur réconcilie cette déclaration en ressources cloud réelles. Pas de ticket, pas d’apply manuel, gouvernance appliquée en un seul endroit.

Le basculement est subtil mais décisif. Au lieu de voir Kubernetes comme un endroit où exécuter des conteneurs, on le voit comme l’endroit où décrire et réconcilier tout le reste. Le Kubernetes Resource Model (KRM) devient le contrat entre ceux qui consomment l’infrastructure et la plateforme qui la provisionne. C’est la même idée que nous explorions au fil de notre décennie d’histoire avec Kubernetes — poussée à sa conclusion logique.

Le cluster de management : un control plane pour tout piloter

Le cluster de management est un cluster Kubernetes dédié qui n’héberge aucun workload applicatif. Son seul rôle : porter l’API de la plateforme, l’authentification, les contrôleurs custom et les ressources qui décrivent chaque cluster de workload en aval. C’est le point unique où les requêtes arrivent, où les identités sont vérifiées et où la réconciliation se produit.

Centraliser sur un seul control plane paie de quatre façons :

  • Une seule surface d’API — les équipes atteignent la plateforme via kubectl, une CLI, une API ou un portail interne, toutes vers le même endpoint.
  • Un seul moteur de réconciliation — chaque ressource est ramenée en continu vers son état déclaré par des contrôleurs qui tournent au même endroit.
  • Une seule frontière de policy — RBAC, admission policies (par exemple Kyverno) et règles de tenancy vivent ensemble, non dispersées entre clusters.
  • Un seul cycle de vie — mises à jour, déploiement d’add-ons et correction de dérive de nombreux clusters sont orchestrés au centre.

Les clusters de workload — généralement du Kubernetes managé comme GKE — sont des sorties du control plane, réenregistrées dans un gestionnaire multi-cluster une fois prêtes.

Modéliser la plateforme en custom resources

L’API publique de la plateforme est un petit ensemble de Custom Resource Definitions cloud-agnostiques. Chaque CRD est une abstraction délibérée : elle expose l’intention qu’une équipe doit contrôler et masque les dizaines de primitives spécifiques au provider en dessous. Deux ressources forment l’ossature du modèle — LandingZone et KubernetesCluster.

LandingZone : une frontière multi-tenant isolée

Une LandingZone est un blueprint structurel de niveau entreprise. Elle provisionne une frontière de tenant sécurisée, isolée et conforme pour un projet, et sa boucle de contrôleur déclarative réalise nativement la réconciliation multi-cloud complète — en gommant les différences entre providers pour matérialiser et appliquer la policy de l’organisation sur trois préoccupations à la fois :

  • Conteneur de ressources — l’unité d’isolation de plus haut niveau selon le cloud cible : un GCP Project, un AWS Account ou un Azure Resource Group.
  • Topologie réseau — VPC, sous-réseaux isolés, règles de firewall et matrices de routage.
  • Garde-fous d’identité et de sécurité — rôles IAM, attachements de policy et bindings de groupes de principals.

Le spec déclare l’intention, jamais une référence produit propre à un vendeur. Le même manifeste cible n’importe quel provider en changeant un seul champ :

apiVersion: platform.example.com/v1alpha1
kind: LandingZone
metadata:
  name: payments-dev
  namespace: proj-1234-tenant-mgmt
spec:
  provider: gcp                    # gcp | aws | azure
  env: dev
  resourceContainer:
    displayName: payments-dev      # → GCP Project / AWS Account / Azure Resource Group
  networking:
    cidrBlock: 10.24.0.0/16
    subnets:
      - name: nodes
        cidr: 10.24.0.0/20
      - name: pods
        cidr: 10.24.16.0/20
    firewall:
      denyAllIngress: true
  identity:
    guardrails:
      - policy: enforce-cmek
      - policy: restrict-public-ip
    roleBindings:
      - principalGroup: payments-platform-admins
        role: platform-admin

Le contrôleur réconcilie cette intention vers les bons objets du provider — un Project plus un VPC sur GCP, un Account plus un VPC sur AWS, un Resource Group plus un VNet sur Azure — et applique en continu les garde-fous à mesure que la policy dérive.

KubernetesCluster : les clusters managés comme intention déclarative

Un KubernetesCluster est l’abstraction phare — un cluster managé entier réduit à la poignée de décisions qui comptent, tout le reste étant fixé sur une baseline sécurisée. Point crucial : le spec est agnostique du runtime ; il décrit ce que l’équipe veut, pas quel moteur managé le porte.

apiVersion: platform.example.com/v1alpha1
kind: KubernetesCluster
metadata:
  name: cluster-1
  namespace: proj-1234-dev
spec:
  landingZoneRef:
    name: payments-dev           # inherits provider, network, identity
  exposure: internal             # immutable: security boundary
  location: europe-west1         # immutable: physical placement
  version:
    channel: REGULAR
  gatewayApi:
    channel: standard

Le moteur du control plane interprète cette intention de haut niveau et orchestre dynamiquement la primitive managée de bas niveau en coulisses : GKE quand la LandingZone référencée cible Google, EKS sur AWS, AKS sur Azure. L’équipe n’écrit jamais un manifeste de cluster façonné par un provider — elle déclare un KubernetesCluster, et le composer choisit le moteur.

Deux règles de conception gardent l’abstraction sûre. Les champs immuables (exposition, location, réseau) sont rejetés à la mise à jour par un admission webhook, car les changer recréerait ou mettrait en danger le cluster en silence. Les valeurs par défaut sécurisées — dataplane réseau durci, nœuds shielded, fenêtres de maintenance saines — sont appliquées automatiquement : un spec minimal produit quand même un cluster durci. L’utilisateur prend cinq décisions ; le contrôleur en prend cinq cents.

La boucle de réconciliation : comment un contrôleur provisionne le cloud

Le moteur derrière chaque CRD est un contrôleur custom exécutant une boucle de réconciliation sur controller-runtime. La boucle observe une ressource, compare l’état désiré (spec) à l’état observé (status), et crée ou met à jour les objets en aval mappés aux vraies API cloud. Puis elle se rejoue — indéfiniment — en corrigeant la dérive.

Au cœur, un reconciler est une seule fonction idempotente :

func (r *KubernetesClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    var cluster platformv1alpha1.KubernetesCluster
    if err := r.Get(ctx, req.NamespacedName, &cluster); err != nil {
        return ctrl.Result{}, client.IgnoreNotFound(err)
    }

    // 1. Render downstream provider objects (Config Connector / ACK / ASO / Crossplane).
    // 2. Wait for readiness; mirror observed state into .status.
    // 3. On ready: mint a kubeconfig secret, register the cluster with the
    //    multi-cluster add-on manager, and trigger add-on delivery.

    if !clusterReady(&cluster) {
        return ctrl.Result{RequeueAfter: 30 * time.Second}, nil
    }
    return ctrl.Result{}, r.Status().Update(ctx, &cluster)
}

Le contrôleur n’appelle jamais un SDK cloud pour construire un cluster directement. Il rend plutôt des ressources d’opérateurs d’infrastructure et laisse ces contrôleurs parler au cloud. C’est ce feuilletage qui rend la plateforme déclarative de bout en bout : la fonction de réconciliation n’est que de la comptabilité Kubernetes, et les vrais appels d’API sont délégués à des providers spécialisés.

L’écosystème des contrôleurs d’infrastructure

Sous une LandingZone ou un KubernetesCluster se trouve une couche de contrôleurs d’infrastructure qui transforment les objets Kubernetes en vrais appels d’API cloud. Il existe deux familles, et une plateforme multi-cloud sérieuse comprend les deux.

Les opérateurs spécifiques au cloud (la couche native des hyperscalers)

Chaque hyperscaler livre son propre opérateur qui mappe ses services un-à-un vers des CRD. Ce sont des représentations fidèles et haute-fidélité de l’API d’un seul provider — idéales quand le composer a besoin d’une primitive native et directe :

  • Google Cloud — Config Connector (KCC) : mappe les services GCP (Projects, sous-réseaux, policies IAM, clusters GKE, BigQuery) vers des CRD, réconciliés par les contrôleurs cnrm.
  • AWS — AWS Controllers for Kubernetes (ACK) : une famille de contrôleurs par service (EKS, VPC, IAM, S3, RDS) qui gèrent les ressources AWS directement depuis Kubernetes.
  • Azure — Azure Service Operator (ASO) : expose les ressources Azure (Resource Groups, VNets, AKS, role assignments) comme des CRD réconciliées contre Azure Resource Manager.

Chacun fait autorité pour son propre cloud, mais chacun ne parle que son propre dialecte. Bâtir directement dessus fragmente vos abstractions le long des lignes de provider.

Les moteurs provider-indépendants : Crossplane

Crossplane est la couche unificatrice. Son écosystème open-source de providers — provider-gcp, provider-aws, provider-azure (et les familles de providers plus récentes générées depuis l’API de chaque cloud) — encapsule les mêmes API cloud sous-jacentes que les opérateurs natifs exposent. Par-dessus, les Compositions et les Composite Resource Definitions (XRD) permettent de replier ces ressources managées fragmentées, propres à chaque cloud, en une seule abstraction uniforme et de haut niveau.

C’est exactement le mécanisme derrière nos modèles LandingZone et KubernetesCluster : une seule claim composite se déploie en un Project + VPC + binding IAM sur GCP, ou un Account + VPC + rôle sur AWS, sans que le consommateur ne voie jamais la couture du provider. Le contrôleur de la plateforme orchestre ces moteurs — opérateurs natifs pour la fidélité directe, Crossplane pour la composition cross-cloud — plutôt que de les remplacer. Cette séparation garde chaque couche testable et permet d’onboarder un nouveau cloud en ajoutant un provider, non en réécrivant la logique de réconciliation.

Multi-tenant et RBAC sans perdre le contrôle

Le multi-tenant est appliqué par la frontière LandingZone décrite plus haut — le conteneur de ressources, la topologie réseau et les garde-fous d’identité qui isolent chaque projet — combinée à un tenant in-cluster (par exemple Capsule) qui borne namespaces, quotas et network policies. Par-dessus cette frontière, le RBAC décide qui peut faire quoi, et l’astuce est qu’il s’étend tout seul à mesure que la plateforme grandit.

Le control plane définit trois rôles de base — platform-admin, platform-editor, platform-viewer — comme des ClusterRoles agrégés. Chaque fois qu’une nouvelle API de service est ajoutée, elle livre son propre rôle étiqueté pour s’agréger aux rôles de base, et Kubernetes fusionne les règles automatiquement :

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: platform-admin
aggregationRule:
  clusterRoleSelectors:
    - matchLabels:
        rbac.platform.example.com/aggregate-to-platform-admin: "true"
rules: []   # filled automatically by the control plane
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: gke-platform-admin
  labels:
    rbac.platform.example.com/aggregate-to-platform-admin: "true"
rules:
  - apiGroups: ["platform.example.com"]
    resources: ["kubernetesclusters"]
    verbs: ["create", "get", "update", "delete", "list"]

Déployez un nouveau service et ses permissions se déversent dans les personas existants — aucun rôle central édité à la main. Les identités elles-mêmes viennent de votre fournisseur OIDC (Okta, Entra ID, Keycloak) et sont fédérées vers le cloud via Workload et Workforce Identity Federation, puis mappées à des bindings au moindre privilège. Un propriétaire de projet administre son propre tenant ; l’équipe plateforme ne devient jamais le goulot d’étranglement.

Les add-ons en self-service

Un cluster nu n’est pas un cluster utile. Chaque cluster de workload a besoin d’agents de sécurité, de moteurs de policy, d’observabilité, d’optimisation des coûts, de gestion des secrets et d’ingress avant qu’une équipe ne puisse livrer. Le faire de façon cohérente sur des dizaines de clusters est une préoccupation plateforme de premier ordre, pas une arrière-pensée.

Le schéma, c’est la livraison multi-cluster pilotée par GitOps. Quand le contrôleur enregistre un nouveau cluster auprès d’un gestionnaire d’add-ons comme Sveltos, celui-ci matche le cluster contre un ensemble de ClusterProfile et déploie les charts Helm et manifestes requis — sécurité des endpoints, application de policy, secrets externes, autoscaling, backup et gateways — dans l’ordre des dépendances.

Le défi subtil, c’est la visibilité. L’état des add-ons vit sur le cluster de management sous forme d’objets de contrôleur que les utilisateurs ordinaires ne peuvent pas lire. Une plateforme de production comble ce trou en exposant le statut des add-ons via l’API : un endpoint en lecture seule lit les résumés sous-jacents à la demande et renvoie un modèle propre — provisioned, provisioning, failed, waiting-for-dependencies — pour qu’une UI affiche la santé en direct et même un graphe de dépendances. La plateforme ne se contente pas d’installer les add-ons ; elle fait de leur état une API self-service supportée.

Exposer la plateforme comme une API, pas seulement du YAML

Les CRD sont un excellent contrat interne, mais tous les consommateurs ne veulent pas écrire du YAML. Comme une CRD est une définition d’API, vous pouvez générer une surface d’API typée par-dessus : dériver du protobuf depuis les ressources, puis exposer des endpoints REST et gRPC et livrer des SDK en Go, Python, JavaScript et Java. Les équipes appellent la plateforme comme n’importe quelle autre API produit.

Pour consommer l’état vivant d’un cluster, un ajout puissant est un proxy d’API Kubernetes transparent hébergé par le control plane. L’utilisateur s’authentifie une fois auprès de la plateforme ; celle-ci miroite l’API server d’un cluster de workload, de sorte que les outils standards fonctionnent en changeant seulement l’URL du serveur :

kubectl --server=https://platform.example.com/tenants/t1/landingzones/lz1/kubernetesclusters/c1/proxy \
  get pods -n t1-lz1-dev

Point critique : ce n’est pas un pass-through ouvert. Un moteur de policy conscient de Kubernetes classe chaque requête (group, version, resource, subresource, verbe, namespace) et décide autoriser ou refuser avant qu’un seul octet ne soit transmis. Il tourne en deny-by-default, avec un deny floor compilé — secrets, émission de tokens, exec, attach, port-forward — qu’aucune erreur de configuration ne peut outrepasser. La compatibilité vient du miroir du chemin d’API ; la sécurité vient du moteur de policy placé devant. Les utilisateurs obtiennent l’ergonomie native de kubectl sans jamais détenir les credentials d’un cluster de workload.

Passer le control plane à l’échelle par sharding des contrôleurs

Un seul contrôleur réconciliant tous les environnements d’un coup lie leur sort : une tempête de réconciliation ou un mauvais déploiement en dev peut dégrader int et ope aussi. À mesure que la plateforme grandit, ce blast radius partagé devient le principal risque d’exploitation.

La solution, c’est le partitionnement horizontal par environnement. Le même binaire de contrôleur est déployé en releases distinctes, chacune épinglée à un environnement via un flag de démarrage, et chacune n’admet que ses propres ressources grâce à un predicate controller-runtime :

func EnvironmentPredicate(assigned string) predicate.Predicate {
    return predicate.NewPredicateFuncs(func(o client.Object) bool {
        return landingZoneEnvOf(o) == assigned
    })
}

Filtrer au niveau du predicate garde les objets hors périmètre entièrement en dehors de la work queue, laissant la logique de réconciliation intacte. Les composants agnostiques de l’environnement — l’API server, le contrôleur de tenant — tournent une seule fois dans une release commune, tandis que chaque environnement obtient ses propres contrôleurs, ses propres limites de ressources et son propre cycle de vie indépendant. Un environnement peut être mis à jour, mis en pause ou rollback sans toucher aux autres. La leader election est bornée par shard pour que les releases ne se disputent jamais le même lease.

Ce que ce schéma vous rapporte

Assemblées, ces pièces tiennent la promesse du platform engineering : autonomie pour les équipes, contrôle pour la plateforme. Les équipes produit demandent un cluster, un service exposé ou une ressource cloud d’un seul appel déclaratif et l’obtiennent en minutes. L’équipe plateforme applique baselines de sécurité, policy de coût et standards de fiabilité au centre, et corrige la dérive automatiquement par réconciliation plutôt que par réunions de revue.

La discipline d’ingénierie qui fait que ça marche mérite d’être répétée : modéliser une surface de CRD petite et opinionnée ; adosser chaque CRD à un reconciler idempotent ; déléguer les appels cloud aux opérateurs des hyperscalers (KCC, ACK, ASO) et à Crossplane ; rendre le RBAC auto-extensible ; livrer les add-ons par GitOps et exposer leur état via l’API ; et sharder les contrôleurs pour que l’échelle ne rime jamais avec panne partagée. Rien d’exotique là-dedans — ce sont les choix ennuyeux et durables qui font tourner un control plane pendant des années.

Conclusion : comment Edixos peut vous accompagner

Chez Edixos, construire des control planes comme celui-ci est notre cœur de métier. Une plateforme cloud est plus qu’un empilement d’outils — elle doit être bâtie pour durer, évoluer et coller aux contraintes réelles de votre organisation. Notre travail va bien au-delà du déploiement de clusters :

  • Nous écrivons des contrôleurs Kubernetes custom qui modélisent vos workflows de provisioning et vos règles métier comme des boucles de réconciliation.
  • Nous intégrons des moteurs de composition comme Crossplane et Kro pour faire de Kubernetes un moteur de provisioning multi-cloud.
  • Nous travaillons avec des providers existants comme Config Connector (KCC) pour exposer nativement les services cloud via des CRD.
  • Nous bâtissons des plateformes API-first complètes — REST, gRPC et SDK multi-langages — avec multi-tenant, identité fédérée et RBAC auto-extensible intégrés.

C’est exactement le type de plateforme que nous décrivions dans pourquoi Kubernetes bat Terraform pour le platform engineering, rendu concret. Si votre ambition est une plateforme Kubernetes self-service robuste qui aligne innovation, agilité et gouvernance, nous avons les briques techniques et l’expérience de terrain pour la concrétiser.

Parlons de votre plateforme Kubernetes as a Service

Vous cherchez à offrir à vos équipes une vraie infrastructure self-service tout en gardant sécurité et coût sous contrôle central ? Discutons de vos enjeux et voyons comment un control plane custom peut vous apporter vitesse, fiabilité et passage à l’échelle.

Réponses directes

Questions fréquentes

Qu'est-ce que le Kubernetes as a Service dans un contexte de platform engineering ?

C'est une plateforme self-service où un cluster de management central joue le rôle de control plane. Les développeurs déclarent un cluster, une base ou un service comme une custom resource Kubernetes, et un contrôleur provisionne et réconcilie l'infrastructure cloud réelle — sans ticket, sans apply Terraform manuel, gouvernance appliquée au centre.

Pourquoi utiliser un cluster de management plutôt que provisionner les clusters directement ?

Un cluster de management offre une seule surface d'API, un seul moteur de réconciliation et une seule frontière de policy pour chaque cluster de workload. Il centralise authentification, RBAC, correction de dérive et livraison d'add-ons : les équipes produit se servent seules pendant que l'équipe plateforme applique sécurité et standards depuis un point unique.

Comment des contrôleurs custom provisionnent-ils des ressources cloud ?

Un contrôleur exécute une boucle de réconciliation bâtie sur controller-runtime. Il observe une custom resource, compare l'état désiré à l'état observé, et crée des objets en aval — ressources Config Connector ou Crossplane — mappés aux vraies API cloud. La boucle se rejoue en continu, corrigeant la dérive jusqu'à ce que la réalité corresponde au spec déclaré.

Quelle différence entre Crossplane et les opérateurs spécifiques au cloud ?

Les opérateurs cloud — Config Connector (Google), ACK (AWS) et Azure Service Operator — mappent les services d'un seul hyperscaler un-à-un vers des CRD. Crossplane est provider-indépendant : ses providers encapsulent ces mêmes API, et ses compositions regroupent plusieurs ressources en une abstraction comme LandingZone ou KubernetesCluster, à travers les clouds.

Comment le multi-tenant est-il appliqué sur un control plane partagé ?

Une custom resource LandingZone provisionne une frontière de tenant isolée — conteneur de ressources, topologie réseau et garde-fous d'identité — par projet. Des ClusterRoles agrégés étendent automatiquement les rôles platform-admin, editor et viewer à mesure que de nouvelles API sont ajoutées, et les identités fédérées de votre fournisseur OIDC sont mappées à des bindings au moindre privilège.

Peut-on consommer la plateforme sans écrire de YAML ?

Oui. Comme les CRD sont des définitions d'API, vous pouvez en générer du protobuf et exposer par-dessus des SDK REST, gRPC et multi-langages. Les équipes appellent l'API de la plateforme depuis une CLI, un portail interne ou des clients Kubernetes standards via un proxy d'API — le YAML devient optionnel, plus obligatoire.