Files
lidar_rendu/docs/DEPLOY_WEBAPP.md
Antoine fb892ea9f2 Translate the whole project to English and fix outdated comments and help
Comments, docstrings, logs, CLI help, map UI, legends, PDF sheet, scripts,
compose files and AGENTS.md are now English. Data keys stay unchanged
(relief_oriente, densite_sol, visualisations/, API JSON keys, link params).
Wrong comments and help defaults found along the way are corrected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 23:16:45 +02:00

180 lines
7.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Two-machine deployment: lightweight map + processing worker
Two-machine architecture: the **map** (interface, XYZ tile pyramid, API) runs
on a Raspberry Pi; **tile generation** (IGN downloads, PDAL, GPU) runs on a
powerful machine. Both run the same server (`lidar_pipeline.mapserve`, image
`lidar-maps`), the powerful machine in its full version (pipeline included).
```
Browser ──HTTP──▶ Raspberry Pi (lightweight lidar-maps image, port 8975)
│ serves the map + the pyramid (cache-only + background
│ maintenance, LIDAR_TILE_CACHE_ONLY / LIDAR_TILE_BACKGROUND)
│ /api/generate, /api/preview, /api/status
│ └─ forwarded to ──▶ processing worker
│ tiles fetched back from the worker (LIDAR_SOURCE_URL:
│ /api/tiles inventory + versioned static assets)
▼
Processing worker (full image,
docker-compose.worker.yml service `worker`):
IGN download + GPU pipeline (tile generator)
+ tile pyramid + tile inventory
```
See also `docs/MAPS.md` for the map/tile-pyramid internals referenced below.
## Processing worker (tile generator)
The `worker` service acts as the generator: it accepts generation requests
sent by remote maps (IGN download + PDAL/GPU processing), serves its own tile
pyramid and tile inventory (`/api/tiles` + static `visualisations/`,
`index_thumbs/`, `index_subtiles/`) that lightweight machines fetch on demand.
```bash
docker compose -f docker-compose.worker.yml up -d --build # API at http://<worker-ip>:8973
docker compose -f docker-compose.worker.yml logs -f worker
```
One-off batch processing of tiles already present in `input/`:
```bash
docker compose -f docker-compose.worker.yml run --rm --build process [-r 0.2 | --force]
```
On a machine without a GPU: remove the `gpus: all` lines (CPU processing,
slower). Optional but recommended if the network isn't trusted: protect the
API with a shared token — uncomment in `docker-compose.worker.yml`:
```yaml
environment:
- LIDAR_API_TOKEN=a-secret-to-share
```
## Raspberry Pi (lightweight map)
### 0. Prerequisites on the Pi
- **Architecture**: the image is built natively on the machine (ARM64 or
x86_64, check with `uname -m`). The build happens on the Pi itself
(`Dockerfile.maps`: `python:3.12-slim` base, ~200 MB, no PDAL/GDAL).
- **Docker + compose plugin**: official install
[docs.docker.com/engine/install](https://docs.docker.com/engine/install/)
(verify with `docker compose version`).
- **Disk space**: plan for the cache size (fetched tiles + rendered tiles;
use the size of `output/` on the processing machine as a reference).
### 1. Copy the code onto the Pi (git clone)
```bash
git clone https://github.com/<you>/lidar_rendu.git lidar
cd lidar
```
`output/` and `input/` are git-ignored: the repository only holds the code,
the cache fills on demand from the processing machine.
### 2. Start the map
`docker-compose.maps.yml` (versioned) serves as the base; the Pi's local
configuration lives in an **override** file `docker-compose.maps.override.yml`
(not versioned). Start from the provided template:
```bash
cp docker-compose.maps.override.yml.example docker-compose.maps.override.yml
```
It looks like this (adapt addresses, cache folder and Traefik routing):
```yaml
name: lidar-maps
services:
maps:
volumes: !override # Compose >= 2.24 (replaces ./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 (tiles + inventory)
- LIDAR_GENERATION_URL=http://192.168.1.50:8973 # worker (delegated generation)
# - LIDAR_REMOTE_TOKEN=a-secret-to-share # if LIDAR_API_TOKEN is set on the worker
- LIDAR_TILE_WORKERS=1
- LIDAR_TILE_SOURCE_CACHE_MB=64
- LIDAR_TILE_CACHE_ONLY=1 # browsing renders NOTHING
- LIDAR_TILE_BACKGROUND=1 # the pyramid is maintained as a background task
- LIDAR_TILE_BACKGROUND_PAUSE=1.0
networks: [webapp, proxy]
labels: # optional Traefik routing
- "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 # owned by uid 1000 (container)
docker compose -f docker-compose.maps.yml -f docker-compose.maps.override.yml up -d --build
```
The map is available at `http://<pi-host>:8975/` (and via Traefik if
configured).
`LIDAR_TILE_CACHE_ONLY=1` + `LIDAR_TILE_BACKGROUND=1` flip the load pattern on
a small Pi: browsing renders nothing (a missing tile is served transparent,
with `X-Tile-Pending`), and a background task watches for new or regenerated
tiles and maintains the pyramid at low priority — see `docs/MAPS.md`, section
"Cache-only + background maintenance".
### 3. Generating tiles from the map
The **Generation** tab (**+ Area**: draw a rectangle → IGN download + run on
the worker; **⤒ Complete**: already-downloaded but incomplete tiles) and the
**↻ Generate this tile** button (Tile tab, after clicking a tile) are hidden
if:
- the browser's IP is outside `LIDAR_REGEN_CIDR` (default: loopback + private
RFC1918 ranges; a comma-separated list of CIDRs, or an empty string to lift
the restriction). The IP is the one seen on the connection (preserved by
Docker's DNAT for LAN clients); behind a local reverse proxy (itself inside
the allowed network), `X-Forwarded-For` designates the real client;
- the worker is unreachable AND no local pipeline exists.
A request submitted while a run is already in progress is placed in a
**queue** on the worker side (an in-progress job is never interrupted);
progress is displayed tile by tile (orange/blue/red frames on the map) and the
**Stop** button sends a SIGTERM to the pipeline. At the end of the
run, the map refreshes and pyramid maintenance resumes automatically.
### 4. Centering the map on the GPS position (phone)
Browsers only expose the Geolocation API in a **secure context** (HTTPS):
serve the map behind Traefik (TLS) as above, or, as a last resort, directly
over HTTPS (the standalone entry point `python -m lidar_pipeline.mapserve`
honors `LIDAR_SSL_CERTFILE` / `LIDAR_SSL_KEYFILE`).
## Updating
### Processing machine
```bash
cd <checkout> && git pull && docker compose -f docker-compose.worker.yml up -d --build
```
### Pi
```bash
ssh <pi-host> "cd <checkout> && git pull && docker compose -f docker-compose.maps.yml -f docker-compose.maps.override.yml up -d --build"
```
The interface code is baked into the image (`Dockerfile.maps`): **ANY**
interface change requires a rebuild (`--build`) — without it, the old code
keeps running.