La carte à tuiles XYZ devient la seule interface : l'API de génération (preview, generate, status, stop, file, cell), le job unique + file persistante, la délégation LIDAR_GENERATION_URL et les garde-fous (token, LIDAR_REGEN_CIDR) passent de webapp.py à mapserve.py ; l'interface gagne les boutons + Zone / ⤒ Compléter / régénération à la dalle, les options de run et la progression cadre par cadre. mapserve sert aussi l'inventaire /api/tiles et les dalles en statique versionné : le worker image complète remplace la webapp sur le 8973 du générateur, le Pi n'exécute plus que lidar-maps. index.py se réduit aux registres partagés + vignettes/sous-tuiles/inventaire (l'UI HTML/JS et les mosaïques d'overview partent avec export.py et les compose/scripts de la webapp).
191 lines
7.6 KiB
Markdown
191 lines
7.6 KiB
Markdown
# Déploiement carte légère + machine de traitement
|
||
|
||
Architecture deux machines : la **carte** (interface, pyramide de tuiles XYZ,
|
||
API) tourne sur un Raspberry Pi ; la **génération de tuiles** (téléchargement
|
||
IGN, PDAL, GPU) tourne sur une machine puissante. Les deux exécutent le même
|
||
serveur (`lidar_pipeline.mapserve`, image `lidar-maps`), la machine puissante
|
||
en version complète (pipeline inclus).
|
||
|
||
```
|
||
Navigateur ──HTTP──▶ Raspberry Pi (image légère lidar-maps, port 8975)
|
||
│ sert la carte + la pyramide (cache seule + maintenance
|
||
│ de fond, LIDAR_TILE_CACHE_ONLY / LIDAR_TILE_BACKGROUND)
|
||
│ /api/generate, /api/preview, /api/status
|
||
│ └─ transmis à ──▶ machine de traitement
|
||
│ dalles rapatriées du worker (LIDAR_SOURCE_URL :
|
||
│ inventaire /api/tiles + statiques versionnées)
|
||
▼
|
||
Machine de traitement (image complète,
|
||
docker-compose.worker.yml service `worker`) :
|
||
téléchargement IGN + pipeline GPU (générateur de tuiles)
|
||
+ pyramide de tuiles + inventaire des dalles
|
||
```
|
||
|
||
## Machine de traitement (générateur de tuiles)
|
||
|
||
Le service `worker` joue le rôle de générateur : il accepte les demandes de
|
||
génération envoyées par les cartes distantes (téléchargement IGN + traitement
|
||
PDAL/GPU), sert sa propre pyramide de tuiles et l'inventaire des dalles
|
||
(`/api/tiles` + `visualisations/`, `index_thumbs/`, `index_subtiles/` en
|
||
statique) que les machines légères rapatrient à la demande.
|
||
|
||
```bash
|
||
docker compose -f docker-compose.worker.yml up -d --build # API sur http://<ip-machine>:8973
|
||
docker compose -f docker-compose.worker.yml logs -f worker
|
||
```
|
||
|
||
Traitement batch ponctuel des dalles déjà présentes dans `input/` :
|
||
|
||
```bash
|
||
docker compose -f docker-compose.worker.yml run --rm --build process [-r 0.2 | --force]
|
||
```
|
||
|
||
Sur une machine sans GPU : retirer les lignes `gpus: all` (traitement CPU,
|
||
plus lent). Optionnel mais recommandé si le réseau n'est pas de confiance :
|
||
protéger l'API avec un jeton partagé — décommenter dans
|
||
`docker-compose.worker.yml` :
|
||
|
||
```yaml
|
||
environment:
|
||
- LIDAR_API_TOKEN=un-secret-à-partager
|
||
```
|
||
|
||
## Raspberry Pi (carte légère)
|
||
|
||
### 0. Prérequis sur le Pi
|
||
|
||
- **Architecture** : image construite nativement sur la machine (ARM64 ou
|
||
x86_64, vérifier avec `uname -m`). Le build se fait sur le Pi lui-même
|
||
(`Dockerfile.maps` : base `python:3.12-slim`, ~200 Mo, sans PDAL/GDAL).
|
||
- **Docker + plugin compose** : installation officielle
|
||
[docs.docker.com/engine/install](https://docs.docker.com/engine/install/)
|
||
(tester avec `docker compose version`).
|
||
- **Espace disque** : prévoir la taille du cache (dalles rapatriées + tuiles
|
||
rendues ; compter la taille de `output/` sur la machine de traitement).
|
||
|
||
### 1. Copier le code sur le Pi (git clone)
|
||
|
||
```bash
|
||
git clone ssh://git@git.example.fr:2222/code_public/lidar_rendu.git lidar
|
||
cd lidar
|
||
```
|
||
|
||
`output/` et `input/` sont ignorés par git : le dépôt ne contient que le
|
||
code, le cache se remplit à la demande depuis la machine de traitement.
|
||
|
||
### 2. Lancer la carte
|
||
|
||
`docker-compose.maps.yml` (versionné) sert de base ; la configuration locale
|
||
du Pi vit dans un **override** `docker-compose.maps.override.yml` (non
|
||
versionné) :
|
||
|
||
```yaml
|
||
name: lidar-maps
|
||
services:
|
||
maps:
|
||
volumes: !override # Compose >= 2.24 (remplace ./output)
|
||
- /srv/lidar/output:/data/output
|
||
mem_limit: 1g
|
||
memswap_limit: 1g
|
||
environment:
|
||
- TZ=Europe/Paris
|
||
- LIDAR_SOURCE_URL=http://192.168.1.50:8973 # worker (dalles + inventaire)
|
||
- LIDAR_GENERATION_URL=http://192.168.1.50:8973 # worker (génération déléguée)
|
||
# - LIDAR_REMOTE_TOKEN=un-secret-à-partager # si LIDAR_API_TOKEN côté worker
|
||
- LIDAR_TILE_WORKERS=1
|
||
- LIDAR_TILE_SOURCE_CACHE_MB=64
|
||
- LIDAR_TILE_CACHE_ONLY=1 # la navigation ne rend RIEN
|
||
- LIDAR_TILE_BACKGROUND=1 # la pyramide est entretenue en tâche de fond
|
||
- LIDAR_TILE_BACKGROUND_PAUSE=1.0
|
||
networks: [webapp, proxy]
|
||
labels: # routage Traefik éventuel
|
||
- "traefik.enable=true"
|
||
- "traefik.http.routers.lidar-maps.rule=Host(`lidar.example.fr`)"
|
||
- "traefik.http.routers.lidar-maps.entrypoints=websecure"
|
||
- "traefik.http.routers.lidar-maps.tls.certresolver=myresolver"
|
||
- "traefik.http.services.lidar-maps.loadbalancer.server.port=8975"
|
||
|
||
networks:
|
||
webapp:
|
||
name: lidar_rendu_default
|
||
external: true
|
||
proxy:
|
||
name: proxy
|
||
external: true
|
||
```
|
||
|
||
```bash
|
||
mkdir -p /srv/lidar/output # appartenant à l'uid 1000 (conteneur)
|
||
docker compose -f docker-compose.maps.yml -f docker-compose.maps.override.yml up -d --build
|
||
```
|
||
|
||
La carte est sur `http://<ip-pi>:8975/` (et via Traefik si configuré).
|
||
|
||
`LIDAR_TILE_CACHE_ONLY=1` + `LIDAR_TILE_BACKGROUND=1` inversent la charge sur
|
||
un petit Pi : la navigation ne rend rien (tuile absente = transparente,
|
||
`X-Tile-Pending`), une tâche de fond surveille les dalles nouvelles ou
|
||
régénérées et entretient la pyramide à basse priorité — cf. `docs/MAPS.md`
|
||
§ « Cache seule + maintenance de fond ».
|
||
|
||
### 3. Génération de tuiles depuis la carte
|
||
|
||
Les boutons **+ Zone** (dessiner un rectangle → téléchargement IGN + run sur
|
||
le worker), **⤒ Compléter** (dalles déjà téléchargées incomplètes) et
|
||
**↻ Générer cette dalle** (fiche d'infos au clic) sont masqués si :
|
||
|
||
- le navigateur vient d'une IP hors `LIDAR_REGEN_CIDR` (défaut : boucle
|
||
locale + plages privées RFC1918 ; liste de CIDR séparés par virgules,
|
||
chaîne vide pour lever la restriction). L'IP est celle de la connexion
|
||
(conservée par le DNAT Docker pour les clients du LAN) ; derrière un
|
||
reverse proxy local (dans le réseau autorisé), `X-Forwarded-For` désigne
|
||
le client réel ;
|
||
- le worker est injoignable ET aucun pipeline local n'existe.
|
||
|
||
Une demande lancée pendant un run part en **file d'attente** côté worker
|
||
(jamais de coupure du travail en place) ; la progression s'affiche dalle par
|
||
dalle (cadres orange/bleu/rouge sur la carte) et le bouton **Arrêter** envoie
|
||
un SIGTERM au pipeline. À la fin du run, la carte se rafraîchit et la
|
||
maintenance de pyramide repart automatiquement.
|
||
|
||
### 4. Centrer la carte sur la position GPS (téléphone)
|
||
|
||
Les navigateurs n'exposent l'API Geolocation qu'en **contexte sécurisé**
|
||
(HTTPS) : servir la carte derrière Traefik (TLS) comme ci-dessus, ou en
|
||
dernier recours en HTTPS direct (l'entrée autonome `python -m
|
||
lidar_pipeline.mapserve` honore `LIDAR_SSL_CERTFILE` / `LIDAR_SSL_KEYFILE`).
|
||
|
||
## Mise à jour
|
||
|
||
### Machine de traitement
|
||
|
||
```bash
|
||
cd <checkout> && git pull && docker compose -f docker-compose.worker.yml up -d --build
|
||
```
|
||
|
||
### Pi (depuis le poste de pilotage)
|
||
|
||
Le poste de pilotage interdit l'appel `ssh` direct : le wrapper
|
||
`ssh` fournit l'accès autorisé avec transfert d'agent (`-A`) —
|
||
les `git pull` distants utilisent la clé locale :
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
set -euo pipefail
|
||
HOST="${1:-192.168.3.10}" # machine carte par défaut (le Pi)
|
||
shift || true
|
||
exec ssh -A -o BatchMode=yes -o ConnectTimeout=5 \
|
||
-o StrictHostKeyChecking=accept-new "$HOST" "$@"
|
||
```
|
||
|
||
Mise à jour complète du Pi (checkout git en `/srv/lidar_rendu`,
|
||
avec l'override Traefik) :
|
||
|
||
```bash
|
||
ssh 192.168.3.10 "cd /srv/lidar_rendu && git pull && \
|
||
docker compose -f docker-compose.maps.yml -f docker-compose.maps.override.yml up -d --build"
|
||
```
|
||
|
||
Le code de l'interface est bâché dans l'image (`Dockerfile.maps`) : **TOUT**
|
||
changement d'interface exige le rebuild (`--build`), sans lui l'ancien code
|
||
tourne.
|