dd0f6e483a
Two genuinely-offline QR readers showed GREEN: the adapter's healthCheck was
hardcoded to { ready, "stub" } and never probed. These are PUSH devices (scan →
GET our backend, resolve by serial) with NO TCP port, so a connect probe has
nothing to hit — the stub "solved" that by lying. False-healthy is the worst
failure for a status bar.
- Optional reader IP field (monitor-ONLY; scans still resolve by serial,
operation unchanged).
- Unprivileged ICMP ping (drivers/icmp.ts): shells /bin/ping -c1, exit-0 = reply.
No native dep, no CAP_NET_RAW. docker-compose.prod.yml sets
net.ipv4.ping_group_range so it works for the non-root container user.
- healthCheck: replies → ready, no reply → offline, NO IP → degraded
("set IP to monitor") — never a false green.
Verified on hardware: readers (10.0.10.7/.8) answer ICMP on the device VLAN;
UI Test connection → "● ready — ping 10.0.10.7". Tests: reader.test.ts (4).
Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
67 lines
2.4 KiB
YAML
67 lines
2.4 KiB
YAML
# PROD override: pull pinned registry images (no local build), restart always, real
|
|
# recognizer, and a CADDY reverse proxy in front so operators reach the booth on a clean
|
|
# port-80 URL (no :3000) — and a path to real TLS later. Server + vision stay INTERNAL
|
|
# (only Caddy publishes a port). Use with the base file and pin TAG to the branch you deploy:
|
|
# REGISTRY=git.infra.msai.al/mca/parking_solution TAG=main \
|
|
# docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
|
|
# See wiki/decisions/container-deployment.md.
|
|
|
|
services:
|
|
# Reverse proxy: :80 → server:3000 (WebSocket /api/ws upgrades pass through natively).
|
|
# Caddy is a single static binary with a one-line proxy config; swapping http:// for the
|
|
# site's real hostname later enables automatic HTTPS. The booth is reached at
|
|
# http://<name-or-ip>/ (the name set via hosts/DNS on-site — NOT baked into any image).
|
|
proxy:
|
|
image: caddy:2-alpine
|
|
restart: always
|
|
ports:
|
|
- "80:80"
|
|
# - "443:443" # uncomment when moving to TLS (and set a real hostname in Caddyfile)
|
|
volumes:
|
|
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
|
- caddy-data:/data
|
|
- caddy-config:/config
|
|
depends_on:
|
|
- server
|
|
networks:
|
|
- parking
|
|
logging:
|
|
driver: json-file
|
|
options:
|
|
max-size: "10m"
|
|
max-file: "3"
|
|
|
|
server:
|
|
restart: always
|
|
# No published port — only the proxy reaches the server, over the private network.
|
|
expose:
|
|
- "3000"
|
|
# Let the server ICMP-ping push-only readers (Dingtian/GEE QR) for an honest
|
|
# online/offline status WITHOUT CAP_NET_RAW: opening ping_group_range to all gids
|
|
# enables `/bin/ping` in unprivileged SOCK_DGRAM mode for the non-root runtime user.
|
|
# (The reader exposes no TCP port, so a connect-probe can't work — see reader.ts /
|
|
# wiki/entities/dingtian-qr-reader.md.)
|
|
sysctls:
|
|
- net.ipv4.ping_group_range=0 2147483647
|
|
logging:
|
|
driver: json-file
|
|
options:
|
|
max-size: "10m"
|
|
max-file: "3"
|
|
|
|
vision:
|
|
restart: always
|
|
# The real ANPR engine. The image baked the model weights at build (offline-first).
|
|
environment:
|
|
VISION_RECOGNIZER: fast_alpr
|
|
# No published ports — vision is reached only by the server over the private network.
|
|
logging:
|
|
driver: json-file
|
|
options:
|
|
max-size: "10m"
|
|
max-file: "3"
|
|
|
|
volumes:
|
|
caddy-data:
|
|
caddy-config:
|