deploy: Dockerfile + docker-compose Traefik per VPS pm.tielogic.xyz
Dockerfile (multi-arch, python 3.13-slim):
- uv copiato da ghcr.io/astral-sh/uv per install deps
- System deps: libgl1 libglib2.0-0 (cv2) + libgomp1 (numba)
- uv sync --frozen --no-dev da uv.lock
- ENV: IMAGES_DIR=/data/images, HOST=0.0.0.0, PORT=8080
- HEALTHCHECK su GET /images ogni 30s
docker-compose.yml:
- Service pm2d con image ${REGISTRY}/pm2d:${TAG}
- Volume ./images:/data/images (persistenza upload/UI)
- Network esterna 'traefik' (adattare se diverso)
- Labels Traefik:
- Router HTTPS Host(pm.tielogic.xyz) entrypoint websecure TLS letsencrypt
- Middleware bodysize 50MB (upload multipart)
- Redirect HTTP->HTTPS automatico
main.py: HOST/PORT da env (default 127.0.0.1:8080 per dev locale).
README: sezione Deploy con build/push/run su VPS.
.dockerignore: esclude .venv, Test/, benchmarks/, md files.
Build + smoke test container: OK su port 18080.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,22 @@
|
|||||||
|
.venv
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
.github
|
||||||
|
__pycache__
|
||||||
|
*.pyc
|
||||||
|
*.pyo
|
||||||
|
*.pyd
|
||||||
|
.DS_Store
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
*.log
|
||||||
|
# Test images non necessarie nel container (caricate via volume/UI)
|
||||||
|
Test
|
||||||
|
benchmarks
|
||||||
|
ROADMAP.md
|
||||||
|
shape_model_2d_technical_doc.md
|
||||||
|
*.md
|
||||||
|
!README.md
|
||||||
|
Dockerfile
|
||||||
|
docker-compose*.yml
|
||||||
|
.env
|
||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
FROM python:3.13-slim AS base
|
||||||
|
|
||||||
|
# uv package manager (copia binario ufficiale)
|
||||||
|
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
|
||||||
|
|
||||||
|
# System deps per opencv (libgl/glib), numba (libgomp)
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
libgl1 \
|
||||||
|
libglib2.0-0 \
|
||||||
|
libgomp1 \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install deps da lockfile (layer cachato finché pyproject/uv.lock non cambiano)
|
||||||
|
COPY pyproject.toml uv.lock ./
|
||||||
|
COPY .python-version* ./
|
||||||
|
RUN uv sync --frozen --no-dev
|
||||||
|
|
||||||
|
# Copia sorgenti applicazione
|
||||||
|
COPY pm2d ./pm2d
|
||||||
|
COPY main.py ./
|
||||||
|
|
||||||
|
# Defaults (override via docker-compose env)
|
||||||
|
ENV IMAGES_DIR=/data/images \
|
||||||
|
HOST=0.0.0.0 \
|
||||||
|
PORT=8080 \
|
||||||
|
PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
|
# Cartella dati (montata come volume in compose)
|
||||||
|
RUN mkdir -p /data/images
|
||||||
|
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
|
||||||
|
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8080/images').read()" || exit 1
|
||||||
|
|
||||||
|
CMD ["uv", "run", "python", "main.py"]
|
||||||
@@ -140,3 +140,52 @@ Implementato con **shift+add vettorizzato NumPy** (O(N_features · H · W) invec
|
|||||||
- ICP locale per raffinamento pose
|
- ICP locale per raffinamento pose
|
||||||
- Vincoli di orientamento: clustering delle pose per eliminare duplicati cross-variante
|
- Vincoli di orientamento: clustering delle pose per eliminare duplicati cross-variante
|
||||||
- Numba JIT per il ciclo shift+add (eventuale 3-5× su scene grandi)
|
- Numba JIT per il ciclo shift+add (eventuale 3-5× su scene grandi)
|
||||||
|
|
||||||
|
## Deploy VPS con Docker + Traefik
|
||||||
|
|
||||||
|
Assume che sulla VPS siano già attivi:
|
||||||
|
- **Traefik** come reverse proxy su network Docker esterna `traefik`
|
||||||
|
- Entrypoints `web` (:80) e `websecure` (:443)
|
||||||
|
- Cert resolver `letsencrypt` configurato
|
||||||
|
|
||||||
|
### Build e push al registry
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build locale
|
||||||
|
docker build -t vps-ip:5000/pm2d:latest .
|
||||||
|
docker push vps-ip:5000/pm2d:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
### Sulla VPS
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Cartella deploy (immagini persistenti qui)
|
||||||
|
mkdir -p /opt/docker/pm2d/images
|
||||||
|
cd /opt/docker/pm2d
|
||||||
|
|
||||||
|
# Copia docker-compose.yml
|
||||||
|
# Imposta REGISTRY / TAG se necessario via .env
|
||||||
|
echo "REGISTRY=vps-ip:5000" > .env
|
||||||
|
echo "TAG=latest" >> .env
|
||||||
|
|
||||||
|
docker compose pull
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
Servizio raggiungibile: **https://pm.tielogic.xyz**
|
||||||
|
|
||||||
|
### Note operative
|
||||||
|
|
||||||
|
- **Volume `./images`**: persistenza delle immagini caricate tramite UI
|
||||||
|
(`IMAGES_DIR=/data/images` nel container). Sopravvive a restart.
|
||||||
|
- **Upload max 50MB**: middleware Traefik `pm2d-bodysize`. Adattare se serve.
|
||||||
|
- **Cache matcher in-memory**: si svuota a restart container (no problema,
|
||||||
|
viene ri-popolata al primo match).
|
||||||
|
- **Healthcheck**: HTTP `GET /images` ogni 30s.
|
||||||
|
- Se nome network Traefik diverso da `traefik`, modifica
|
||||||
|
`docker-compose.yml` sezione `networks`.
|
||||||
|
|
||||||
|
### Adattamenti config Traefik non-standard
|
||||||
|
|
||||||
|
Se la VPS ha convenzioni diverse (es. cert resolver chiamato `le`,
|
||||||
|
entrypoint `https`), modifica i labels nel `docker-compose.yml`.
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
# docker-compose per deploy VPS con Traefik.
|
||||||
|
# Assume che Traefik sia già attivo sulla VPS con:
|
||||||
|
# - network esterna "traefik" (adatta nome se diverso)
|
||||||
|
# - entrypoint "websecure" su :443
|
||||||
|
# - certresolver "letsencrypt" configurato
|
||||||
|
#
|
||||||
|
# Adattare eventualmente: nome network, entrypoint, certresolver.
|
||||||
|
|
||||||
|
services:
|
||||||
|
pm2d:
|
||||||
|
image: ${REGISTRY:-localhost:5000}/pm2d:${TAG:-latest}
|
||||||
|
container_name: pm2d
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
IMAGES_DIR: /data/images
|
||||||
|
HOST: 0.0.0.0
|
||||||
|
PORT: 8080
|
||||||
|
volumes:
|
||||||
|
# Persistenza immagini tra restart (upload/selezione)
|
||||||
|
- ./images:/data/images
|
||||||
|
networks:
|
||||||
|
- traefik
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
|
||||||
|
# Router HTTPS principale
|
||||||
|
- "traefik.http.routers.pm2d.rule=Host(`pm.tielogic.xyz`)"
|
||||||
|
- "traefik.http.routers.pm2d.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.pm2d.tls=true"
|
||||||
|
- "traefik.http.routers.pm2d.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.services.pm2d.loadbalancer.server.port=8080"
|
||||||
|
|
||||||
|
# Middleware: upload fino a 50MB (default Traefik bufferizza a 4MB)
|
||||||
|
- "traefik.http.middlewares.pm2d-bodysize.buffering.maxRequestBodyBytes=52428800"
|
||||||
|
- "traefik.http.routers.pm2d.middlewares=pm2d-bodysize"
|
||||||
|
|
||||||
|
# Redirect HTTP → HTTPS
|
||||||
|
- "traefik.http.routers.pm2d-http.rule=Host(`pm.tielogic.xyz`)"
|
||||||
|
- "traefik.http.routers.pm2d-http.entrypoints=web"
|
||||||
|
- "traefik.http.routers.pm2d-http.middlewares=pm2d-redirect-https"
|
||||||
|
- "traefik.http.middlewares.pm2d-redirect-https.redirectscheme.scheme=https"
|
||||||
|
- "traefik.http.middlewares.pm2d-redirect-https.redirectscheme.permanent=true"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
traefik:
|
||||||
|
external: true
|
||||||
@@ -1,10 +1,14 @@
|
|||||||
"""Entry-point PM2D — webapp HTML.
|
"""Entry-point PM2D — webapp HTML.
|
||||||
|
|
||||||
Esegui: uv run python main.py
|
Esegui locale: uv run python main.py (default 127.0.0.1:8080)
|
||||||
Apri: http://127.0.0.1:8080/
|
Container: HOST=0.0.0.0 PORT=8080 python main.py
|
||||||
"""
|
"""
|
||||||
|
import os
|
||||||
|
|
||||||
from pm2d.web.server import serve
|
from pm2d.web.server import serve
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
serve(host="127.0.0.1", port=8080)
|
host = os.environ.get("HOST", "127.0.0.1")
|
||||||
|
port = int(os.environ.get("PORT", "8080"))
|
||||||
|
serve(host=host, port=port)
|
||||||
|
|||||||
Reference in New Issue
Block a user