Files
lidar_rendu/docs/DEPLOY_WEBAPP.md
2026-09-27 22:31:54 +02:00

6.9 KiB
Raw Blame History

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.

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/:

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:

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 (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)

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):

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
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 + Zone ("Add area": draw a rectangle → IGN download + run on the worker), ⤒ Compléter ("Complete": already-downloaded but incomplete tiles) and ↻ Générer cette dalle ("Generate this tile": info panel on click) buttons 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 Arrêter ("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

cd <checkout> && git pull && docker compose -f docker-compose.worker.yml up -d --build

Pi

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.