"Add test script and guide for separate servers setup (feat)"

This commit is contained in:
Till Tomczak 2025-05-23 08:52:11 +02:00
parent 03ff4260e2
commit c1e8ee01c5
4 changed files with 625 additions and 477 deletions

View File

@ -10,7 +10,7 @@ PYTHONUNBUFFERED=1
# SQLite (Default) # SQLite (Default)
DATABASE_PATH=instance/myp.db DATABASE_PATH=instance/myp.db
# PostgreSQL (Optional) # PostgreSQL (Optional - für Produktionsumgebung empfohlen)
DB_NAME=myp_backend DB_NAME=myp_backend
DB_USER=myp_user DB_USER=myp_user
DB_PASSWORD=secure_backend_password DB_PASSWORD=secure_backend_password
@ -48,18 +48,38 @@ REDIS_DB=0
# === LOGGING === # === LOGGING ===
LOG_LEVEL=INFO LOG_LEVEL=INFO
LOG_FILE=logs/backend.log LOG_FILE=logs/backend.log
LOG_MAX_SIZE=10485760 LOG_MAX_BYTES=10485760
LOG_BACKUP_COUNT=5 LOG_BACKUP_COUNT=5
# === DATEISYSTEM === # === PRODUKTIONS-KONFIGURATION ===
UPLOAD_FOLDER=uploads # Gunicorn-Einstellungen
MAX_CONTENT_LENGTH=16777216 WORKERS=4
BIND_ADDRESS=0.0.0.0:5000
TIMEOUT=30
KEEP_ALIVE=5
MAX_REQUESTS=1000
MAX_REQUESTS_JITTER=100
# === SICHERHEITS-EINSTELLUNGEN ===
WTF_CSRF_ENABLED=true
FORCE_HTTPS=false
RATE_LIMIT_ENABLED=true
MAX_REQUESTS_PER_MINUTE=60
RATE_LIMIT_WINDOW_MINUTES=15
# === MONITORING === # === MONITORING ===
HEALTH_CHECK_INTERVAL=30 HEALTH_CHECK_INTERVAL=30
METRICS_ENABLED=true METRICS_ENABLED=true
METRICS_PORT=9090 METRICS_PORT=9090
# === JOB-KONFIGURATION ===
JOB_CHECK_INTERVAL=60
SOCKET_CHECK_INTERVAL=120
# === DATEISYSTEM ===
UPLOAD_FOLDER=uploads
MAX_CONTENT_LENGTH=16777216
# === ENTWICKLUNG === # === ENTWICKLUNG ===
DEBUG=false DEBUG=false
TESTING=false TESTING=false

View File

@ -1,7 +1,9 @@
#!/bin/bash #!/bin/bash
# MYP Backend Installations-Skript # 🏭 MYP Backend - Installations-Skript
# Dieses Skript installiert das Backend mit Docker und Host-Netzwerkanbindung # Installiert das Backend für Produktionsbetrieb oder Entwicklung
set -e
# Farbcodes für Ausgabe # Farbcodes für Ausgabe
RED='\033[0;31m' RED='\033[0;31m'
@ -15,496 +17,335 @@ log() {
echo -e "${BLUE}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $1" echo -e "${BLUE}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $1"
} }
success_log() {
echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')] SUCCESS:${NC} $1"
}
warning_log() {
echo -e "${YELLOW}[$(date +'%Y-%m-%d %H:%M:%S')] WARNING:${NC} $1"
}
error_log() { error_log() {
echo -e "${RED}[$(date +'%Y-%m-%d %H:%M:%S')] FEHLER:${NC} $1" >&2 echo -e "${RED}[$(date +'%Y-%m-%d %H:%M:%S')] FEHLER:${NC} $1" >&2
} }
# Funktion zum Bereinigen vorhandener Installationen # Banner
cleanup_existing_installation() { echo "========================================"
log "${YELLOW}Bereinige vorhandene Installation...${NC}" echo "🏭 MYP Backend - Installation"
echo "========================================"
echo ""
# Stoppe und entferne existierende Container # Arbeitsverzeichnis
if docker ps -a | grep -q "myp-backend"; then
log "Stoppe und entferne existierenden Backend-Container..."
docker stop myp-backend &>/dev/null || true
docker rm myp-backend &>/dev/null || true
fi
# Entferne Docker Images
if docker images | grep -q "myp-backend"; then
log "Entferne existierendes Backend-Image..."
docker rmi myp-backend &>/dev/null || true
fi
log "${GREEN}Bereinigung abgeschlossen.${NC}"
}
# Pfade definieren
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
BACKEND_DIR="$SCRIPT_DIR" cd "$SCRIPT_DIR"
# Bereinige existierende Installation log "Arbeitsverzeichnis: $SCRIPT_DIR"
cleanup_existing_installation
# Funktion zur Installation von Docker und Docker Compose für Raspberry Pi # Installation-Modus bestimmen
install_docker() { INSTALL_MODE="development"
log "${YELLOW}Docker ist nicht installiert. Installation wird gestartet...${NC}" if [ "$1" = "--production" ]; then
INSTALL_MODE="production"
# Erkenne Raspberry Pi log "🚀 Produktions-Installation gewählt"
if [ -f /proc/device-tree/model ] && grep -q "Raspberry Pi" /proc/device-tree/model; then elif [ "$1" = "--development" ]; then
log "${GREEN}Raspberry Pi erkannt. Installiere Docker für ARM-Architektur...${NC}" INSTALL_MODE="development"
IS_RASPBERRY_PI=true log "🔧 Entwicklungs-Installation gewählt"
else
IS_RASPBERRY_PI=false
fi
# Aktualisiere Paketindex
if ! sudo apt-get update; then
error_log "Konnte Paketindex nicht aktualisieren. Bitte manuell installieren."
exit 1
fi
# Installiere erforderliche Pakete
if ! sudo apt-get install -y apt-transport-https ca-certificates curl gnupg software-properties-common; then
error_log "Konnte erforderliche Pakete nicht installieren. Bitte manuell installieren."
exit 1
fi
# Raspberry Pi-spezifische Installation
if [ "$IS_RASPBERRY_PI" = true ]; then
# Setze Systemarchitektur für Raspberry Pi (armhf oder arm64)
ARCH=$(dpkg --print-architecture)
log "Erkannte Systemarchitektur: ${ARCH}"
# Installiere Docker mit convenience script (für Raspberry Pi empfohlen)
log "${YELLOW}Installiere Docker mit dem convenience script...${NC}"
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
if [ $? -ne 0 ]; then
error_log "Docker-Installation fehlgeschlagen. Bitte manuell installieren."
exit 1
fi
else
# Standard-Installation für andere Systeme
# Füge Docker's offiziellen GPG-Schlüssel hinzu
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
# Füge Docker-Repository hinzu
if ! sudo add-apt-repository "deb [arch=$(dpkg --print-architecture)] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"; then
error_log "Konnte Docker-Repository nicht hinzufügen. Prüfen Sie, ob Ihr System unterstützt wird."
exit 1
fi
# Aktualisiere Paketindex erneut
sudo apt-get update
# Installiere Docker
if ! sudo apt-get install -y docker-ce docker-ce-cli containerd.io; then
error_log "Konnte Docker nicht installieren. Bitte manuell installieren."
exit 1
fi
fi
# Füge aktuellen Benutzer zur Docker-Gruppe hinzu
sudo usermod -aG docker "$USER"
log "${GREEN}Docker wurde installiert.${NC}"
log "${YELLOW}WICHTIG: Möglicherweise müssen Sie sich neu anmelden, damit die Gruppenänderung wirksam wird.${NC}"
# Prüfen, ob Docker Compose v2 Plugin verfügbar ist (bevorzugt, da moderner)
log "${YELLOW}Prüfe Docker Compose Version...${NC}"
if docker compose version &> /dev/null; then
log "${GREEN}Docker Compose v2 Plugin ist bereits installiert.${NC}"
DOCKER_COMPOSE_V2=true
else
log "${YELLOW}Docker Compose v2 Plugin nicht gefunden. Versuche Docker Compose v1 zu installieren...${NC}"
DOCKER_COMPOSE_V2=false
if [ "$IS_RASPBERRY_PI" = true ]; then
# Für Raspberry Pi ist es besser, die richtige Architektur zu verwenden
if [ "$ARCH" = "armhf" ]; then
log "Installiere Docker Compose für armhf (32-bit)..."
sudo curl -L "https://github.com/docker/compose/releases/download/v2.6.1/docker-compose-linux-armv7" -o /usr/local/bin/docker-compose
elif [ "$ARCH" = "arm64" ]; then
log "Installiere Docker Compose für arm64 (64-bit)..."
sudo curl -L "https://github.com/docker/compose/releases/download/v2.6.1/docker-compose-linux-aarch64" -o /usr/local/bin/docker-compose
else
# Fallback auf v1.29.2 für unbekannte ARM-Architekturen
log "Verwende automatische Architekturerkennung für Docker Compose v1.29.2..."
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
fi
else
# Für andere Systeme versuche zuerst v2, dann v1.29.2 als Fallback
log "Installiere Docker Compose v2 für $(uname -s)/$(uname -m)..."
if ! sudo curl -L "https://github.com/docker/compose/releases/download/v2.6.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose; then
log "${YELLOW}Konnte Docker Compose v2 nicht herunterladen. Versuche v1.29.2...${NC}"
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
fi
fi
if [ $? -ne 0 ]; then
error_log "Konnte Docker Compose nicht herunterladen. Bitte manuell installieren."
exit 1
fi
sudo chmod +x /usr/local/bin/docker-compose
log "${GREEN}Docker Compose wurde installiert.${NC}"
fi
# Starte Docker-Dienst
if command -v systemctl &> /dev/null; then
sudo systemctl enable docker
sudo systemctl start docker
elif command -v service &> /dev/null; then
sudo service docker enable
sudo service docker start
fi
}
# Prüfen ob Docker installiert ist
if ! command -v docker &> /dev/null; then
log "${YELLOW}Docker ist nicht installiert.${NC}"
read -p "Möchten Sie Docker installieren? (j/n): " install_docker_choice
if [[ "$install_docker_choice" == "j" ]]; then
install_docker
else
error_log "Docker wird für die Installation benötigt. Bitte installieren Sie Docker manuell."
log "Siehe: https://docs.docker.com/get-docker/"
exit 1
fi
fi
# Prüfen ob Docker Daemon läuft
if ! docker info &> /dev/null; then
log "${YELLOW}Docker-Daemon läuft nicht. Versuche, den Dienst zu starten...${NC}"
# Versuche, Docker zu starten
if command -v systemctl &> /dev/null; then
sudo systemctl start docker
elif command -v service &> /dev/null; then
sudo service docker start
else
error_log "Konnte Docker-Daemon nicht starten. Bitte starten Sie den Docker-Dienst manuell."
log "Starten mit: sudo systemctl start docker oder sudo service docker start"
exit 1
fi
# Prüfe erneut, ob Docker läuft
if ! docker info &> /dev/null; then
error_log "Docker-Daemon konnte nicht gestartet werden. Bitte starten Sie den Docker-Dienst manuell."
exit 1
fi
log "${GREEN}Docker-Daemon wurde erfolgreich gestartet.${NC}"
fi
# Prüfen ob Docker Compose installiert ist
if docker compose version &> /dev/null; then
log "${GREEN}Docker Compose v2 Plugin ist bereits installiert.${NC}"
DOCKER_COMPOSE_V2=true
elif command -v docker-compose &> /dev/null; then
log "${GREEN}Docker Compose v1 ist bereits installiert.${NC}"
DOCKER_COMPOSE_V2=false
else else
log "${YELLOW}Docker Compose ist nicht installiert.${NC}" echo "Wählen Sie den Installationsmodus:"
DOCKER_COMPOSE_V2=false echo "1) Entwicklung (empfohlen für lokale Tests)"
read -p "Möchten Sie Docker Compose installieren? (j/n): " install_compose_choice echo "2) Produktion (für Server-Deployment)"
if [[ "$install_compose_choice" == "j" ]]; then read -p "Ihre Wahl (1/2): " choice
log "${YELLOW}Installiere Docker Compose...${NC}"
# Prüfe ob das Betriebssystem ARM-basiert ist (z.B. Raspberry Pi) case $choice in
if grep -q "arm" /proc/cpuinfo 2> /dev/null; then 1) INSTALL_MODE="development" ;;
ARCH=$(dpkg --print-architecture 2> /dev/null || echo "unknown") 2) INSTALL_MODE="production" ;;
IS_RASPBERRY_PI=true *) log "Verwende Standard-Entwicklungsmodus" && INSTALL_MODE="development" ;;
else esac
IS_RASPBERRY_PI=false
fi
# Versuche zuerst Docker Compose v2 zu installieren
if [ "$IS_RASPBERRY_PI" = true ]; then
if [ "$ARCH" = "armhf" ]; then
log "Installiere Docker Compose für armhf (32-bit)..."
sudo curl -L "https://github.com/docker/compose/releases/download/v2.6.1/docker-compose-linux-armv7" -o /usr/local/bin/docker-compose
elif [ "$ARCH" = "arm64" ]; then
log "Installiere Docker Compose für arm64 (64-bit)..."
sudo curl -L "https://github.com/docker/compose/releases/download/v2.6.1/docker-compose-linux-aarch64" -o /usr/local/bin/docker-compose
else
log "Verwende automatische Architekturerkennung für Docker Compose v1.29.2..."
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
fi
else
log "Installiere Docker Compose v2 für $(uname -s)/$(uname -m)..."
if ! sudo curl -L "https://github.com/docker/compose/releases/download/v2.6.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose; then
log "${YELLOW}Konnte Docker Compose v2 nicht herunterladen. Versuche v1.29.2...${NC}"
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
fi
fi
if [ $? -ne 0 ]; then
error_log "Konnte Docker Compose nicht herunterladen. Bitte manuell installieren."
exit 1
fi
sudo chmod +x /usr/local/bin/docker-compose
log "${GREEN}Docker Compose wurde installiert.${NC}"
else
error_log "Docker Compose wird für die Installation benötigt. Bitte installieren Sie es manuell."
log "Siehe: https://docs.docker.com/compose/install/"
exit 1
fi
fi fi
# Prüfen ob wget installiert ist (wird für healthcheck verwendet) log "Installationsmodus: $INSTALL_MODE"
if ! command -v wget &> /dev/null; then
error_log "wget ist nicht installiert, wird aber für den Container-Healthcheck benötigt."
log "Installation mit: sudo apt-get install wget"
exit 1
fi
# Wechsle ins Backend-Verzeichnis # Bereinige vorherige Installation
log "Wechsle ins Verzeichnis: $BACKEND_DIR" cleanup_existing_installation() {
cd "$BACKEND_DIR" || { log "🧹 Bereinige vorherige Installation..."
error_log "Konnte nicht ins Verzeichnis $BACKEND_DIR wechseln."
exit 1 # Stoppe laufende Prozesse
if pgrep -f "flask run" > /dev/null; then
log "Stoppe laufende Flask-Prozesse..."
pkill -f "flask run" || true
fi
if pgrep -f "gunicorn" > /dev/null; then
log "Stoppe laufende Gunicorn-Prozesse..."
pkill -f "gunicorn.*wsgi:application" || true
fi
# Entferne alte virtuelle Umgebung
if [ -d "venv" ]; then
log "Entferne alte virtuelle Umgebung..."
rm -rf venv
fi
success_log "Bereinigung abgeschlossen"
} }
# Prüfe ob Dockerfile existiert # System-Dependencies prüfen und installieren
if [ ! -f "Dockerfile" ]; then install_system_dependencies() {
error_log "Dockerfile nicht gefunden in $BACKEND_DIR." log "🔧 Prüfe System-Dependencies..."
exit 1
fi
# Prüfe ob docker-compose.yml existiert # Betriebssystem erkennen
if [ ! -f "docker-compose.yml" ]; then if [ -f /etc/os-release ]; then
error_log "docker-compose.yml nicht gefunden in $BACKEND_DIR." . /etc/os-release
exit 1 OS=$NAME
fi VER=$VERSION_ID
elif type lsb_release >/dev/null 2>&1; then
OS=$(lsb_release -si)
VER=$(lsb_release -sr)
else
OS=$(uname -s)
VER=$(uname -r)
fi
# Erstelle .env-Datei log "Erkanntes System: $OS $VER"
log "${YELLOW}Erstelle .env Datei...${NC}"
cat > .env << EOL # Python 3 prüfen
SECRET_KEY=7445630171969DFAC92C53CEC92E67A9CB2E00B3CB2F if ! command -v python3 &> /dev/null; then
error_log "Python 3 ist nicht installiert!"
log "Installationsanleitung:"
if [[ "$OS" == *"Ubuntu"* ]] || [[ "$OS" == *"Debian"* ]]; then
log "sudo apt update && sudo apt install python3 python3-pip python3-venv"
elif [[ "$OS" == *"CentOS"* ]] || [[ "$OS" == *"Red Hat"* ]]; then
log "sudo yum install python3 python3-pip"
elif [[ "$OS" == *"Alpine"* ]]; then
log "sudo apk add python3 py3-pip"
else
log "Bitte installieren Sie Python 3 manuell für Ihr System"
fi
exit 1
fi
# Python-Version prüfen
PYTHON_VERSION=$(python3 -c "import sys; print('.'.join(map(str, sys.version_info[:2])))")
log "Python-Version: $PYTHON_VERSION"
if python3 -c "import sys; exit(0 if sys.version_info >= (3, 8) else 1)"; then
success_log "Python-Version ist kompatibel (>= 3.8)"
else
error_log "Python-Version ist zu alt! Benötigt wird mindestens Python 3.8"
exit 1
fi
# pip prüfen
if ! command -v pip3 &> /dev/null; then
error_log "pip3 ist nicht installiert!"
log "Installiere pip3..."
if [[ "$OS" == *"Ubuntu"* ]] || [[ "$OS" == *"Debian"* ]]; then
sudo apt install python3-pip
else
error_log "Bitte installieren Sie pip3 manuell"
exit 1
fi
fi
# Weitere notwendige System-Pakete prüfen
if [[ "$OS" == *"Ubuntu"* ]] || [[ "$OS" == *"Debian"* ]]; then
log "Prüfe System-Pakete für Ubuntu/Debian..."
# Prüfe ob build-essential installiert ist (für Compilation von Python-Paketen)
if ! dpkg -l | grep -q build-essential; then
log "Installiere build-essential..."
sudo apt update
sudo apt install -y build-essential python3-dev
fi
# Prüfe curl für Health-Checks
if ! command -v curl &> /dev/null; then
log "Installiere curl..."
sudo apt install -y curl
fi
fi
success_log "System-Dependencies sind verfügbar"
}
# Python virtuelle Umgebung erstellen
create_virtual_environment() {
log "🐍 Erstelle Python virtuelle Umgebung..."
# Erstelle virtuelle Umgebung
python3 -m venv venv
# Aktiviere virtuelle Umgebung
source venv/bin/activate
# Upgrade pip in virtueller Umgebung
log "Aktualisiere pip..."
pip install --upgrade pip
success_log "Virtuelle Umgebung erstellt und aktiviert"
}
# Python-Dependencies installieren
install_python_dependencies() {
log "📦 Installiere Python-Dependencies..."
# Aktiviere virtuelle Umgebung
source venv/bin/activate
# Installiere Requirements
if [ -f "requirements.txt" ]; then
log "Installiere aus requirements.txt..."
pip install -r requirements.txt
else
error_log "requirements.txt nicht gefunden!"
exit 1
fi
# Produktions-spezifische Dependencies
if [ "$INSTALL_MODE" = "production" ]; then
log "Installiere Produktions-Dependencies..."
pip install gunicorn supervisor
fi
success_log "Python-Dependencies installiert"
}
# Konfiguration vorbereiten
prepare_configuration() {
log "⚙️ Bereite Konfiguration vor..."
# Erstelle notwendige Verzeichnisse
mkdir -p instance logs migrations/versions
# Kopiere Beispiel-Umgebungsvariablen falls nicht vorhanden
if [ ! -f "env.backend" ]; then
if [ -f "env.example" ]; then
log "Erstelle env.backend aus Vorlage..."
cp env.example env.backend
else
log "Erstelle Standard env.backend..."
cat > env.backend << EOF
# MYP Backend Konfiguration
FLASK_ENV=$INSTALL_MODE
SECRET_KEY=$(python3 -c "import secrets; print(secrets.token_hex(32))")
DATABASE_PATH=instance/myp.db DATABASE_PATH=instance/myp.db
TAPO_USERNAME=till.tomczak@mercedes-benz.com LOG_LEVEL=INFO
TAPO_PASSWORD=744563017196A JOB_CHECK_INTERVAL=60
PRINTERS={"Printer 1": {"ip": "192.168.0.100"}, "Printer 2": {"ip": "192.168.0.101"}, "Printer 3": {"ip": "192.168.0.102"}, "Printer 4": {"ip": "192.168.0.103"}, "Printer 5": {"ip": "192.168.0.104"}, "Printer 6": {"ip": "192.168.0.106"}} PRINTERS={}
EOL TAPO_USERNAME=
TAPO_PASSWORD=
if [ ! -f ".env" ]; then EOF
error_log "Konnte .env-Datei nicht erstellen. Prüfen Sie die Berechtigungen."
exit 1
fi
log "${GREEN}.env Datei erfolgreich erstellt${NC}"
# Verzeichnisse erstellen
log "Erstelle benötigte Verzeichnisse"
if ! mkdir -p logs; then
error_log "Konnte Verzeichnis 'logs' nicht erstellen. Prüfen Sie die Berechtigungen."
exit 1
fi
if ! mkdir -p instance; then
error_log "Konnte Verzeichnis 'instance' nicht erstellen. Prüfen Sie die Berechtigungen."
exit 1
fi
# Docker-Image bauen und starten
log "${YELLOW}Baue und starte Backend-Container...${NC}"
log "${YELLOW}Dies kann auf einem Raspberry Pi einige Minuten dauern - bitte geduldig sein${NC}"
# Prüfe, ob Docker-Daemon läuft
if ! docker info &>/dev/null; then
log "${YELLOW}Docker-Daemon scheint nicht zu laufen. Versuche zu starten...${NC}"
# Versuche Docker zu starten
if command -v systemctl &>/dev/null; then
sudo systemctl start docker || true
sleep 5
elif command -v service &>/dev/null; then
sudo service docker start || true
sleep 5
fi fi
# Prüfe erneut, ob Docker jetzt läuft warning_log "env.backend wurde erstellt. Bitte anpassen!"
if ! docker info &>/dev/null; then
error_log "Docker-Daemon konnte nicht gestartet werden."
log "Führen Sie vor der Installation bitte folgende Befehle aus:"
log " sudo systemctl start docker"
log " sudo systemctl enable docker"
log "Starten Sie dann das Installationsskript erneut."
exit 1
fi fi
fi
# Docker-Rechte prüfen success_log "Konfiguration vorbereitet"
if ! docker ps &>/dev/null; then }
error_log "Sie haben keine Berechtigung, Docker ohne sudo zu verwenden."
log "Bitte führen Sie folgenden Befehl aus und melden Sie sich danach neu an:"
log " sudo usermod -aG docker $USER"
exit 1
fi
# Prüfen, ob erforderliche Basis-Images lokal verfügbar sind # Datenbank initialisieren
if ! docker image inspect python:3-slim &>/dev/null; then initialize_database() {
log "${YELLOW}Prüfe und setze DNS-Server für Docker...${NC}" log "🗄️ Initialisiere Datenbank..."
# DNS-Einstellungen prüfen und anpassen # Aktiviere virtuelle Umgebung
if [ -f /etc/docker/daemon.json ]; then source venv/bin/activate
log "Bestehende Docker-Konfiguration gefunden."
# Lade Umgebungsvariablen
if [ -f "env.backend" ]; then
export $(cat env.backend | grep -v '^#' | grep -v '^$' | xargs)
fi
# Setze Flask-App
export FLASK_APP=app.py
export FLASK_ENV=$INSTALL_MODE
# Initialisiere Datenbank
python3 -c "
from app import create_app, init_db
app = create_app('$INSTALL_MODE')
with app.app_context():
init_db()
print('✅ Datenbank initialisiert')
"
success_log "Datenbank initialisiert"
}
# Systemd-Service für Produktion erstellen
create_systemd_service() {
if [ "$INSTALL_MODE" = "production" ]; then
log "🔧 Erstelle systemd-Service für Produktion..."
SERVICE_FILE="/etc/systemd/system/myp-backend.service"
sudo tee $SERVICE_FILE > /dev/null << EOF
[Unit]
Description=MYP Backend Flask Application
After=network.target
[Service]
Type=exec
User=$USER
Group=$USER
WorkingDirectory=$SCRIPT_DIR
Environment=PATH=$SCRIPT_DIR/venv/bin
EnvironmentFile=$SCRIPT_DIR/env.backend
ExecStart=$SCRIPT_DIR/venv/bin/gunicorn --bind 0.0.0.0:5000 --workers 4 wsgi:application
ExecReload=/bin/kill -s HUP \$MAINPID
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable myp-backend
success_log "Systemd-Service erstellt: myp-backend.service"
log "Starten mit: sudo systemctl start myp-backend"
log "Status prüfen mit: sudo systemctl status myp-backend"
fi
}
# Hauptinstallation
main() {
cleanup_existing_installation
install_system_dependencies
create_virtual_environment
install_python_dependencies
prepare_configuration
initialize_database
create_systemd_service
echo ""
echo "========================================"
success_log "🎉 Installation erfolgreich abgeschlossen!"
echo "========================================"
echo ""
log "Nächste Schritte:"
echo ""
if [ "$INSTALL_MODE" = "production" ]; then
echo "📋 Produktionsbetrieb:"
echo " 1. Konfiguration prüfen: nano env.backend"
echo " 2. Service starten: sudo systemctl start myp-backend"
echo " 3. Service prüfen: sudo systemctl status myp-backend"
echo " 4. Oder manuell: ./start-production.sh"
else else
log "Erstelle Docker-Konfiguration mit Google DNS..." echo "🔧 Entwicklungsbetrieb:"
sudo mkdir -p /etc/docker echo " 1. Konfiguration prüfen: nano env.backend"
echo '{ echo " 2. Server starten: ./start-backend-server.sh"
"dns": ["8.8.8.8", "8.8.4.4"] echo " 3. Development-Server: ./start-backend-server.sh --development"
}' | sudo tee /etc/docker/daemon.json > /dev/null
# Docker neu starten, damit die Änderungen wirksam werden
if command -v systemctl &>/dev/null; then
sudo systemctl restart docker
sleep 5
elif command -v service &>/dev/null; then
sudo service docker restart
sleep 5
fi
fi fi
# Versuche Image explizit mit anderen Tags herunterzuladen echo ""
log "${YELLOW}Versuche lokal vorhandene Python-Version zu finden...${NC}" echo "📡 Backend wird verfügbar sein unter:"
echo " - API: http://localhost:5000"
echo " - Health-Check: http://localhost:5000/health"
echo " - Test: http://localhost:5000/api/test"
echo ""
}
# Suche nach allen verfügbaren Python-Images # Installation starten
PYTHON_IMAGES=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep "python:") main "$@"
if [ -n "$PYTHON_IMAGES" ]; then
log "Gefundene Python-Images: $PYTHON_IMAGES"
# Verwende das erste gefundene Python-Image
FIRST_PYTHON=$(echo "$PYTHON_IMAGES" | head -n 1)
log "${GREEN}Verwende vorhandenes Python-Image: $FIRST_PYTHON${NC}"
# Aktualisiere den Dockerfile
sed -i "s|FROM python:3-slim|FROM $FIRST_PYTHON|g" Dockerfile
log "Dockerfile aktualisiert, um lokales Image zu verwenden."
else
# Versuche unterschiedliche Python-Versionen
for PYTHON_VERSION in "python:3.11-slim" "python:3.10-slim" "python:3.9-slim" "python:slim" "python:alpine"; do
log "Versuche $PYTHON_VERSION zu laden..."
if docker pull $PYTHON_VERSION; then
log "${GREEN}Erfolgreich $PYTHON_VERSION heruntergeladen${NC}"
# Aktualisiere den Dockerfile
sed -i "s|FROM python:3-slim|FROM $PYTHON_VERSION|g" Dockerfile
log "Dockerfile aktualisiert, um $PYTHON_VERSION zu verwenden."
break
fi
done
fi
fi
# Erhöhe Docker-Timeout für langsame Verbindungen und Raspberry Pi
export DOCKER_CLIENT_TIMEOUT=300
export COMPOSE_HTTP_TIMEOUT=300
# Verwende die richtige Docker Compose Version
if [ "${DOCKER_COMPOSE_V2:-false}" = true ]; then
# Docker Compose V2 Plugin (docker compose)
log "Baue lokales Image..."
if ! docker compose build --no-cache; then
error_log "Docker Compose Build (v2) fehlgeschlagen. Versuche mit v1 Format..."
if ! docker-compose build --no-cache; then
error_log "Docker Compose Build fehlgeschlagen. Siehe Fehlermeldung oben."
exit 1
fi
fi
log "Starte Container aus lokalem Image..."
if ! docker compose up -d; then
error_log "Docker Compose Up (v2) fehlgeschlagen. Versuche mit v1 Format..."
if ! docker-compose up -d; then
error_log "Docker Compose Up fehlgeschlagen. Siehe Fehlermeldung oben."
exit 1
fi
fi
else
# Docker Compose V1 (docker-compose)
log "Baue lokales Image..."
if ! docker-compose build --no-cache; then
error_log "Docker Compose Build fehlgeschlagen. Siehe Fehlermeldung oben."
exit 1
fi
log "Starte Container aus lokalem Image..."
if ! docker-compose up -d; then
error_log "Docker Compose Up fehlgeschlagen. Siehe Fehlermeldung oben."
exit 1
fi
fi
# Prüfe, ob der Container läuft
log "Warte 10 Sekunden, bis der Container gestartet ist..."
sleep 10
if docker ps | grep -q "myp-backend"; then
log "${GREEN}Backend-Container läuft${NC}"
else
error_log "Backend-Container läuft nicht. Container-Status:"
docker ps -a | grep myp-backend
log "Container-Logs:"
docker logs myp-backend
exit 1
fi
# Test API-Endpunkt
log "${YELLOW}Teste Backend-API...${NC}"
log "${YELLOW}HINWEIS: Der API-Server ist bei der ersten Installation oft noch nicht erreichbar${NC}"
log "${YELLOW}Dies ist ein bekanntes Verhalten wegen der Netzwerkkonfiguration${NC}"
log "${YELLOW}Bitte nach der Installation das System neu starten, danach sollte der API-Server erreichbar sein${NC}"
# Wir versuchen es trotzdem einmal, um zu sehen, ob er vielleicht doch läuft
if curl -s http://localhost:5000/health 2>/dev/null | grep -q "healthy"; then
log "${GREEN}Backend-API ist erreichbar und funktioniert${NC}"
else
log "${YELLOW}Backend-API ist wie erwartet noch nicht erreichbar${NC}"
log "${GREEN}Das ist völlig normal bei der Erstinstallation${NC}"
log "${GREEN}Nach einem Neustart des Systems sollte der API-Server korrekt erreichbar sein${NC}"
log "Container-Status prüfen mit: docker logs myp-backend"
fi
# Initialisierung der Datenbank prüfen
log "${YELLOW}Prüfe Datenbank-Initialisierung...${NC}"
if [ ! -s "instance/myp.db" ]; then
log "${YELLOW}Datenbank scheint leer zu sein. Führe Initialisierungsskript aus...${NC}"
DB_INIT_OUTPUT=$(docker exec myp-backend python -c "from app import init_db; init_db()" 2>&1)
if [ $? -eq 0 ]; then
log "${GREEN}Datenbank erfolgreich initialisiert${NC}"
else
error_log "Fehler bei der Datenbank-Initialisierung:"
echo "$DB_INIT_OUTPUT"
log "Container-Logs:"
docker logs myp-backend
fi
else
log "${GREEN}Datenbank existiert bereits${NC}"
fi
# Teste, ob ein API-Endpunkt Daten zurückgibt
log "${YELLOW}Teste Datenbank-Verbindung über API...${NC}"
if curl -s http://localhost:5000/api/printers | grep -q "\[\]"; then
log "${GREEN}Datenbank-Verbindung funktioniert${NC}"
else
log "${YELLOW}API gibt keine leere Drucker-Liste zurück. Möglicherweise ist die DB nicht korrekt initialisiert.${NC}"
log "API-Antwort:"
curl -s http://localhost:5000/api/printers
fi
log "${GREEN}=== Installation abgeschlossen ===${NC}"
log "${YELLOW}WICHTIG: Nach der Erstinstallation ist ein Systemneustart erforderlich${NC}"
log "${YELLOW}Danach ist das Backend unter http://localhost:5000 erreichbar${NC}"
log "Anzeigen der Logs: docker logs -f myp-backend"
# Verwende die richtige Docker Compose Version für Hinweis
if [ "${DOCKER_COMPOSE_V2:-false}" = true ]; then
log "Backend stoppen: docker compose -f $BACKEND_DIR/docker-compose.yml down"
else
log "Backend stoppen: docker-compose -f $BACKEND_DIR/docker-compose.yml down"
fi

View File

@ -0,0 +1 @@

View File

@ -1 +1,287 @@
# 🏗️ MYP - Separate Server Architektur
## Übersicht
Das MYP-System wurde in **zwei vollständig unabhängige Server** aufgeteilt:
- **🏭 Backend-Server** (Port 5000): Flask-API für Geschäftslogik und Datenmanagement
- **🎨 Frontend-Server** (Port 3000): Next.js-Anwendung für Benutzeroberfläche
## 🔗 Server-Kommunikation
```
┌─────────────────┐ HTTP/API ┌─────────────────┐
│ Frontend │◄───────────────►│ Backend │
│ (Next.js) │ │ (Flask) │
│ Port: 3000 │ │ Port: 5000 │
└─────────────────┘ └─────────────────┘
```
## 🚀 Separate Server starten
### Backend-Server (unabhängig)
```bash
cd backend
./start-backend-server.sh
# Alternative mit Logs
./start-backend-server.sh --logs
# Vollständige Neuinstallation
./start-backend-server.sh --clean
```
**Backend verfügbar unter:**
- 📡 Backend-API: http://localhost:5000
- 🔧 Health-Check: http://localhost:5000/health
- 📋 API-Docs: http://localhost:5000/swagger
### Frontend-Server (unabhängig)
```bash
cd frontend
./start-frontend-server.sh
# Alternative mit Logs
./start-frontend-server.sh --logs
# Vollständige Neuinstallation
./start-frontend-server.sh --clean
```
**Frontend verfügbar unter:**
- 🌐 Web-App: http://localhost:3000
- 🔧 Health-Check: http://localhost:3000/health
- 📦 CDN-Assets: http://localhost:8080
## ⚙️ Konfiguration
### Backend-Konfiguration
**Datei:** `backend/env.backend`
```bash
# Backend-Server
PORT=5000
BACKEND_URL=http://localhost:5000
# CORS für Frontend-Zugriff
CORS_ORIGINS=http://localhost:3000,https://frontend.myp.local
# Datenbank
DATABASE_PATH=instance/myp.db
# Cache
REDIS_HOST=localhost
REDIS_PORT=6379
```
### Frontend-Konfiguration
**Datei:** `frontend/env.frontend`
```bash
# Frontend-Server
PORT=3000
FRONTEND_URL=http://localhost:3000
# Backend-API Verbindung
BACKEND_API_URL=http://localhost:5000/api
NEXT_PUBLIC_API_URL=http://localhost:5000/api
# Cache
FRONTEND_REDIS_PORT=6380
```
## 🐋 Docker-Container
### Backend-Container
```bash
cd backend
docker-compose -f docker-compose.backend.yml up -d
# Services:
# - myp-backend-standalone (Port 5000)
# - myp-backend-db (PostgreSQL, Port 5432)
# - myp-backend-cache (Redis, Port 6379)
```
### Frontend-Container
```bash
cd frontend
docker-compose -f docker-compose.frontend.yml up -d
# Services:
# - myp-frontend-standalone (Port 3000)
# - myp-frontend-cache (Redis, Port 6380)
# - myp-frontend-cdn (Nginx, Port 8080)
```
## 🔒 Sicherheit
### CORS-Konfiguration
Das Backend ist für **explizite Frontend-Origins** konfiguriert:
```python
# Backend: app.py
CORS(app,
origins=['http://localhost:3000', 'https://frontend.myp.local'],
supports_credentials=True,
allow_headers=['Content-Type', 'Authorization', 'X-Requested-With'],
methods=['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'])
```
### API-Authentifizierung
- **JWT-Tokens** für API-Zugriff
- **Session-basierte** Authentifizierung für Web-UI
- **Separate Secrets** für Frontend und Backend
## 📊 Monitoring
### Health-Checks
**Backend:** GET http://localhost:5000/health
```json
{
"status": "healthy",
"service": "myp-backend",
"database": "connected",
"timestamp": "2024-01-15T10:30:00Z"
}
```
**Frontend:** GET http://localhost:3000/health
```json
{
"status": "healthy",
"service": "myp-frontend",
"backend": {
"url": "http://localhost:5000",
"status": "connected"
},
"timestamp": "2024-01-15T10:30:00Z"
}
```
### Logs verfolgen
```bash
# Backend-Logs
cd backend
docker-compose -f docker-compose.backend.yml logs -f
# Frontend-Logs
cd frontend
docker-compose -f docker-compose.frontend.yml logs -f
```
## 🔧 Troubleshooting
### Backend startet nicht
```bash
# 1. Prüfe Ports
netstat -an | grep 5000
# 2. Prüfe Backend-Logs
cd backend
docker-compose -f docker-compose.backend.yml logs backend
# 3. Datenbank-Migration
docker-compose -f docker-compose.backend.yml exec backend flask db upgrade
```
### Frontend kann Backend nicht erreichen
```bash
# 1. Prüfe Backend-Verfügbarkeit
curl http://localhost:5000/health
# 2. Prüfe CORS-Konfiguration
curl -H "Origin: http://localhost:3000" \
-H "Access-Control-Request-Method: GET" \
-H "Access-Control-Request-Headers: Content-Type" \
-X OPTIONS http://localhost:5000/api/printers
# 3. Prüfe Frontend-Umgebungsvariablen
cd frontend
grep BACKEND env.frontend
```
### Port-Konflikte
```bash
# Standard-Ports ändern
# Backend: PORT=5001 in env.backend
# Frontend: PORT=3001 in env.frontend
# Neue URLs in beiden Konfigurationen anpassen
```
## 🌐 Deployment
### Produktions-Deployment
```bash
# Backend (Server 1)
cd backend
FLASK_ENV=production ./start-backend-server.sh
# Frontend (Server 2)
cd frontend
NODE_ENV=production BACKEND_API_URL=https://api.myp.de ./start-frontend-server.sh
```
### Reverse Proxy (Optional)
Für Produktion können beide Server hinter einem Reverse Proxy laufen:
```
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Client │────►│ Nginx/Caddy │────►│ Frontend │
│ │ │ │ ┌─►│ :3000 │
└─────────────┘ │ /api/* ─────┤──┘ └─────────────┘
│ │ ┌─►┌─────────────┐
│ /api/* ─────┤──┘ │ Backend │
└─────────────┘ │ :5000 │
└─────────────┘
```
## 📁 Dateistruktur
```
Projektarbeit-MYP/
├── backend/ # 🏭 Backend-Server
│ ├── docker-compose.backend.yml # Docker-Konfiguration
│ ├── start-backend-server.sh # Start-Skript
│ ├── env.backend # Umgebungsvariablen
│ └── app.py # Flask-Anwendung
├── frontend/ # 🎨 Frontend-Server
│ ├── docker-compose.frontend.yml # Docker-Konfiguration
│ ├── start-frontend-server.sh # Start-Skript
│ ├── env.frontend # Umgebungsvariablen
│ └── src/ # Next.js-Anwendung
└── SEPARATE_SERVERS_GUIDE.md # Diese Dokumentation
```
## ✅ Vorteile der Trennung
1. **🔄 Unabhängige Skalierung** - Frontend und Backend können getrennt skaliert werden
2. **🚀 Separate Deployments** - Updates können unabhängig deployed werden
3. **🛡️ Verbesserte Sicherheit** - Klare API-Grenzen und CORS-Kontrolle
4. **🔧 Technologie-Flexibilität** - Frontend und Backend können verschiedene Technologien verwenden
5. **📊 Besseres Monitoring** - Separate Health-Checks und Logs
6. **🏗️ Microservice-Ready** - Vorbereitung für Microservice-Architektur
---
**Hinweis:** Die alte gekoppelte Konfiguration ist weiterhin in `docker-compose.yml` verfügbar, wird aber für neue Deployments nicht empfohlen.