Document, as a tree-docs tree, the end-to-end procedure to stand up a new web application on the Arcodange platform — a mechanic spread across the factory, tools and app repos with non-trivial ordering dependencies. Covers: Gitea repo creation (org-secret inheritance), Postgres DB + owner role (factory/postgres/iac), platform Vault declaration (gitea_cicd_<app> + policies, tools/hashicorp-vault/iac), the app Helm chart (VSO dynamic secrets via pgbouncer), the app Terraform (app_roles module), the CI workflows (tofu apply + image build, incl. the copy-pasted role pitfall), and ArgoCD registration (factory/argocd/values.yaml). Adds a naming- conventions concept page and an ordered checklist. Wires the legacy doc/adr "setup hello world web app" item and the factory README to the runbook. New docs live under doc/ (singular) per the PR #8 convention. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
105 lines
7.1 KiB
Markdown
105 lines
7.1 KiB
Markdown
[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<br>arcodange-org/‹app›"]:::step
|
||
DB["2 · factory/postgres/iac<br>base ‹app› + rôle ‹app›_role"]:::plat
|
||
VAULT["3 · tools/hashicorp-vault/iac<br>gitea_cicd_‹app› + policies ‹app› / ‹app›-ops"]:::plat
|
||
CONTENT["4·5·6 · chart/ + iac/ + .gitea/<br>push → CI build image & tofu apply"]:::step
|
||
ARGO["7 · factory/argocd/values.yaml<br>→ Application ArgoCD (ns ‹app›)"]:::gitops
|
||
POD["Runtime · Pod(SA ‹app›) → VSO → Vault<br>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_<app>` (étape 3) et le rôle Postgres `<app>_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 `<app>_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 <app> + <app>_role + user_lookup()
|
||
│
|
||
└──> [03] tools/hashicorp-vault/iac → gitea_cicd_<app> (JWT CI) + policies <app> / <app>-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/<app> (rôle DB dynamique) + rôle K8s <app> + secrets KV
|
||
▼
|
||
[07] factory/argocd/values.yaml → ArgoCD crée l'Application → déploie le chart dans le namespace <app>
|
||
▼
|
||
Runtime : Pod(SA <app>) → VSO → VaultAuth(role <app>) → creds/<app>
|
||
→ user PG dynamique héritant de <app>_role → pgbouncer.tools → base <app>
|
||
```
|
||
|
||
## 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 `<app>` 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 `<app>` + rôle `<app>_role` | ✅ |
|
||
| 03 | [Vault plateforme](03-vault-platform.md) | `tools/hashicorp-vault/iac` → `gitea_cicd_<app>` + 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.
|