From e8887724888fcef96c2ef1f39db0def7246dd160 Mon Sep 17 00:00:00 2001 From: webfarben Date: Tue, 3 Mar 2026 08:43:30 +0000 Subject: [PATCH] chore: simplify docker-only deployment workflow --- .dockerignore | 14 +++----- .env.example | 10 ++++++ .gitignore | 2 ++ Dockerfile | 3 +- WEB_README.md | 68 +++++++++++++++++++++++++++++++++++++++ deploy.sh | 41 +++++++++++++++++++++++ docker-compose.deploy.yml | 25 ++++++++++++++ docker-compose.yml | 20 ++++++++++-- update.sh | 44 +++++++++++++++++++++++++ 9 files changed, 214 insertions(+), 13 deletions(-) create mode 100644 .env.example create mode 100755 deploy.sh create mode 100644 docker-compose.deploy.yml create mode 100755 update.sh diff --git a/.dockerignore b/.dockerignore index 73a3b57..19b4be0 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,10 +1,4 @@ -.git -.venv -__pycache__ -*.pyc -*.pyo -*.pyd -*.log -build/ -*.ics -*.pdf +* +!pdf_to_ics.py +!web/ +!web/** diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..141727b --- /dev/null +++ b/.env.example @@ -0,0 +1,10 @@ +# Docker-only Deployment Konfiguration +# Kopieren nach .env und Werte anpassen: +# cp .env.example .env + +# Container-Image mit festem Release-Tag (kein latest) +PDF_TO_ICS_IMAGE=ghcr.io/webfarben/pdf_to_ics:v1.0.0 + +# Optional: App-interne Basic Auth (leer = deaktiviert) +WEB_AUTH_USER= +WEB_AUTH_PASSWORD= diff --git a/.gitignore b/.gitignore index d3167f2..4ac4c4a 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,8 @@ .venv/ __pycache__/ .pdf_to_ics_config.json +.env +.env.local # Build artifacts dist/ diff --git a/Dockerfile b/Dockerfile index 332e80b..a6ae669 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,7 +8,8 @@ WORKDIR /app COPY web/requirements-web.txt /app/web/requirements-web.txt RUN pip install --no-cache-dir -r /app/web/requirements-web.txt -COPY . /app +COPY pdf_to_ics.py /app/pdf_to_ics.py +COPY web /app/web EXPOSE 8000 diff --git a/WEB_README.md b/WEB_README.md index ede3ce0..344decb 100644 --- a/WEB_README.md +++ b/WEB_README.md @@ -21,6 +21,74 @@ Danach im Browser öffnen: Diese Variante ist für deinen aktuellen Wunsch geeignet: öffentlich erreichbar ohne VPN. +### Docker-only Betrieb (empfohlen für Webserver) + +Wenn auf dem Webserver **nur Docker laufen soll**, nutze die image-basierte Compose-Datei statt lokalem Build. + +1) Vorlage übernehmen: + +```bash +cp .env.example .env +``` + +2) Optional Werte in `.env` anpassen: + +```dotenv +PDF_TO_ICS_IMAGE=ghcr.io/webfarben/pdf_to_ics:v1.0.0 +WEB_AUTH_USER= +WEB_AUTH_PASSWORD= +``` + +3) Starten: + +```bash +docker compose -f docker-compose.deploy.yml up -d +``` + +Kurzvariante für Erststart: + +```bash +./deploy.sh +``` + +4) Update: + +```bash +git pull +# in .env auf neues Release setzen, z. B. v1.1.0 +docker compose -f docker-compose.deploy.yml pull +docker compose -f docker-compose.deploy.yml up -d +``` + +Kurzvariante mit Helper-Skript: + +```bash +./update.sh +``` + +Hinweis: Für ein neues Release vorher den Tag in `.env` anpassen. + +Damit entfallen lokale Python/venv-Abhängigkeiten auf dem Host vollständig. +Mit festem Tag bleiben Deployments reproduzierbar und Updates kontrolliert. + +### Schlanker Checkout auf dem Server (Sparse) + +Für einen neuen Server-Checkout kannst du den Arbeitsbaum klein halten: + +```bash +git clone --filter=blob:none --sparse pdf_to_ics +cd pdf_to_ics +git sparse-checkout set docker-compose.deploy.yml .env.example deploy.sh update.sh WEB_README.md +``` + +Optional zusätzlich aufnehmen: + +```bash +git sparse-checkout add README.md +``` + +Hinweis: Ein bestehender Voll-Clone wird dadurch nicht automatisch klein; dafür einmal neu klonen. + ### 1) Starten ```bash diff --git a/deploy.sh b/deploy.sh new file mode 100755 index 0000000..1112b6c --- /dev/null +++ b/deploy.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" + +COMPOSE_FILE="docker-compose.deploy.yml" + +if ! command -v docker >/dev/null 2>&1; then + echo "❌ Fehler: docker ist nicht installiert oder nicht im PATH." + exit 1 +fi + +if ! docker compose version >/dev/null 2>&1; then + echo "❌ Fehler: docker compose ist nicht verfügbar." + exit 1 +fi + +if [ ! -f "$COMPOSE_FILE" ]; then + echo "❌ Fehler: $COMPOSE_FILE nicht gefunden." + exit 1 +fi + +if [ ! -f ".env" ]; then + if [ -f ".env.example" ]; then + cp .env.example .env + echo "ℹ️ .env wurde aus .env.example erstellt. Bitte Werte prüfen." + else + echo "❌ Fehler: .env fehlt und keine .env.example vorhanden." + exit 1 + fi +fi + +echo "⬇️ Lade Container-Image..." +docker compose -f "$COMPOSE_FILE" pull + +echo "🚀 Starte Container..." +docker compose -f "$COMPOSE_FILE" up -d + +echo "✅ Deployment abgeschlossen." +docker compose -f "$COMPOSE_FILE" ps diff --git a/docker-compose.deploy.yml b/docker-compose.deploy.yml new file mode 100644 index 0000000..941aa11 --- /dev/null +++ b/docker-compose.deploy.yml @@ -0,0 +1,25 @@ +networks: + proxy: + name: proxy + external: true + +services: + pdf-to-ics-web: + image: ${PDF_TO_ICS_IMAGE:-ghcr.io/webfarben/pdf_to_ics:latest} + container_name: pdf-to-ics-web + restart: unless-stopped + ports: + - "8000:8000" + networks: + - proxy + environment: + - TZ=Europe/Berlin + # Optional aktivieren für App-Login: + - WEB_AUTH_USER=${WEB_AUTH_USER:-} + - WEB_AUTH_PASSWORD=${WEB_AUTH_PASSWORD:-} + healthcheck: + test: ["CMD", "python3", "-c", "import http.client,sys;c=http.client.HTTPConnection('127.0.0.1',8000,timeout=5);c.request('GET','/');r=c.getresponse();sys.exit(0 if r.status in (200,401) else 1)"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 10s diff --git a/docker-compose.yml b/docker-compose.yml index 8a82deb..28a9897 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,3 +1,10 @@ +networks: + internal: + external: false + proxy: + name: proxy + external: true + services: pdf-to-ics-web: build: . @@ -5,8 +12,17 @@ services: restart: unless-stopped ports: - "8000:8000" + networks: + - internal + - proxy environment: - TZ=Europe/Berlin # Optional aktivieren für App-Login: - # - WEB_AUTH_USER=kalender - # - WEB_AUTH_PASSWORD=BitteSicheresPasswortSetzen + - WEB_AUTH_USER=dbregio + - WEB_AUTH_PASSWORD=dbregio + healthcheck: + test: ["CMD", "python3", "-c", "import http.client,sys;c=http.client.HTTPConnection('127.0.0.1',8000,timeout=5);c.request('GET','/');r=c.getresponse();sys.exit(0 if r.status in (200,401) else 1)"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 10s diff --git a/update.sh b/update.sh new file mode 100755 index 0000000..ae7f5a7 --- /dev/null +++ b/update.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" + +COMPOSE_FILE="docker-compose.deploy.yml" + +if ! command -v docker >/dev/null 2>&1; then + echo "❌ Fehler: docker ist nicht installiert oder nicht im PATH." + exit 1 +fi + +if ! docker compose version >/dev/null 2>&1; then + echo "❌ Fehler: docker compose ist nicht verfügbar." + exit 1 +fi + +if [ ! -f "$COMPOSE_FILE" ]; then + echo "❌ Fehler: $COMPOSE_FILE nicht gefunden." + exit 1 +fi + +if [ ! -f ".env" ]; then + if [ -f ".env.example" ]; then + cp .env.example .env + echo "ℹ️ .env wurde aus .env.example erstellt. Bitte Werte prüfen." + else + echo "❌ Fehler: .env fehlt und keine .env.example vorhanden." + exit 1 + fi +fi + +echo "📥 Hole aktuelle Git-Änderungen..." +git pull --ff-only + +echo "⬇️ Lade aktuelles Container-Image..." +docker compose -f "$COMPOSE_FILE" pull + +echo "🚀 Starte/aktualisiere Container..." +docker compose -f "$COMPOSE_FILE" up -d + +echo "✅ Update abgeschlossen." +docker compose -f "$COMPOSE_FILE" ps