tadata
← Retour à l'accueil

Comment une petite équipe fait tourner ses propres produits SaaS

#devops#kubernetes#aws#ci-cd#finops#infrastructure

Chez Tadata, nous conseillons nos clients sur leurs plateformes cloud, et nous exploitons aussi nos propres produits : memo, l'application de notes PDF, et les autres applications réunies sur waiyers.com. Cet article décrit une architecture qu'une petite équipe peut réellement opérer, et les leçons qui nous ont coûté du temps ou de l'argent.

La pile en un coup d'œil

CoucheChoixPourquoi
CloudAWS, région de ParisDonnées en France, proches des utilisateurs, services managés matures
CalculUn seul cluster Amazon EKSUn seul plan de contrôle à payer et à mettre à jour
PackagingCharts HelmUn chart par service, des valeurs par environnement
DéploiementArgo CD (GitOps)Le cluster converge vers ce que dit Git
Développement localSkaffold sur un cluster k3s localLes mêmes manifestes en local et dans le cloud
CI/CDGitHub Actionsmain → test, tag de version → prod
ConnexionZitadel (OIDC), avec Google comme fournisseur d'identitéUne seule connexion pour tous les produits, OIDC standard
BackendsPython FastAPI (HTTP) + services gRPCFastAPI pour les API publiques, gRPC entre services
Code partagéPaquets Python et npm dans un registre privé (AWS CodeArtifact)Des bibliothèques versionnées plutôt que du copier-coller
Sites vitrinesSites statiquesPeu coûteux, rapides, rien à patcher
SecretsUn gestionnaire de secrets cloud, synchronisé dans le clusterAucun secret dans Git ni dans les images
Suivi des coûtsOpenCostCoût par namespace et par produit

Un cluster, plusieurs produits

Tout tourne dans un seul cluster EKS, avec un namespace par produit et par environnement. Un plan de contrôle managé est facturé à l'heure par cluster, et chaque cluster apporte ses propres add-ons, mises à jour et supervision. Pour une petite équipe, un deuxième cluster double le travail d'exploitation bien avant d'apporter le moindre bénéfice.

L'isolation repose sur les namespaces, les network policies, les quotas de ressources et des comptes de service distincts aux droits cloud restreints. Voir Patterns Kubernetes pour les briques de base.

tadata
EKS ml-serving (eu-west-3) Control plane { } API server Scheduler Controller manager Cluster store key-value schedules pods onto nodes AWS ALB Ingress fraud-test 8080 1 fraud-staging 8080 2 fraud-prod 8080 3 /test /staging /v1 system node argocd-server argocd-repo-server application-controller cpu node A 1 fraud-test 2 fraud-staging cpu node B ×3 3 fraud-prod n service → the pods it selects namespace argocd namespace fraud-test namespace fraud-staging namespace fraud-prod
EKS ml-serving (eu-west-3) Control plane { } API server Scheduler Controller manager Cluster store key-value schedules pods onto nodes AWS ALB Ingress fraud-test 8080 1 fraud-staging 8080 2 fraud-prod 8080 3 /test /staging /v1 system node argocd-server argocd-repo-server application-controller cpu node A 1 fraud-test 2 fraud-staging cpu node B ×3 3 fraud-prod n service → the pods it selects namespace argocd namespace fraud-test namespace fraud-staging namespace fraud-prod
Le cluster EKS après synchronisation : Argo CD, dans son propre namespace, réconcilie un namespace par environnement ; chaque InferenceService obtient un Deployment de prédiction et un Service derrière l'ingress

Extrait de la fiche « GitOps and Argo CD for Model Serving » · Demander la fiche complète

GitOps avec Helm et Argo CD

Chaque service a son chart Helm ; chaque environnement a son fichier de valeurs. Argo CD surveille le dépôt Git et applique les changements. Personne ne lance kubectl apply sur la test ou la prod.

BénéficeEn pratique
TraçabilitéChaque modification du cluster est un commit
Retour arrièreOn annule le commit ; Argo CD reconverge
Détection des dérivesLes modifications manuelles apparaissent « out of sync »
RepriseUn nouveau cluster se reconstruit à partir de Git

Plus de détails dans Patterns GitOps.

tadata
Engineer Config repo Argo CD EKS API KServe 1. merge PR: newdigest inoverlays/prod 2. webhook (or 3-minpoll) 3. render kustomize,diff with live:OutOfSync 4. applyInferenceService 5. reconcile 6. new pods Ready 7. Synced + Healthy (notification)
Engineer Config repo Argo CD EKS API KServe 1. merge PR: newdigest inoverlays/prod 2. webhook (or 3-minpoll) 3. render kustomize,diff with live:OutOfSync 4. applyInferenceService 5. reconcile 6. new pods Ready 7. Synced + Healthy (notification)
De la PR fusionnée aux pods en service : personne en dehors du cluster n'appelle l'API Kubernetes

Extrait de la fiche « GitOps and Argo CD for Model Serving » · Demander la fiche complète

Le local d'abord : Skaffold sur k3s

Les développeurs font tourner toute la pile sur leur portable avec k3s (un Kubernetes léger) et Skaffold, qui construit les images, déploie les mêmes charts Helm avec des valeurs locales et synchronise les modifications de code dans les pods en cours d'exécution. Les paquets Python partagés sont montés dans les pods pendant le développement : une modification de bibliothèque est visible immédiatement, sans publier de nouvelle version.

L'avantage : « ça marche sur ma machine » signifie « ça marche avec les mêmes manifestes qu'en production ». Le prix : une installation plus lourde qu'un docker compose, que nous acceptons parce que les charts sont testés tous les jours.

CI/CD : deux règles

ÉvénementRésultat
Merge sur mainBuild des images, push, mise à jour des valeurs de test → Argo CD déploie en test
Push d'un tag de version (v1.4.0)Promotion des mêmes images en prod

Les images sont construites une fois puis promues, jamais reconstruites par environnement. Une mise en production est un acte délibéré (un tag), pas un effet de bord d'un merge. Détails dans Bonnes pratiques CI/CD.

Connexion : OIDC partout

Tous les produits utilisent Zitadel comme fournisseur OIDC, avec Google comme fournisseur d'identité en amont. Chaque application est un client OIDC standard ; aucune ne stocke de mot de passe. Ajouter un produit, c'est enregistrer un client, pas développer une page de connexion. Les organisations Zitadel correspondent naturellement aux équipes des applications collaboratives.

tadata
User Client app Authorization server API 1. front channel: /authorize(code_challenge, state,nonce) 2. login (MFA, passkey) + consent to scopes 3.redirect_uri?code=...&state=... 4. back channel: POST /token(code, code_verifier) 5. access_token, id_token,refresh_token 6. Authorization: Bearer access_token
User Client app Authorization server API 1. front channel: /authorize(code_challenge, state,nonce) 2. login (MFA, passkey) + consent to scopes 3.redirect_uri?code=...&state=... 4. back channel: POST /token(code, code_verifier) 5. access_token, id_token,refresh_token 6. Authorization: Bearer access_token
Authorization code + PKCE (RFC 7636), le seul flux navigateur et mobile d'OAuth 2.1. Le client crée un code_verifier aléatoire (43 à 128 caractères) et envoie code_challenge = BASE64URL(SHA256(verifier)) avec code_challenge_method=S256, state et nonce. Le code est à usage unique (10 minutes au plus) et ne part que vers la redirect_uri exacte enregistrée ; le client vérifie state. Sur /token, l'AS recalcule le challenge à partir du verifier : un code volé seul est inutile ; le client s'authentifie par un secret, private_key_jwt ou mTLS

Extrait de la fiche « Identity Protocols: OAuth, OIDC, SAML, FIDO2 » · Demander la fiche complète

Backends et paquets

Les backends sont en Python : FastAPI pour les API HTTP utilisées par les applications web et mobiles, gRPC pour les appels entre services lorsque les contrats typés et le streaming comptent. La logique métier vit dans des paquets versionnés publiés dans un registre privé (AWS CodeArtifact), pour Python et npm. Les services sont minces : ils importent des paquets, câblent la configuration et exposent des endpoints.

PratiquePourquoi
Logique dans les paquets, services mincesLe même code tourne dans une API, un worker ou une CLI
Versions sémantiques, publiées par la CILes services fixent ce qu'ils utilisent ; les montées de version sont explicites
Aucun chemin local inter-dépôts dans les builds de productionDes builds reproductibles sur n'importe quelle machine

Les leçons

1. Garder un seul cluster

Voir plus haut. Ne scinder que lorsqu'une contrainte forte (conformité, locataire bruyant, région) l'impose.

2. Des environnements peu coûteux au repos

Un environnement de test allumé en permanence coûte presque autant que la production. Le nôtre est conçu pour être détruit puis recréé à partir de Terraform et de Git quand personne ne teste. Les vraies économies ne portaient pas que sur les nœuds :

PosteLeçon
Passerelles NATFacturées à l'heure et au Go ; souvent la ligne surprise d'une petite facture
Load balancersUn par ingress, ça s'additionne ; mutualisez un contrôleur d'ingress
Bases managéesArrêtez ou supprimez les instances de test ; restaurez depuis un snapshot au besoin
Adresses IPv4 publiquesFacturées une à une chez AWS

Gardez ce qui est long à recréer et coûte peu (DNS, secrets, registres d'images) ; détruisez ce qui se recrée vite et coûte cher.

3. Les secrets vivent dans un gestionnaire de secrets

Les secrets sont stockés dans un gestionnaire de secrets managé et synchronisés dans le cluster. Ils ne passent jamais par Git, les images ou les logs de CI. Un code d'infrastructure qui écrit des secrets ne doit jamais être appliqué sans ses valeurs d'entrée, sous peine d'écraser les vrais secrets par des valeurs vides : une erreur facile à commettre une fois. Voir Gestion des secrets.

4. Suivre le coût par produit dès le premier jour

OpenCost répartit le coût du cluster par namespace, donc par produit et par environnement. « La facture AWS a augmenté » devient « la test du produit X a doublé ses demandes de mémoire la semaine dernière ». Complétez avec les tags de facturation cloud pour ce qui vit hors du cluster. Notre comparateur de prix cloud aide à vérifier si une ligne reste dans la norme.

5. Construire une plateforme, mais petite

Une petite équipe n'a pas besoin d'une plateforme interne complète. Il lui faut une voie balisée : un modèle de chart, un workflow de CI, une façon de se connecter, une façon de publier un paquet. Voir Platform Engineering.

Ce que nous referions

DécisionVerdict
Un seul clusterOui
GitOps dès le départOui : la reprise et l'audit viennent gratuitement
Kubernetes local plutôt que composeOui, avec une bonne configuration Skaffold
Mises en production par tagOui
Détruire la test au reposOui : la plus grosse économie au regard de l'effort
Un fournisseur OIDC dédié plutôt qu'une authentification maisonOui

Nous utilisons des cookies analytiques pour améliorer votre expérience. Aucune donnée personnelle n'est collectée.