[Factory](../../../README.md) > [Doc](../../README.md) > [Runbooks](../README.md) > **Nouvelle application web** # Mettre en service une nouvelle application web > **Last Updated:** 2026-05-31 > **Status:** ✅ Procédure courante > **Related:** [Conventions de nommage](conventions.md) · [Checklist](08-checklist.md) · [ADR CI/CD](../../adr/03_cicd_gitea_action_argocd.md) · [ADR Vault](../../adr/04_tool_hashicorp_vault.md) ## C'est quoi ? Ce runbook décrit, de zéro, comment faire vivre une nouvelle application web sur la plateforme Arcodange. Le pattern est **GitOps** : l'app habite son propre dépôt Gitea, sa base de données et ses accès Vault sont provisionnés par Terraform/OpenTofu, et **ArgoCD** déploie son chart Helm dans un namespace dédié. Les identifiants Postgres ne sont jamais écrits en clair : ils sont générés à la volée par Vault et injectés dans le pod par le **Vault Secrets Operator (VSO)**. La mécanique est répartie sur **trois dépôts** — le dépôt plateforme [`factory`](https://gitea.arcodange.lab/arcodange-org/factory), le dépôt des services partagés [`tools`](https://gitea.arcodange.lab/arcodange-org/tools), et le **nouveau dépôt de l'app** — avec des **dépendances d'ordre** strictes (voir plus bas). Les exemples de référence sont [`erp`](https://gitea.arcodange.lab/arcodange-org/erp) (image publique + DB) et [`webapp`](https://gitea.arcodange.lab/arcodange-org/webapp) (image maison + DB). **Sert à :** 1. Créer un dépôt Gitea et son squelette (`chart/`, `iac/`, `.gitea/workflows/`). 2. Provisionner la base de données, son rôle propriétaire, et les accès Vault (statiques + dynamiques). 3. Déployer l'app via ArgoCD et l'exposer derrière Traefik (interne `.lab` ou public `.fr` + CrowdSec). ## Carte de bout en bout ```mermaid %%{init: {'theme': 'base'}}%% flowchart TB classDef step fill:#2563eb,stroke:#1e40af,color:#fff classDef plat fill:#059669,stroke:#047857,color:#fff classDef gitops fill:#7c3aed,stroke:#6d28d9,color:#fff classDef run fill:#b45309,stroke:#92400e,color:#fff REPO["1 · Dépôt Gitea
arcodange-org/‹app›"]:::step DB["2 · factory/postgres/iac
base ‹app› + rôle ‹app›_role"]:::plat VAULT["3 · tools/hashicorp-vault/iac
gitea_cicd_‹app› + policies ‹app› / ‹app›-ops"]:::plat CONTENT["4·5·6 · chart/ + iac/ + .gitea/
push → CI build image & tofu apply"]:::step ARGO["7 · factory/argocd/values.yaml
→ Application ArgoCD (ns ‹app›)"]:::gitops POD["Runtime · Pod(SA ‹app›) → VSO → Vault
creds/‹app› → pgbouncer.tools → base ‹app›"]:::run REPO --> DB REPO --> VAULT DB --> CONTENT VAULT --> CONTENT CONTENT --> ARGO ARGO --> POD ``` ## Ordre des opérations (le point le plus important) > [!IMPORTANT] > Les étapes ne sont pas interchangeables. Le rôle JWT de CI `gitea_cicd_` (étape 3) et le rôle Postgres `_role` (étape 2) doivent **exister avant** que la CI Terraform de l'app (étape 6 appliquant l'étape 5) ne s'exécute — sinon l'authentification Vault de la CI échoue, ou le module `app_roles` n'a pas de `_role` à qui rattacher les credentials dynamiques. ``` [01] Dépôt Gitea sous arcodange-org (hérite les secrets CI d'org) │ ├──> [02] factory/postgres/iac → base + _role + user_lookup() │ └──> [03] tools/hashicorp-vault/iac → gitea_cicd_ (JWT CI) + policies / -ops │ (02 et 03 indépendants entre eux, mais TOUS DEUX avant 05) ▼ [04+05+06] Contenu du dépôt : chart/ + iac/ + .gitea/workflows/ (+ Dockerfile) │ push → CI « dockerimage » build l'image · CI « vault » applique iac/ │ → creds/ (rôle DB dynamique) + rôle K8s + secrets KV ▼ [07] factory/argocd/values.yaml → ArgoCD crée l'Application → déploie le chart dans le namespace ▼ Runtime : Pod(SA ) → VSO → VaultAuth(role ) → creds/ → user PG dynamique héritant de _role → pgbouncer.tools → base ``` ## Prérequis plateforme (déjà en place) Ces fondations existent et ne sont **pas** à refaire pour chaque app : | Brique | Où | Rôle | |---|---|---| | Mounts Vault `kvv2`, `postgres`, `transit`, auth `kubernetes` | [`tools/hashicorp-vault/iac/main.tf`](https://gitea.arcodange.lab/arcodange-org/tools/src/branch/main/hashicorp-vault/iac/main.tf) | Moteurs de secrets + auth K8s | | Connexion Vault→Postgres (via `pgbouncer.tools`, user `credentials_editor`) | idem | Permet à Vault d'émettre des users PG dynamiques | | Rôle JWT de bootstrap `gitea_cicd` + app OAuth2 Gitea (`gitea_app_id`) | [`gitea_oidc_auth.yml`](https://gitea.arcodange.lab/arcodange-org/factory/src/branch/main/ansible/arcodange/factory/playbooks/tools/roles/hashicorp_vault/tasks/gitea_oidc_auth.yml) | Échange OIDC Gitea → JWT Vault dans la CI | | Bot `tofu_module_reader` (clé SSH dans `kvv1/gitea/tofu_module_reader`) | [`factory/iac/gitea_tofu_ci_user.tf`](https://gitea.arcodange.lab/arcodange-org/factory/src/branch/main/iac/gitea_tofu_ci_user.tf) | Laisse la CI cloner le module partagé `tools` en SSH | | Secrets Actions d'organisation (`HOMELAB_CA_CERT`, `vault_oauth__sh_b64`, `PACKAGES_TOKEN`) | org Gitea `arcodange-org` | Hérités par tout dépôt de l'org | ## Index des étapes | # | Page | Ce qu'on y fait | Statut | |---|---|---|---| | — | [Conventions de nommage](conventions.md) | Le nom `` réutilisé à l'identique partout (à lire en premier) | ✅ | | 01 | [Dépôt Gitea](01-gitea-repo.md) | Créer le dépôt sous `arcodange-org` + squelette | ✅ | | 02 | [Base de données](02-database.md) | `factory/postgres/iac` → base `` + rôle `_role` | ✅ | | 03 | [Vault plateforme](03-vault-platform.md) | `tools/hashicorp-vault/iac` → `gitea_cicd_` + policies | ✅ | | 04 | [Chart Helm](04-helm-chart.md) | Le chart de l'app (DB via pgbouncer, secrets VSO, ingress) | ✅ | | 05 | [Terraform de l'app](05-app-terraform.md) | `iac/` → module `app_roles` (creds dynamiques + rôle K8s) | ✅ | | 06 | [Workflows CI](06-ci-workflows.md) | `.gitea/workflows/` : `tofu apply` + build image | ✅ | | 07 | [Enregistrement ArgoCD](07-argocd-register.md) | `factory/argocd/values.yaml` → Application + déploiement | ✅ | | 08 | [Checklist](08-checklist.md) | Récapitulatif ordonné + definition of done | ✅ | ## Légende de statut ✅ actif · 🟡 dégradé/beta · 🔴 critique/EOL · ⚠️ problème connu · ❌ désactivé ## Comment éditer ce runbook 1. **Ajouter une page** → la créer depuis le template tree-docs adéquat **et** ajouter sa ligne dans l'index ci-dessus. 2. **Garder les liens croisés bidirectionnels** → toute dépendance citée dans une page (`Upstream`/`Downstream`) doit avoir sa réciproque sur l'autre page. 3. **Mettre à jour `Last Updated:`** ci-dessus après tout changement de structure. 4. Les exemples cités (`erp`, `webapp`) sont vivants : revérifier les snippets contre le code réel avant de s'y fier aveuglément.