Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
10cc408b03 | ||
|
|
c7744483b4 | ||
|
|
ac05da7001 | ||
|
|
cfc194a3fb |
@@ -3,6 +3,8 @@
|
|||||||
# espace de travail : `.env`, certificats et volumes y survivent d'un déploiement à l'autre.
|
# espace de travail : `.env`, certificats et volumes y survivent d'un déploiement à l'autre.
|
||||||
# Piège : jamais de déclencheur `pull_request` ici. Sur un dépôt public, une PR de fork
|
# Piège : jamais de déclencheur `pull_request` ici. Sur un dépôt public, une PR de fork
|
||||||
# exécuterait son code sur la machine de production (ADR 0009) - job deploy.
|
# exécuterait son code sur la machine de production (ADR 0009) - job deploy.
|
||||||
|
# Pourquoi : `main` va en prod, `dev` en recette, et toute autre branche lancée à la main
|
||||||
|
# (workflow_dispatch) va dans `dev`, la vitrine d'une branche de travail (ADR 0017).
|
||||||
|
|
||||||
name: Déploiement
|
name: Déploiement
|
||||||
|
|
||||||
@@ -14,8 +16,10 @@ on:
|
|||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|
||||||
|
# Par environnement et non par branche : deux branches lancées dans `dev` écriraient sinon
|
||||||
|
# dans le même dossier en même temps.
|
||||||
concurrency:
|
concurrency:
|
||||||
group: deploy-${{ github.ref_name }}
|
group: deploy-${{ github.ref_name == 'main' && 'prod' || github.ref_name == 'dev' && 'rec' || 'dev' }}
|
||||||
cancel-in-progress: false
|
cancel-in-progress: false
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -23,11 +27,11 @@ jobs:
|
|||||||
runs-on: [self-hosted, linux, eni-g3]
|
runs-on: [self-hosted, linux, eni-g3]
|
||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
environment:
|
environment:
|
||||||
name: ${{ github.ref_name == 'main' && 'prod' || 'rec' }}
|
name: ${{ github.ref_name == 'main' && 'prod' || github.ref_name == 'dev' && 'rec' || 'dev' }}
|
||||||
url: ${{ github.ref_name == 'main' && 'https://enervision.local' || 'https://rec.enervision.local:8443' }}
|
url: ${{ github.ref_name == 'main' && 'https://enervision.local' || github.ref_name == 'dev' && 'https://rec.enervision.local:8443' || 'https://dev.enervision.local:9443' }}
|
||||||
env:
|
env:
|
||||||
ENVIRONNEMENT: ${{ github.ref_name == 'main' && 'prod' || 'rec' }}
|
ENVIRONNEMENT: ${{ github.ref_name == 'main' && 'prod' || github.ref_name == 'dev' && 'rec' || 'dev' }}
|
||||||
PORT_HTTPS: ${{ github.ref_name == 'main' && '443' || '8443' }}
|
PORT_HTTPS: ${{ github.ref_name == 'main' && '443' || github.ref_name == 'dev' && '8443' || '9443' }}
|
||||||
steps:
|
steps:
|
||||||
- name: Aligner le dossier de l'environnement sur la branche poussée
|
- name: Aligner le dossier de l'environnement sur la branche poussée
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ EN_TETES: Final[dict[str, str]] = {
|
|||||||
"X-Content-Type-Options": "nosniff",
|
"X-Content-Type-Options": "nosniff",
|
||||||
"X-Frame-Options": "DENY",
|
"X-Frame-Options": "DENY",
|
||||||
"Referrer-Policy": "no-referrer",
|
"Referrer-Policy": "no-referrer",
|
||||||
|
# same-origin : aucun client ne charge l'API en no-cors depuis une autre origine
|
||||||
|
# (proxy.conf.json en dev, reverse proxy nginx ensuite, cf. docs/architecture/20-backend.md).
|
||||||
|
"Cross-Origin-Resource-Policy": "same-origin",
|
||||||
}
|
}
|
||||||
|
|
||||||
PREFIXE_AUTHENTIFICATION: Final = "/auth"
|
PREFIXE_AUTHENTIFICATION: Final = "/auth"
|
||||||
|
|||||||
@@ -23,8 +23,9 @@ async def interroge(
|
|||||||
("x-content-type-options", "nosniff"),
|
("x-content-type-options", "nosniff"),
|
||||||
("x-frame-options", "DENY"),
|
("x-frame-options", "DENY"),
|
||||||
("referrer-policy", "no-referrer"),
|
("referrer-policy", "no-referrer"),
|
||||||
|
("cross-origin-resource-policy", "same-origin"),
|
||||||
],
|
],
|
||||||
ids=["nosniff", "anti_iframe", "referrer"],
|
ids=["nosniff", "anti_iframe", "referrer", "corp"],
|
||||||
)
|
)
|
||||||
async def test_every_response_carries_the_security_headers(
|
async def test_every_response_carries_the_security_headers(
|
||||||
client: AsyncClient, entete: str, valeur: str
|
client: AsyncClient, entete: str, valeur: str
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
# 0017 - Un troisième environnement, `dev`, déployé à la demande depuis n'importe quelle branche
|
||||||
|
|
||||||
|
- Statut : accepté
|
||||||
|
- Date : 2026-09-23
|
||||||
|
|
||||||
|
## Contexte
|
||||||
|
|
||||||
|
L'[ADR 0009](0009-deux-environnements-compose-sur-la-vm-eni.md) a posé deux environnements sur
|
||||||
|
la VM ENI : la recette suit `dev`, la production suit `main`. Les environnements GitHub en
|
||||||
|
comptent trois, `dev`, `rec` et `prod`, et le troisième ne déployait rien.
|
||||||
|
|
||||||
|
Il manque un endroit où montrer une branche de travail avant son merge : la recette ne doit
|
||||||
|
porter que ce qui est intégré à `dev`, sinon elle cesse d'être une recette. Un
|
||||||
|
`workflow_dispatch` sur une branche de travail envoyait d'ailleurs cette branche dans la
|
||||||
|
recette, puisque tout ce qui n'était pas `main` y partait.
|
||||||
|
|
||||||
|
La VM est passée à 32 Go : une troisième TimescaleDB, réglée à 2 Go comme les deux autres,
|
||||||
|
tient sans peine.
|
||||||
|
|
||||||
|
## Décision
|
||||||
|
|
||||||
|
**Un troisième projet Compose, `enervision-dev`, dans `/srv/enervision/dev`**, bâti exactement
|
||||||
|
comme les deux autres : son clone, son `.env`, son certificat, préparés par
|
||||||
|
`scripts/provision-host.sh`.
|
||||||
|
|
||||||
|
**Déployé à la demande, jamais sur un push.** `deploy.yml` envoie `main` en prod, `dev` en
|
||||||
|
recette, et toute autre branche lancée depuis l'onglet Actions dans `dev`. Seul un membre ayant
|
||||||
|
le droit d'écriture sur le dépôt peut lancer un workflow.
|
||||||
|
|
||||||
|
**Ports décalés d'un cran de plus** : HTTPS `9443`, et sur `127.0.0.1` la redirection HTTP
|
||||||
|
`8083`, PostgreSQL `5435`, Mailpit `8027`, Airflow `8084`. Nom d'hôte `dev.enervision.local`,
|
||||||
|
pour la même raison de cookie que la recette.
|
||||||
|
|
||||||
|
**Le groupe de concurrence suit l'environnement**, et non plus la branche : deux branches lancées
|
||||||
|
coup sur coup écriraient sinon dans le même dossier en même temps.
|
||||||
|
|
||||||
|
## Alternatives écartées
|
||||||
|
|
||||||
|
- **`dev` suit la branche `dev` à chaque push, la recette devient manuelle** : la recette
|
||||||
|
offrirait une version figée au jury, mais la doc CI/CD, l'ADR 0009 et l'habitude de l'équipe
|
||||||
|
basculeraient à deux jours du rendu.
|
||||||
|
- **Un environnement par branche de travail** : un projet Compose et une TimescaleDB par
|
||||||
|
branche, sans mécanisme de nettoyage. La machine ne le porterait pas longtemps.
|
||||||
|
- **Garder `dev` sur les postes seulement** : rien à montrer d'une branche non mergée sans
|
||||||
|
passer par la recette.
|
||||||
|
|
||||||
|
## Conséquences
|
||||||
|
|
||||||
|
- Une branche de travail créée avant ce changement porte l'ancien `deploy.yml` : lancée à la
|
||||||
|
main, elle part encore dans la recette. Limiter l'environnement GitHub `rec` à la branche
|
||||||
|
`dev` ferme ce chemin, réglage que seul un administrateur du dépôt peut poser.
|
||||||
|
- `dev` ne garde aucune donnée d'une branche à l'autre au-delà de ce que ses migrations
|
||||||
|
acceptent : une branche dont les migrations divergent de `dev` peut laisser la base dans un
|
||||||
|
état que la suivante refuse. Recréer le volume, `docker compose down -v`, est alors le remède.
|
||||||
|
- Trois environnements construisent leurs images séparément : l'écart de l'ADR 0009, un même
|
||||||
|
commit construit deux fois, reste ouvert jusqu'au passage à GHCR.
|
||||||
@@ -227,26 +227,27 @@ Deux conséquences se propagent jusqu'à l'application, et elles ne se devinent
|
|||||||
- `APP_TRUST_PROXY_HEADERS` passe à vrai en même temps, sinon la limitation de débit par IP
|
- `APP_TRUST_PROXY_HEADERS` passe à vrai en même temps, sinon la limitation de débit par IP
|
||||||
compte sur l'IP du proxy et devient globale.
|
compte sur l'IP du proxy et devient globale.
|
||||||
|
|
||||||
### Deux environnements sur la même machine
|
### Trois environnements sur la même machine
|
||||||
|
|
||||||
Statut : `En cours`, la machine n'étant pas encore provisionnée. Décision et motifs dans
|
Statut : `En cours`. Décision et motifs dans
|
||||||
l'[ADR 0009](../adr/0009-deux-environnements-compose-sur-la-vm-eni.md).
|
l'[ADR 0009](../adr/0009-deux-environnements-compose-sur-la-vm-eni.md), étendue à un troisième
|
||||||
La VM `eadl-2025-nantes-g3` portera la recette et la production, chacune dans son clone du dépôt,
|
environnement par l'[ADR 0017](../adr/0017-environnement-dev-a-la-demande.md).
|
||||||
son `.env` et son projet Compose. Le nom de projet préfixe volumes, réseau et conteneurs : rien
|
La VM `eadl-2025-nantes-g3` porte le développement, la recette et la production, chacun dans son
|
||||||
n'est partagé. `scripts/provision-host.sh` prépare les deux dossiers, génère les secrets et les
|
clone du dépôt, son `.env` et son projet Compose. Le nom de projet préfixe volumes, réseau et
|
||||||
certificats, et ne démarre rien.
|
conteneurs : rien n'est partagé. `scripts/provision-host.sh` prépare les trois dossiers, génère
|
||||||
|
les secrets et les certificats, et ne démarre rien.
|
||||||
|
|
||||||
| | Recette | Production |
|
| | Développement | Recette | Production |
|
||||||
|---|---|---|
|
|---|---|---|---|
|
||||||
| Branche, environnement GitHub | `dev`, `rec` | `main`, `prod` |
|
| Branche, environnement GitHub | toute branche lancée à la main, `dev` | `dev`, `rec` | `main`, `prod` |
|
||||||
| Dossier, projet Compose | `/srv/enervision/rec`, `enervision-rec` | `/srv/enervision/prod`, `enervision-prod` |
|
| Dossier, projet Compose | `/srv/enervision/dev`, `enervision-dev` | `/srv/enervision/rec`, `enervision-rec` | `/srv/enervision/prod`, `enervision-prod` |
|
||||||
| URL | `https://rec.enervision.local:8443` | `https://enervision.local` |
|
| URL | `https://dev.enervision.local:9443` | `https://rec.enervision.local:8443` | `https://enervision.local` |
|
||||||
| Proxy HTTP, HTTPS | `127.0.0.1:8081`, `8443` | `80`, `443` |
|
| Proxy HTTP, HTTPS | `127.0.0.1:8083`, `9443` | `127.0.0.1:8081`, `8443` | `80`, `443` |
|
||||||
| PostgreSQL, Mailpit, Airflow, sur `127.0.0.1` | `5434`, `8026`, `8082` | `5433`, `8025`, `8080` |
|
| PostgreSQL, Mailpit, Airflow, sur `127.0.0.1` | `5435`, `8027`, `8084` | `5434`, `8026`, `8082` | `5433`, `8025`, `8080` |
|
||||||
|
|
||||||
Les deux noms d'hôte visent la même IP, à déclarer dans le `/etc/hosts` des postes. Deux noms
|
Les trois noms d'hôte visent la même IP, à déclarer dans le `/etc/hosts` des postes. Deux noms
|
||||||
distincts sont nécessaires : le cookie `__Secure-ev_refresh` est posé par hôte, pas par port.
|
distincts sont nécessaires : le cookie `__Secure-ev_refresh` est posé par hôte, pas par port.
|
||||||
La redirection HTTP de la recette est ramenée sur la boucle locale parce que la configuration
|
La redirection HTTP de la recette et du développement est ramenée sur la boucle locale parce que la configuration
|
||||||
Nginx renvoie vers `https://$host` sans port, c'est-à-dire vers la production.
|
Nginx renvoie vers `https://$host` sans port, c'est-à-dire vers la production.
|
||||||
|
|
||||||
Le déploiement est décrit dans [50-cicd.md](50-cicd.md) : un runner GitHub Actions installé sur
|
Le déploiement est décrit dans [50-cicd.md](50-cicd.md) : un runner GitHub Actions installé sur
|
||||||
@@ -267,7 +268,7 @@ sequenceDiagram
|
|||||||
|
|
||||||
TF->>VM: SSH, get.docker.com puis docker compose version
|
TF->>VM: SSH, get.docker.com puis docker compose version
|
||||||
TF->>VM: copie et exécute scripts/provision-host.sh
|
TF->>VM: copie et exécute scripts/provision-host.sh
|
||||||
VM->>VM: deux clones, deux .env, deux certificats
|
VM->>VM: trois clones, trois .env, trois certificats
|
||||||
TF->>VM: installe actions-runner, config.sh, svc.sh
|
TF->>VM: installe actions-runner, config.sh, svc.sh
|
||||||
VM->>GH: le runner s'enregistre avec le label eni-g3
|
VM->>GH: le runner s'enregistre avec le label eni-g3
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -423,8 +423,13 @@ Le reste, par ordre de surface :
|
|||||||
écriture des journaux. C'est la troisième ligne de défense : la première est de ne rien passer
|
écriture des journaux. C'est la troisième ligne de défense : la première est de ne rien passer
|
||||||
de secret au logger, la deuxième de ne jamais mettre un jeton dans une URL.
|
de secret au logger, la deuxième de ne jamais mettre un jeton dans une URL.
|
||||||
- En-têtes posés par l'application : `X-Content-Type-Options`, `X-Frame-Options`,
|
- En-têtes posés par l'application : `X-Content-Type-Options`, `X-Frame-Options`,
|
||||||
`Referrer-Policy`, plus `Cache-Control: no-store` sur `/auth/*`. HSTS et CSP appartiennent au
|
`Referrer-Policy`, `Cross-Origin-Resource-Policy: same-origin`, plus `Cache-Control: no-store`
|
||||||
terminateur TLS, que l'application ne connaît pas : le reverse proxy les pose
|
sur `/auth/*`. Le CORP est fixé à `same-origin` parce qu'aucun client légitime ne charge l'API
|
||||||
|
en `no-cors` (image, script, média) depuis une autre origine : le frontend l'appelle en relatif
|
||||||
|
(`/api/v1`), sur sa propre origine, via `proxy.conf.json` en dev et le reverse proxy nginx
|
||||||
|
(`infra/proxy/conf.d/enervision.conf`) en recette et en production. Les appels `HttpClient`, en
|
||||||
|
mode `cors`, n'y sont de toute façon pas soumis. HSTS et CSP appartiennent au terminateur TLS, que
|
||||||
|
l'application ne connaît pas : le reverse proxy les pose
|
||||||
([ADR 0007](../adr/0007-terminaison-tls-et-reverse-proxy-nginx.md)).
|
([ADR 0007](../adr/0007-terminaison-tls-et-reverse-proxy-nginx.md)).
|
||||||
- Le conteneur tourne en utilisateur non-root, avec un `HEALTHCHECK` sur `/api/v1/health/live`.
|
- Le conteneur tourne en utilisateur non-root, avec un `HEALTHCHECK` sur `/api/v1/health/live`.
|
||||||
- TLS, limitation de débit au frontal et journal d'accès sont portés par le reverse proxy.
|
- TLS, limitation de débit au frontal et journal d'accès sont portés par le reverse proxy.
|
||||||
|
|||||||
@@ -131,13 +131,14 @@ entrant n'est ouvert.
|
|||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| `push` sur `dev` | `rec` | `/srv/enervision/rec` | aucune : la recette suit `dev` |
|
| `push` sur `dev` | `rec` | `/srv/enervision/rec` | aucune : la recette suit `dev` |
|
||||||
| `push` sur `main` | `prod` | `/srv/enervision/prod` | approbation d'un relecteur dans l'environnement `prod`, branche `main` seule autorisée |
|
| `push` sur `main` | `prod` | `/srv/enervision/prod` | approbation d'un relecteur dans l'environnement `prod`, branche `main` seule autorisée |
|
||||||
|
| `workflow_dispatch` sur toute autre branche | `dev` | `/srv/enervision/dev` | droit d'écriture sur le dépôt, seul à pouvoir lancer un workflow ([ADR 0017](../adr/0017-environnement-dev-a-la-demande.md)) |
|
||||||
|
|
||||||
Le job aligne le clone sur la branche (`fetch`, `checkout`, `reset --hard`), lance
|
Le job aligne le clone sur la branche (`fetch`, `checkout`, `reset --hard`), lance
|
||||||
`make stack-up`, qui reconstruit les images, redémarre les conteneurs puis applique les
|
`make stack-up`, qui reconstruit les images, redémarre les conteneurs puis applique les
|
||||||
migrations Alembic dans le conteneur backend, et attend jusqu'à trois minutes que
|
migrations Alembic dans le conteneur backend, et attend jusqu'à trois minutes que
|
||||||
`/api/v1/health/ready` réponde derrière le proxy. Cette sonde ne vérifie que la connexion à la
|
`/api/v1/health/ready` réponde derrière le proxy. Cette sonde ne vérifie que la connexion à la
|
||||||
base et la présence de TimescaleDB : sans la migration, le déploiement serait vert sur une base
|
base et la présence de TimescaleDB : sans la migration, le déploiement serait vert sur une base
|
||||||
sans schéma, et c'est pourquoi `make stack-up` la porte. Un groupe de concurrence par branche,
|
sans schéma, et c'est pourquoi `make stack-up` la porte. Un groupe de concurrence par environnement,
|
||||||
sans annulation, empêche deux déploiements simultanés du même environnement.
|
sans annulation, empêche deux déploiements simultanés du même environnement.
|
||||||
|
|
||||||
Le job ne fait pas de `actions/checkout` dans son espace de travail, et c'est voulu : le dossier
|
Le job ne fait pas de `actions/checkout` dans son espace de travail, et c'est voulu : le dossier
|
||||||
@@ -157,7 +158,7 @@ passé à `scripts/provision-host.sh` fixe ce propriétaire.
|
|||||||
|
|
||||||
La machine se prépare avec `scripts/provision-host.sh`, qui vérifie Docker et Compose 2.24.4 ou
|
La machine se prépare avec `scripts/provision-host.sh`, qui vérifie Docker et Compose 2.24.4 ou
|
||||||
plus, clone les deux branches, génère les secrets de chaque `.env` et les certificats
|
plus, clone les deux branches, génère les secrets de chaque `.env` et les certificats
|
||||||
auto-signés, et ne démarre rien. Le détail des deux environnements, ports et noms d'hôte, est
|
auto-signés, et ne démarre rien. Le détail des trois environnements, ports et noms d'hôte, est
|
||||||
dans [10-infra.md](10-infra.md).
|
dans [10-infra.md](10-infra.md).
|
||||||
|
|
||||||
## Ce qui bloque un merge
|
## Ce qui bloque un merge
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ lecture seule ; plusieurs lignes resteront à compléter une fois les endpoints
|
|||||||
| Cinq gardes de configuration qui refusent le démarrage plutôt que de dégrader silencieusement | `app/core/config.py` | A05 |
|
| Cinq gardes de configuration qui refusent le démarrage plutôt que de dégrader silencieusement | `app/core/config.py` | A05 |
|
||||||
| Documentation interactive fermée hors développement, `/metrics` derrière un jeton, sonde qui ne publie plus de version | `app/main.py`, `app/api/security.py` | A05 |
|
| Documentation interactive fermée hors développement, `/metrics` derrière un jeton, sonde qui ne publie plus de version | `app/main.py`, `app/api/security.py` | A05 |
|
||||||
| Scan dynamique OWASP ZAP de l'API authentifiée (compte `lecteur` jetable), non bloquant, configuration par défaut du backend uniquement (ni TLS ni en-têtes du reverse proxy) | `.github/workflows/dast.yml`, `scripts/dast-token.sh` | A05, API8 Security Misconfiguration |
|
| Scan dynamique OWASP ZAP de l'API authentifiée (compte `lecteur` jetable), non bloquant, configuration par défaut du backend uniquement (ni TLS ni en-têtes du reverse proxy) | `.github/workflows/dast.yml`, `scripts/dast-token.sh` | A05, API8 Security Misconfiguration |
|
||||||
| En-têtes `nosniff`, `DENY`, `no-referrer`, et `no-store` sur les routes d'authentification | `app/api/middleware.py` | A05 |
|
| En-têtes `nosniff`, `DENY`, `no-referrer`, `Cross-Origin-Resource-Policy: same-origin`, et `no-store` sur les routes d'authentification | `app/api/middleware.py` | A05 |
|
||||||
| Refus de rétrograder ou désactiver le dernier administrateur actif | `app/services/user.py` | A04 Insecure Design |
|
| Refus de rétrograder ou désactiver le dernier administrateur actif | `app/services/user.py` | A04 Insecure Design |
|
||||||
| Amorçage du premier administrateur hors dépôt, mot de passe jamais dans `argv` ni dans Git | `app/cli.py` | A02, A05 |
|
| Amorçage du premier administrateur hors dépôt, mot de passe jamais dans `argv` ni dans Git | `app/cli.py` | A02, A05 |
|
||||||
| Réponse de l'API Mock bornée avant écriture : timeout, plafond de sites et de mesures, bornes physiques par grandeur, recopie des seuls champs attendus | `app/etl/mock_api_import.py` | API10 Unsafe Consumption of APIs |
|
| Réponse de l'API Mock bornée avant écriture : timeout, plafond de sites et de mesures, bornes physiques par grandeur, recopie des seuls champs attendus | `app/etl/mock_api_import.py` | API10 Unsafe Consumption of APIs |
|
||||||
|
|||||||
+7
-5
@@ -8,8 +8,9 @@ Rien ici ne construit d'image ni ne lance de conteneur.
|
|||||||
- `k3s` : installe un cluster k3s single-node sur une machine distante via SSH
|
- `k3s` : installe un cluster k3s single-node sur une machine distante via SSH
|
||||||
(script officiel `get.k3s.io`) et rapatrie le kubeconfig en local.
|
(script officiel `get.k3s.io`) et rapatrie le kubeconfig en local.
|
||||||
- `terraform/environments/<racine>` : une racine par machine provisionnee.
|
- `terraform/environments/<racine>` : une racine par machine provisionnee.
|
||||||
- `vm-eni` : la VM `eadl-2025-nantes-g3`, qui porte les environnements `rec` et `prod`
|
- `vm-eni` : la VM `eadl-2025-nantes-g3`, qui porte les environnements `dev`, `rec` et `prod`
|
||||||
([ADR 0009](../docs/adr/0009-deux-environnements-compose-sur-la-vm-eni.md)). Installe Docker,
|
([ADR 0009](../docs/adr/0009-deux-environnements-compose-sur-la-vm-eni.md),
|
||||||
|
[ADR 0017](../docs/adr/0017-environnement-dev-a-la-demande.md)). Installe Docker,
|
||||||
execute `scripts/provision-host.sh`, enregistre le runner GitHub Actions.
|
execute `scripts/provision-host.sh`, enregistre le runner GitHub Actions.
|
||||||
- `k3s-cible` : le cluster k3s, cible a terme de `docs/architecture/10-infra.md`. Jamais
|
- `k3s-cible` : le cluster k3s, cible a terme de `docs/architecture/10-infra.md`. Jamais
|
||||||
applique.
|
applique.
|
||||||
@@ -32,9 +33,10 @@ terraform apply
|
|||||||
Parametres du depot, Actions, Runners, New self-hosted runner. Seul un administrateur du depot
|
Parametres du depot, Actions, Runners, New self-hosted runner. Seul un administrateur du depot
|
||||||
peut le creer.
|
peut le creer.
|
||||||
|
|
||||||
Apres l'apply, la machine porte `/srv/enervision/rec` et `/srv/enervision/prod`, chacun avec son
|
Apres l'apply, la machine porte `/srv/enervision/dev`, `/srv/enervision/rec` et
|
||||||
`.env` et son certificat. Le premier demarrage reste manuel, `make stack-up` dans chaque dossier ;
|
`/srv/enervision/prod`, chacun avec son `.env` et son certificat. Le premier demarrage reste
|
||||||
les suivants sont joues par le runner a chaque push sur `dev` et sur `main`.
|
manuel, `make stack-up` dans chaque dossier ; les suivants sont joues par le runner a chaque push
|
||||||
|
sur `dev` et sur `main`, et a chaque lancement manuel d'une autre branche pour `dev`.
|
||||||
|
|
||||||
Retirer le runner se fait a la main, depuis les parametres du depot : `terraform destroy` ne le
|
Retirer le runner se fait a la main, depuis les parametres du depot : `terraform destroy` ne le
|
||||||
desinscrit pas.
|
desinscrit pas.
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
# Contrainte : pas de provisioner `destroy` sur le runner. Il imposerait une connexion ne lisant
|
# Contrainte : pas de provisioner `destroy` sur le runner. Il imposerait une connexion ne lisant
|
||||||
# que `self`, donc le chemin de la cle SSH dans le state, et `svc.sh uninstall` ne desinscrit pas
|
# que `self`, donc le chemin de la cle SSH dans le state, et `svc.sh uninstall` ne desinscrit pas
|
||||||
# le runner cote GitHub : le retrait reste manuel, depuis les parametres du depot.
|
# le runner cote GitHub : le retrait reste manuel, depuis les parametres du depot.
|
||||||
# Ref : ADR 0009 pour les deux environnements, `scripts/provision-host.sh` pour leur contenu.
|
# Ref : ADR 0009 et 0017 pour les trois environnements, `scripts/provision-host.sh` pour leur contenu.
|
||||||
|
|
||||||
locals {
|
locals {
|
||||||
sudo = var.ssh_user == "root" ? "" : "sudo "
|
sudo = var.ssh_user == "root" ? "" : "sudo "
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
variable "ssh_host" {
|
variable "ssh_host" {
|
||||||
type = string
|
type = string
|
||||||
description = "Adresse de la VM ENI qui porte les deux environnements (ADR 0009)."
|
description = "Adresse de la VM ENI qui porte les trois environnements (ADR 0009, ADR 0017)."
|
||||||
}
|
}
|
||||||
|
|
||||||
variable "ssh_port" {
|
variable "ssh_port" {
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Pourquoi : la machine porte deux environnements, chacun un clone du dépôt, un `.env` et un
|
# Pourquoi : la machine porte trois environnements, chacun un clone du dépôt, un `.env` et un
|
||||||
# projet Compose (ADR 0009). Ce script prépare la machine et les deux dossiers sans rien
|
# projet Compose (ADR 0009, ADR 0017). Ce script prépare la machine et les trois dossiers sans
|
||||||
# démarrer : construction des images et démarrage restent à l'opérateur, puis au runner GitHub.
|
# rien démarrer : construction des images et démarrage restent à l'opérateur, puis au runner.
|
||||||
|
# Piège : lancé en root, git refuse un clone déjà chowné au runner (propriété douteuse). D'où
|
||||||
|
# `safe.directory` passé en ligne de commande, seule portée où git l'accepte - preparer().
|
||||||
# Rejouable : un dossier déjà cloné est réaligné sur sa branche, un `.env` existant n'est jamais
|
# Rejouable : un dossier déjà cloné est réaligné sur sa branche, un `.env` existant n'est jamais
|
||||||
# réécrit, un certificat présent n'est jamais régénéré.
|
# réécrit, un certificat présent n'est jamais régénéré.
|
||||||
|
|
||||||
@@ -39,9 +41,10 @@ preparer() {
|
|||||||
local dossier="$RACINE/$env"
|
local dossier="$RACINE/$env"
|
||||||
|
|
||||||
if [[ -d "$dossier/.git" ]]; then
|
if [[ -d "$dossier/.git" ]]; then
|
||||||
git -C "$dossier" fetch --quiet origin "$branche"
|
local git=(git -c "safe.directory=$dossier" -C "$dossier")
|
||||||
git -C "$dossier" checkout --quiet "$branche"
|
"${git[@]}" fetch --quiet origin "$branche"
|
||||||
git -C "$dossier" reset --quiet --hard "origin/$branche"
|
"${git[@]}" checkout --quiet "$branche"
|
||||||
|
"${git[@]}" reset --quiet --hard "origin/$branche"
|
||||||
else
|
else
|
||||||
git clone --quiet --branch "$branche" "$DEPOT" "$dossier"
|
git clone --quiet --branch "$branche" "$DEPOT" "$dossier"
|
||||||
fi
|
fi
|
||||||
@@ -93,6 +96,7 @@ mkdir -p "$RACINE"
|
|||||||
# env branche hôte origine https http pg mailpit airflow
|
# env branche hôte origine https http pg mailpit airflow
|
||||||
preparer prod main enervision.local https://enervision.local 443 80 5433 8025 8080
|
preparer prod main enervision.local https://enervision.local 443 80 5433 8025 8080
|
||||||
preparer rec dev rec.enervision.local https://rec.enervision.local:8443 8443 127.0.0.1:8081 5434 8026 8082
|
preparer rec dev rec.enervision.local https://rec.enervision.local:8443 8443 127.0.0.1:8081 5434 8026 8082
|
||||||
|
preparer dev dev dev.enervision.local https://dev.enervision.local:9443 9443 127.0.0.1:8083 5435 8027 8084
|
||||||
|
|
||||||
if [[ -n "$PROPRIETAIRE" && "$(id -u)" -eq 0 ]]; then
|
if [[ -n "$PROPRIETAIRE" && "$(id -u)" -eq 0 ]]; then
|
||||||
chown -R "$PROPRIETAIRE" "$RACINE"
|
chown -R "$PROPRIETAIRE" "$RACINE"
|
||||||
@@ -104,10 +108,12 @@ Démarrage, dans chaque dossier : make stack-up, qui applique aussi les migratio
|
|||||||
Premier administrateur, stack démarrée, dans chaque dossier :
|
Premier administrateur, stack démarrée, dans chaque dossier :
|
||||||
docker compose -f docker-compose.yml -f docker-compose.prod.yml exec backend \\
|
docker compose -f docker-compose.yml -f docker-compose.prod.yml exec backend \\
|
||||||
python -m app.cli create-admin --email <adresse>
|
python -m app.cli create-admin --email <adresse>
|
||||||
Le runner GitHub Actions (label eni-g3) rejouera le déploiement à chaque push sur dev et main.
|
Le runner GitHub Actions (label eni-g3) rejouera le déploiement à chaque push sur dev et main,
|
||||||
|
et déploiera dans dev toute autre branche lancée à la main depuis l'onglet Actions.
|
||||||
L'installer sous le propriétaire de $RACINE, sinon git refuse ces dépôts et le .env en 600 lui
|
L'installer sous le propriétaire de $RACINE, sinon git refuse ces dépôts et le .env en 600 lui
|
||||||
échappe : relancer au besoin ce script avec PROPRIETAIRE=<utilisateur du runner>.
|
échappe : relancer au besoin ce script avec PROPRIETAIRE=<utilisateur du runner>.
|
||||||
Données historiques : git ne porte pas data/raw, déposer les fichiers dans chaque dossier avant
|
Données historiques : git ne porte pas data/raw, déposer les fichiers dans chaque dossier avant
|
||||||
de déclencher le DAG historical_import.
|
de déclencher le DAG historical_import.
|
||||||
Depuis un poste : ajouter « $ADRESSE enervision.local rec.enervision.local » à /etc/hosts.
|
Depuis un poste : ajouter « $ADRESSE enervision.local rec.enervision.local dev.enervision.local »
|
||||||
|
à /etc/hosts.
|
||||||
FIN
|
FIN
|
||||||
|
|||||||
Reference in New Issue
Block a user