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).
7.6 KiB
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.
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/ :
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 :
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: basepython:3.12-slim, ~200 Mo, sans PDAL/GDAL). - Docker + plugin compose : installation officielle
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)
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é) :
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
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-Fordé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
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 :
#!/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) :
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.