docs(runbooks): add "new web app" setup runbook under doc/runbooks/
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>
This commit is contained in:
108
doc/runbooks/new-web-app/06-ci-workflows.md
Normal file
108
doc/runbooks/new-web-app/06-ci-workflows.md
Normal file
@@ -0,0 +1,108 @@
|
||||
[Factory](../../../README.md) > [Doc](../../README.md) > [Runbooks](../README.md) > [Nouvelle application web](README.md) > **6. Workflows CI**
|
||||
|
||||
# 6. Les workflows CI (`.gitea/workflows/`)
|
||||
|
||||
> **Status:** ✅ Active
|
||||
> **Upstream:** [1. Dépôt Gitea](01-gitea-repo.md) (secrets d'org), [3. Vault plateforme](03-vault-platform.md) (`gitea_cicd_<app>`)
|
||||
> **Related:** [4. Chart Helm](04-helm-chart.md) · [5. Terraform de l'app](05-app-terraform.md) · [7. Enregistrement ArgoCD](07-argocd-register.md) · [Conventions de nommage](conventions.md)
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
Deux workflows Gitea Actions vivent dans le dépôt : **`vault.yaml`** applique le Terraform de l'app (`iac/`) en s'authentifiant à Vault via OIDC, et **`dockerimage.yaml`** (optionnel) construit l'image et la pousse au registre Gitea. Le déploiement lui-même n'est pas dans la CI : c'est ArgoCD qui s'en charge ([étape 7](07-argocd-register.md)).
|
||||
|
||||
## `vault.yaml` — appliquer le `iac/` de l'app
|
||||
|
||||
Déclenché sur tout changement de `iac/*.tf`. Deux jobs : obtenir un JWT depuis Gitea, puis `tofu apply`.
|
||||
|
||||
```yaml
|
||||
on:
|
||||
workflow_dispatch: {}
|
||||
push: { paths: ['iac/*.tf'] }
|
||||
pull_request: { paths: ['iac/*.tf'] }
|
||||
|
||||
# job 1 : échange OIDC Gitea → JWT (script base64 fourni en secret d'org)
|
||||
# run: echo -n "${{ secrets.vault_oauth__sh_b64 }}" | base64 -d | bash
|
||||
|
||||
# job 2 : lire les secrets de bootstrap puis appliquer
|
||||
- name: read vault secret
|
||||
uses: https://gitea.arcodange.lab/arcodange-org/vault-action.git@main
|
||||
with:
|
||||
url: https://vault.arcodange.lab
|
||||
caCertificate: ${{ secrets.HOMELAB_CA_CERT }}
|
||||
jwtGiteaOIDC: ${{ needs.gitea_vault_auth.outputs.gitea_vault_jwt }}
|
||||
role: gitea_cicd_<app> # ← le rôle JWT de l'app (étape 3)
|
||||
method: jwt
|
||||
path: gitea_jwt
|
||||
secrets: |
|
||||
kvv1/google/credentials credentials | GOOGLE_BACKEND_CREDENTIALS ;
|
||||
kvv1/gitea/tofu_module_reader ssh_private_key | TERRAFORM_SSH_KEY ;
|
||||
- uses: actions/checkout@v4
|
||||
- name: terraform apply
|
||||
uses: dflook/terraform-apply@v1
|
||||
with: { path: iac, auto_approve: true }
|
||||
```
|
||||
|
||||
Les deux secrets lus servent au backend (clé GCS `GOOGLE_BACKEND_CREDENTIALS`) et au clone du module partagé en SSH (`TERRAFORM_SSH_KEY`, cf. [étape 5](05-app-terraform.md)).
|
||||
|
||||
> [!WARNING]
|
||||
> **Piège du `role:` copié-collé.** Le `role:` du step `vault-action` **et** le `role` de `iac/providers.tf` doivent tous deux être `gitea_cicd_<app>`. L'exemple `erp` porte encore `role: gitea_cicd_webapp` dans son [`vault.yaml`](https://gitea.arcodange.lab/arcodange-org/erp/src/branch/main/.gitea/workflows/vault.yaml) (reliquat de copier-coller) alors que son `providers.tf` utilise bien `gitea_cicd_erp`. Vérifie et aligne sur le nom de **ton** app, sinon la CI lit/écrit avec la mauvaise identité.
|
||||
|
||||
## `dockerimage.yaml` — construire l'image (si image maison)
|
||||
|
||||
À n'ajouter **que** si l'app build sa propre image (pas pour une image publique comme `erp`/Dolibarr). Déclenché au push sur `main`, en ignorant `README.md` et `chart/**` (changer le chart ne reconstruit pas l'image).
|
||||
|
||||
```yaml
|
||||
on:
|
||||
push: { branches: [main], paths-ignore: ['README.md', 'chart/**'] }
|
||||
|
||||
jobs:
|
||||
build-and-push-image:
|
||||
steps:
|
||||
- uses: docker/login-action@v3
|
||||
with:
|
||||
registry: gitea.arcodange.lab
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.PACKAGES_TOKEN }} # secret d'org (étape 1)
|
||||
- uses: actions/checkout@v4
|
||||
- run: |
|
||||
TAGS="latest ${{ github.ref_name }}"
|
||||
docker build -t app .
|
||||
for TAG in $TAGS; do
|
||||
docker tag app gitea.arcodange.lab/${{ github.repository }}:$TAG
|
||||
docker push gitea.arcodange.lab/${{ github.repository }}:$TAG
|
||||
done
|
||||
```
|
||||
|
||||
L'image atterrit donc en `gitea.arcodange.lab/arcodange-org/<app>:latest` — exactement ce que `image.repository` du chart référence ([étape 4](04-helm-chart.md)). Un `Dockerfile` multi-stage à la racine convient (cf. [`webapp/Dockerfile`](https://gitea.arcodange.lab/arcodange-org/webapp/src/branch/main/Dockerfile)).
|
||||
|
||||
## Vue d'ensemble
|
||||
|
||||
```mermaid
|
||||
%%{init: {'theme': 'base'}}%%
|
||||
flowchart TB
|
||||
classDef ci fill:#059669,stroke:#047857,color:#fff
|
||||
classDef out fill:#7c3aed,stroke:#6d28d9,color:#fff
|
||||
PUSH["push sur main"]:::ci
|
||||
PUSH -->|"iac/*.tf modifié"| TF["vault.yaml<br>OIDC → JWT → tofu apply iac/"]:::ci
|
||||
PUSH -->|"code modifié"| IMG["dockerimage.yaml<br>build + push image"]:::ci
|
||||
TF --> VR["creds/‹app› + rôle K8s ‹app› + KV"]:::out
|
||||
IMG --> REG["registre gitea.arcodange.lab/arcodange-org/‹app›"]:::out
|
||||
```
|
||||
|
||||
## Déploiement automatique sur nouvelle image
|
||||
|
||||
Pour qu'ArgoCD redéploie quand une nouvelle image est poussée, on n'ajoute **rien** dans la CI : ce sont les annotations `argocd-image-updater` posées à l'[étape 7](07-argocd-register.md) (stratégie `digest`) qui surveillent le tag `latest`.
|
||||
|
||||
## Notes / contraintes
|
||||
|
||||
- `concurrency: cancel-in-progress` est activé sur les deux workflows : un nouveau push annule le run précédent sur la même ref.
|
||||
- Le `vault-action` est lui-même un dépôt Gitea (`arcodange-org/vault-action`) épinglé `@main`.
|
||||
|
||||
## Related
|
||||
|
||||
- [3. Vault plateforme](03-vault-platform.md) — d'où vient `gitea_cicd_<app>`.
|
||||
- [5. Terraform de l'app](05-app-terraform.md) — ce que `vault.yaml` applique.
|
||||
- [4. Chart Helm](04-helm-chart.md) — `image.repository` = l'image poussée ici.
|
||||
- [7. Enregistrement ArgoCD](07-argocd-register.md) — déploie, et porte les annotations d'auto-update.
|
||||
Reference in New Issue
Block a user