Deploy
Le déploiement de KOHAMI repose sur une séparation stricte entre deux couches, chacune avec son outil et son rythme :
| Couche | Outil | Contenu | Rythme |
|---|---|---|---|
| Plateforme | Ansible (infra/ansible) | OS, pare-feu, Docker, piles Compose, cluster k3s, secrets, reverse-proxy TLS | Manuel, à la demande (changement d'infrastructure) |
| Applications | GitHub Actions (deploy-box) | Images API et voice-agent, manifests k3s, migrations, smoke | Automatique, à chaque push develop |
Cette frontière n'est pas cosmétique : la CI ne détient aucun secret d'infrastructure (elle n'a que la clé SSH de déploiement et l'accès registre), et Ansible ne touche jamais aux versions applicatives. On peut rejouer l'un sans craindre d'effet de bord sur l'autre.
Couche plateforme : Ansible
Deux playbooks pilotent le serveur dédié :
playbook.yamlprovisionne l'hôte : durcissement SSH, pare-feu ufw, Docker (avec les données sur la grande partition, images comprises), les trois piles Compose (PostgreSQL par environnement, LiveKit, Inngest), la sauvegarde WAL-G et le reverse-proxy Caddy qui termine le TLS public.playbook-k3s.yamlinstalle le cluster k3s mono-nœud (données hors de la partition racine, Traefik embarqué) puis pose la couche plateforme Kubernetes de chaque environnement basculé : namespace, secrets dérivés du vault, accès registre, et le pont vers la base PostgreSQL restée côté Compose (Service et EndpointSlice pointant une IP fixe).
cd infra/ansible
ansible-playbook playbook.yaml --vault-password-file .vault_pass
ansible-playbook playbook-k3s.yaml --vault-password-file .vault_passLes deux playbooks sont idempotents et convergents : rejoués sans changement, ils terminent à changed=0. C'est vérifié après chaque évolution, et c'est la garantie que le serveur est reconstructible depuis le repo. Deux garde-fous méritent d'être connus :
- Un pre-task refuse d'appliquer sur le serveur réel si le vault n'est pas déchiffré (sinon les valeurs d'exemple du repo remplaceraient les secrets).
- Les manifests kustomize des environnements réels ne génèrent aucun secret : les credentials appartiennent à Ansible, un apply CI ne peut pas les écraser.
Le tout est testable à blanc sur une VM locale (OrbStack) avant de toucher le serveur.
Couche applications : le workflow deploy-box
Chaque push sur develop qui touche apps/api, apps/voice-agent, packages/shared, les Dockerfiles ou les manifests infra/k8s déclenche .github/workflows/deploy-box.yaml :
- Build et push des deux images (API construite depuis le monorepo Bun, voice-agent depuis son projet Python autonome) vers le registre privé Scaleway, avec cache de build.
- Pré-vol sur le serveur : le job vérifie que la couche plateforme Ansible est en place (secrets Kubernetes présents) avant d'appliquer quoi que ce soit. Si elle manque, le déploiement échoue immédiatement avec un message explicite au lieu d'un timeout opaque.
- Apply k3s : synchronisation des manifests,
kubectl apply -kde l'overlay dev, puis redémarrage contrôlé des déploiements (API, voice-agent, LiveKit) et attente des rollouts. - Migrations : la base est migrée via un conteneur éphémère qui rejoint le réseau de l'environnement.
- Nettoyage : les générations d'images remplacées sont purgées (elles rempliraient le disque en quelques déploiements).
- Smoke public :
/v1/healthdoit répondre 200, la garde d'authentification doit refuser un appel anonyme, et le worker vocal doit s'être enregistré auprès de LiveKit. Ce dernier point compte : un rollout peut être vert avec un worker incapable de servir la voix, et ce contrôle transforme ce scénario silencieux en échec de déploiement visible.
Un déploiement de bout en bout (build compris) prend une dizaine de minutes. Les runs sont visibles dans l'onglet Actions du repo.
Déployer la documentation
Ce site est un export statique (Fumadocs / Next.js) publié sur un bucket public Scaleway. Le workflow est volontairement à déclenchement manuel, la doc n'évoluant pas à chaque commit :
gh workflow run "Deploy · docs" --ref developRollback
- Applications : les images sont taguées par SHA de commit en plus de
latest. Revenir en arrière consiste à re-pointer le déploiement k3s sur le tag précédent (ou à re-pousser le commit antérieur surdevelop, qui redéclenche le pipeline). - Plateforme : l'état étant décrit par le repo, un rollback d'infrastructure est un
git revertdu changement Ansible suivi d'un replay du playbook. - Base de données : les migrations sont écrites pour être rejouables ; la restauration complète s'appuie sur WAL-G (sauvegarde continue) une fois la production armée.
Aller plus loin
- Environnements, URLs et comportements par environnement
- Runbooks, procédures d'exploitation