Files
factory/doc/runbooks/new-web-app/06-ci-workflows.md
Gabriel Radureau 8330d82225 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>
2026-05-31 17:22:30 +02:00

5.4 KiB
Raw Permalink Blame History

Factory > Doc > Runbooks > Nouvelle application web > 6. Workflows CI

6. Les workflows CI (.gitea/workflows/)

Status: Active Upstream: 1. Dépôt Gitea (secrets d'org), 3. Vault plateforme (gitea_cicd_<app>) Related: 4. Chart Helm · 5. Terraform de l'app · 7. Enregistrement ArgoCD · Conventions de nommage


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).

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.

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).

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 (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).

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). Un Dockerfile multi-stage à la racine convient (cf. webapp/Dockerfile).

Vue d'ensemble

%%{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 (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.