261 lines
10 KiB
Markdown
261 lines
10 KiB
Markdown
# Mise en production
|
|
|
|
Déploiement de Stream Control : l'interface en Docker Compose, les agents en une
|
|
commande, les artefacts construits et publiés par Gitea Actions.
|
|
|
|
```
|
|
┌──────────────────────────┐ ┌───────────────────────────────┐
|
|
│ Gitea │ │ Machine du plan de contrôle │
|
|
│ ├─ registre d'images ───┼───────►│ docker compose up -d │
|
|
│ └─ paquets génériques │ │ → http://control.lan:8080 │
|
|
│ │ agent.cjs │ └───────────────┬───────────────┘
|
|
└─────────┼────────────────┘ │ ws:// (réseau privé)
|
|
│ install-agent.sh/.ps1 ┌──────────┴──────────┐
|
|
└─────────────────────────────►│ VM Ubuntu/Windows │
|
|
│ agent + OBS │
|
|
└─────────────────────┘
|
|
```
|
|
|
|
L'interface est conteneurisée ; **les agents ne le sont pas**. Ils doivent voir
|
|
l'OBS local et la fenêtre du navigateur, ce qu'un conteneur ne permet pas.
|
|
|
|
## Prérequis
|
|
|
|
| Où | Quoi |
|
|
| --- | --- |
|
|
| Gitea | Paquets activés, un runner `ubuntu-latest` avec accès au socket Docker, un runner `windows-latest` |
|
|
| Plan de contrôle | Docker + Docker Compose, sur le réseau privé |
|
|
| VM d'enregistrement | OBS 28+ avec obs-websocket activé. Node.js est installé par le script si absent |
|
|
|
|
---
|
|
|
|
## Étape 1 — Préparer Gitea
|
|
|
|
### Secret
|
|
|
|
Dans **Paramètres du dépôt → Actions → Secrets**, ajoute :
|
|
|
|
| Nom | Valeur |
|
|
| --- | --- |
|
|
| `REGISTERYKEY` | Jeton d'accès du compte `jeanbon`, portées **repository** et **package** |
|
|
|
|
### Variable optionnelle
|
|
|
|
Le workflow déduit l'hôte du registre de l'URL de ton instance. Si elle est
|
|
publiée sous un autre nom que celui vu par les runners, ajoute la variable
|
|
`REGISTRY_HOST` (par ex. `git.jeanbonapp.com`, sans schéma).
|
|
|
|
### Vérifier les runners
|
|
|
|
Dans **Site Administration → Runners**, les labels doivent inclure
|
|
`ubuntu-latest` et `windows-latest`. S'ils diffèrent, adapte les deux champs
|
|
`runs-on:` de [.gitea/workflows/release.yml](.gitea/workflows/release.yml).
|
|
|
|
---
|
|
|
|
## Étape 2 — Premier build
|
|
|
|
Pousse sur `main`, ou lance le workflow à la main. Il produit :
|
|
|
|
| Artefact | Emplacement |
|
|
| --- | --- |
|
|
| Image du plan de contrôle | `<gitea>/jeanbon/stream-control-server:latest` |
|
|
| Bundle d'agent | paquet générique `stream-control-agent`, fichier `agent.cjs` |
|
|
| Scripts d'installation | même paquet, `install-agent.sh` et `install-agent.ps1` |
|
|
|
|
Chaque build publie une version immuable (`0.1.0-<sha>`, ou `1.2.3` sur une
|
|
étiquette `v1.2.3`). L'alias `latest` ne suit que `main` et les étiquettes.
|
|
|
|
Le pipeline refuse de publier un bundle qui ne démarre pas : il exécute
|
|
`agent.cjs --check` sur Linux **et** sur Windows, et valide la syntaxe de
|
|
`install-agent.ps1` sur le runner Windows.
|
|
|
|
---
|
|
|
|
## Étape 3 — Déployer l'interface
|
|
|
|
Sur la machine du plan de contrôle :
|
|
|
|
```bash
|
|
mkdir -p /opt/stream-control && cd /opt/stream-control
|
|
|
|
# Récupérer compose et modèle d'environnement depuis le dépôt
|
|
curl -fsSLO https://git.jeanbonapp.com/jeanbon/stream-control/raw/branch/main/docker-compose.yml
|
|
curl -fsSL https://git.jeanbonapp.com/jeanbon/stream-control/raw/branch/main/.env.production.example -o .env
|
|
chmod 600 .env
|
|
```
|
|
|
|
Génère les secrets et complète `.env` :
|
|
|
|
```bash
|
|
echo "SESSION_SECRET=$(openssl rand -hex 32)"
|
|
echo "ENROLLMENT_TOKEN=$(openssl rand -hex 24)"
|
|
```
|
|
|
|
À renseigner impérativement :
|
|
|
|
| Variable | Rôle |
|
|
| --- | --- |
|
|
| `IMAGE` | `git.jeanbonapp.com/jeanbon/stream-control-server:latest` |
|
|
| `ADMIN_PASSWORD` | Mot de passe du dashboard |
|
|
| `SESSION_SECRET` | Clé de signature des sessions |
|
|
| `ENROLLMENT_TOKEN` | Jeton présenté par les agents à leur première connexion |
|
|
| `BIND_ADDR` | Interface d'écoute — mets l'IP LAN/VPN si la machine a une patte publique |
|
|
|
|
Puis :
|
|
|
|
```bash
|
|
docker login git.jeanbonapp.com -u jeanbon # jeton avec la portée package
|
|
docker compose up -d
|
|
docker compose logs -f
|
|
```
|
|
|
|
Contrôle : `curl http://localhost:8080/healthz` doit répondre
|
|
`{"ok":true,"agents":0}`.
|
|
|
|
La base SQLite vit dans `./data`, monté depuis l'hôte — **c'est le seul état à
|
|
sauvegarder**.
|
|
|
|
La base tourne en mode WAL : les écritures récentes vivent dans
|
|
`stream-control.sqlite-wal` et pas encore dans le fichier principal. Copier le
|
|
seul `.sqlite` pendant que le serveur tourne donne une sauvegarde tronquée. Le
|
|
plus sûr est un arrêt de deux secondes :
|
|
|
|
```bash
|
|
docker compose stop server
|
|
tar czf ~/stream-control-$(date +%F).tar.gz data/
|
|
docker compose start server
|
|
```
|
|
|
|
À chaud, copie impérativement les trois fichiers ensemble (`.sqlite`,
|
|
`-wal`, `-shm`) — jamais le premier seul.
|
|
|
|
---
|
|
|
|
## Étape 4 — Déployer un agent
|
|
|
|
Une seule commande par VM. Le `<JETON_ENROLEMENT>` est l'`ENROLLMENT_TOKEN` du
|
|
serveur : l'agent s'enregistre tout seul, reçoit un jeton permanent et le
|
|
persiste.
|
|
|
|
### Ubuntu
|
|
|
|
```bash
|
|
curl -fsSL https://git.jeanbonapp.com/api/packages/jeanbon/generic/stream-control-agent/latest/install-agent.sh \
|
|
| sudo bash -s -- \
|
|
--registry https://git.jeanbonapp.com \
|
|
--server ws://control.lan:8080/ws/agent \
|
|
--token <JETON_ENROLEMENT> \
|
|
--name vm-rec-01 \
|
|
--obs-password <MDP_OBS>
|
|
```
|
|
|
|
Le script installe Node.js et `xdotool` si besoin, dépose le bundle dans
|
|
`/opt/stream-control-agent`, écrit un service systemd et lance un diagnostic.
|
|
|
|
L'agent tourne sous le compte qui a invoqué `sudo` — celui qui ouvre la session
|
|
graphique d'OBS. Force-le avec `--user` si ce n'est pas le bon.
|
|
|
|
### Windows
|
|
|
|
Dans un PowerShell **administrateur**, sur le compte qui lance OBS :
|
|
|
|
```powershell
|
|
& ([scriptblock]::Create((irm 'https://git.jeanbonapp.com/api/packages/jeanbon/generic/stream-control-agent/latest/install-agent.ps1'))) `
|
|
-Registry 'https://git.jeanbonapp.com' `
|
|
-Server 'ws://control.lan:8080/ws/agent' `
|
|
-Token '<JETON_ENROLEMENT>' `
|
|
-Name 'vm-rec-02' `
|
|
-ObsPassword '<MDP_OBS>'
|
|
```
|
|
|
|
L'agent est enregistré comme **tâche planifiée à l'ouverture de session**, pas
|
|
comme service : un service Windows tourne en session 0 et ne verrait ni OBS ni la
|
|
fenêtre du navigateur.
|
|
|
|
### Si le paquet est privé
|
|
|
|
Ajoute `--package-token <JETON>` (Linux) ou `-PackageToken '<JETON>'` (Windows),
|
|
avec un jeton en lecture sur les paquets.
|
|
|
|
### Vérifier
|
|
|
|
```bash
|
|
sudo -u <user> node /opt/stream-control-agent/agent.cjs --check # Linux
|
|
node C:\stream-control-agent\agent.cjs --check # Windows
|
|
```
|
|
|
|
Le diagnostic contrôle la configuration, la joignabilité du serveur et d'OBS, et
|
|
les prérequis du rappel plein écran (`xdotool`, `DISPLAY`, PowerShell).
|
|
|
|
---
|
|
|
|
## Mises à jour
|
|
|
|
**Interface** — le tag `latest` bouge à chaque build sur `main` :
|
|
|
|
```bash
|
|
cd /opt/stream-control && docker compose pull && docker compose up -d
|
|
```
|
|
|
|
Épingle une version précise dans `IMAGE` si tu préfères maîtriser le moment.
|
|
|
|
**Agents** — relance exactement la même commande d'installation. Le script
|
|
détecte l'installation existante, remplace le binaire et **conserve
|
|
`agent.config.json`** : l'identité de l'agent est préservée. Sans cela, l'agent
|
|
se ré-enrôlerait et apparaîtrait en double dans le dashboard.
|
|
|
|
Pour installer une version figée plutôt que `latest`, remplace `latest` par la
|
|
version voulue dans l'URL **et** passe `--version <VERSION>`.
|
|
|
|
---
|
|
|
|
## Sécurité
|
|
|
|
Ce déploiement est en **HTTP sur réseau privé**, conformément au choix retenu.
|
|
Ce que cela implique concrètement :
|
|
|
|
- Les jetons d'agent, le mot de passe du dashboard et les jetons de session
|
|
circulent **en clair**. Toute machine capable de sniffer le segment réseau peut
|
|
les récupérer et prendre la main sur les agents.
|
|
- Le port ne doit **jamais** être joignable depuis Internet. Restreins `BIND_ADDR`
|
|
à l'IP LAN ou VPN, et ferme le port au pare-feu :
|
|
```bash
|
|
ufw allow from 10.0.0.0/8 to any port 8080 proto tcp
|
|
```
|
|
- Le mot de passe obs-websocket est stocké en base et poussé aux agents ; il n'est
|
|
jamais renvoyé au navigateur (masqué en `********`).
|
|
- `agent.config.json` est en `600` et porte le jeton permanent de l'agent.
|
|
|
|
Passer en HTTPS plus tard ne demande qu'un reverse proxy devant le conteneur et
|
|
le remplacement de `ws://` par `wss://` dans les commandes d'installation —
|
|
[deploy/nginx.conf.example](deploy/nginx.conf.example) donne le bloc de conf.
|
|
La rotation des jetons se fait alors depuis le dashboard, agent par agent.
|
|
|
|
---
|
|
|
|
## Dépannage
|
|
|
|
| Symptôme | Piste |
|
|
| --- | --- |
|
|
| `docker compose up` : *manifest unknown* | `docker login` non fait, ou build jamais lancé |
|
|
| Le conteneur redémarre en boucle | `docker compose logs server` — le plus souvent `ADMIN_PASSWORD` ou `SESSION_SECRET` absent de `.env` |
|
|
| `unable to open database file` (`ERR_SQLITE_ERROR`, errcode 14) | Le répertoire `./data` de l'hôte n'appartient pas à l'uid du conteneur. L'entrypoint le corrige automatiquement ; si tu as forcé un `user:` dans le compose, il ne peut plus le faire — aligne alors la propriété à la main : `sudo chown -R 1000:1000 data` |
|
|
| Agent absent du dashboard | `--server` erroné, ou `ENROLLMENT_TOKEN` différent de celui du serveur. `journalctl -u stream-control-agent -f` |
|
|
| Agent en ligne, OBS déconnecté | obs-websocket désactivé ou mot de passe erroné. Le diagnostic teste le port |
|
|
| Rappel plein écran sans effet (Linux) | Session Wayland au lieu de X11, ou `DISPLAY` inaccessible au service. Le diagnostic signale les deux |
|
|
| Rappel plein écran sans effet (Windows) | La tâche ne tourne pas dans la session interactive : vérifie que le compte de `-RunAsUser` est bien celui ouvert sur la VM |
|
|
| Agent en double après réinstallation | `agent.config.json` avait été supprimé : l'agent s'est ré-enrôlé. Supprime le doublon dans le dashboard |
|
|
| Workflow : *unauthorized* au push | `REGISTERYKEY` sans la portée **package**, ou expiré |
|
|
|
|
### Journaux
|
|
|
|
```bash
|
|
docker compose logs -f server # plan de contrôle
|
|
journalctl -u stream-control-agent -f # agent Linux
|
|
Get-ScheduledTaskInfo -TaskName StreamControlAgent # agent Windows
|
|
```
|
|
|
|
Le dashboard affiche aussi le journal consolidé de tous les agents, persisté en
|
|
base — souvent le point de départ le plus rapide.
|