multiple corrections on docker-compose and Dockerfile
robust start sequence avoid scrolling of main content
This commit is contained in:
@@ -1,39 +1,52 @@
|
|||||||
# ==========================================
|
# ==========================================
|
||||||
# dashboard/Dockerfile (Production)
|
# dashboard/Dockerfile (Production)
|
||||||
|
# 🔧 OPTIMIERT: Multi-Stage-Build für ein minimales Produktions-Image
|
||||||
# ==========================================
|
# ==========================================
|
||||||
FROM node:lts-alpine AS builder
|
|
||||||
|
# Stage 1: Build-Umgebung
|
||||||
|
FROM node:20-alpine AS build
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Copy package files
|
# Kopiere package.json und pnpm-lock.yaml
|
||||||
COPY package*.json ./
|
COPY package.json pnpm-lock.yaml ./
|
||||||
COPY pnpm-lock.yaml* ./
|
|
||||||
|
|
||||||
# Install pnpm and dependencies
|
# Installiere pnpm und dann die Abhängigkeiten
|
||||||
RUN npm install -g pnpm
|
# --prod stellt sicher, dass nur Produktions-Abhängigkeiten installiert werden
|
||||||
RUN pnpm install --frozen-lockfile
|
RUN npm install -g pnpm && pnpm install --prod --frozen-lockfile
|
||||||
|
|
||||||
# Copy source code
|
# Kopiere den restlichen Quellcode
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# Build arguments
|
# Setze Build-Argumente als Umgebungsvariablen
|
||||||
ARG NODE_ENV=production
|
|
||||||
ARG VITE_API_URL
|
ARG VITE_API_URL
|
||||||
|
ENV VITE_API_URL=${VITE_API_URL}
|
||||||
|
|
||||||
# Build the application
|
# Baue die Anwendung für die Produktion
|
||||||
RUN pnpm build
|
RUN pnpm build
|
||||||
|
|
||||||
# Production stage with nginx
|
# Stage 2: Produktions-Umgebung
|
||||||
FROM nginx:alpine
|
FROM nginx:1.25-alpine
|
||||||
|
|
||||||
# Copy built files to nginx
|
# Kopiere die gebauten statischen Dateien aus der Build-Stage
|
||||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
COPY --from=build /app/dist /usr/share/nginx/html
|
||||||
|
|
||||||
# Copy custom nginx config (optional)
|
# Optional: Eine Nginx-Konfiguration für Single-Page-Applications (SPA)
|
||||||
COPY nginx.conf /etc/nginx/nginx.conf
|
# Diese leitet alle Anfragen, die keine Dateien sind, auf die index.html um.
|
||||||
|
# Erstelle eine Datei `nginx.prod.conf` mit folgendem Inhalt:
|
||||||
|
# server {
|
||||||
|
# listen 80;
|
||||||
|
# root /usr/share/nginx/html;
|
||||||
|
# index index.html;
|
||||||
|
# location / {
|
||||||
|
# try_files $uri $uri/ /index.html;
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# COPY nginx.prod.conf /etc/nginx/conf.d/default.conf
|
||||||
|
|
||||||
# Expose port
|
# Exponiere Port 80 (Standard-HTTP-Port von Nginx)
|
||||||
EXPOSE 3000
|
EXPOSE 80
|
||||||
|
|
||||||
# Start nginx
|
# Starte Nginx
|
||||||
CMD ["nginx", "-g", "daemon off;"]
|
CMD ["nginx", "-g", "daemon off;"]
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +1,36 @@
|
|||||||
# ==========================================
|
# ==========================================
|
||||||
# dashboard/Dockerfile.dev (Development)
|
# dashboard/Dockerfile.dev (Development)
|
||||||
|
# 🔧 OPTIMIERT: Für schnelle Entwicklung mit Vite und pnpm
|
||||||
# ==========================================
|
# ==========================================
|
||||||
FROM node:lts-alpine
|
FROM node:20-alpine
|
||||||
|
|
||||||
|
# Setze das Arbeitsverzeichnis auf den Workspace-Root, um die Pfade aus
|
||||||
|
# docker-compose.override.yml korrekt aufzulösen.
|
||||||
|
WORKDIR /workspace
|
||||||
|
|
||||||
|
# 🔧 HINZUGEFÜGT: Installiere curl, damit das wait-for-backend.sh Skript funktioniert
|
||||||
|
RUN apk add --no-cache curl
|
||||||
|
|
||||||
|
# Installiere pnpm, da es im Projekt verwendet wird.
|
||||||
|
RUN npm install -g pnpm
|
||||||
|
|
||||||
|
# Kopiere die package-Dateien in das korrekte Unterverzeichnis.
|
||||||
|
# Dies nutzt den Docker-Cache: Wenn sich die Dateien nicht ändern,
|
||||||
|
# wird der `pnpm install`-Schritt übersprungen.
|
||||||
|
COPY package.json pnpm-lock.yaml* ./
|
||||||
|
|
||||||
|
# Wechsle in das Dashboard-Verzeichnis, um die Befehle auszuführen.
|
||||||
WORKDIR /workspace/dashboard
|
WORKDIR /workspace/dashboard
|
||||||
|
|
||||||
# Install dependencies manager (pnpm optional, npm reicht für Compose-Setup)
|
# Installiere ALLE Abhängigkeiten (inkl. devDependencies)
|
||||||
# RUN npm install -g pnpm
|
RUN pnpm install
|
||||||
|
|
||||||
# Copy package files
|
# Das Kopieren des restlichen Codes ist nicht nötig, da das gesamte
|
||||||
COPY package*.json ./
|
# Verzeichnis `./:/workspace` in der docker-compose.override.yml gemountet wird.
|
||||||
|
|
||||||
# Install dependencies (nutze npm, da Compose "npm run dev" nutzt)
|
# Exponiere die Ports für Vite und Node-Debugging
|
||||||
RUN npm install
|
EXPOSE 5173 9229
|
||||||
|
|
||||||
# Copy source code
|
# Der Startbefehl wird in der docker-compose.override.yml definiert.
|
||||||
COPY . .
|
# Ein Standard-CMD ist dennoch eine gute Praxis.
|
||||||
|
CMD ["pnpm", "run", "dev", "--", "--host", "0.0.0.0", "--port", "5173"]
|
||||||
# Expose ports
|
|
||||||
EXPOSE 3000 9229
|
|
||||||
|
|
||||||
# Standard-Dev-Command (wird von Compose überschrieben)
|
|
||||||
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0", "--port", "3000"]
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --host 0.0.0.0 --port 3000",
|
"dev": "vite",
|
||||||
"build": "tsc -b && vite build",
|
"build": "tsc -b && vite build",
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: Inter, 'Segoe UI', Roboto, Arial, sans-serif;
|
font-family: Inter, 'Segoe UI', Roboto, Arial, sans-serif;
|
||||||
|
overflow: hidden; /* Verhindert den Scrollbalken auf der obersten Ebene */
|
||||||
}
|
}
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
@@ -28,6 +29,7 @@ body {
|
|||||||
/* Layout-Container für Sidebar und Content */
|
/* Layout-Container für Sidebar und Content */
|
||||||
.layout-container {
|
.layout-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
position: relative; /* Wichtig für die absolute Positionierung des Inhalts */
|
||||||
height: 100vh; /* Feste Höhe auf die des Viewports setzen */
|
height: 100vh; /* Feste Höhe auf die des Viewports setzen */
|
||||||
overflow: hidden; /* Verhindert, dass der Scrollbalken den gesamten Container betrifft */
|
overflow: hidden; /* Verhindert, dass der Scrollbalken den gesamten Container betrifft */
|
||||||
}
|
}
|
||||||
@@ -40,6 +42,7 @@ body {
|
|||||||
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif;
|
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
z-index: 10; /* Stellt sicher, dass die Sidebar über dem Inhalt ist */
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-theme .sidebar-link {
|
.sidebar-theme .sidebar-link {
|
||||||
@@ -73,16 +76,36 @@ body {
|
|||||||
color: var(--sidebar-bg);
|
color: var(--sidebar-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* === START: ROBUSTES ABSOLUTE-POSITIONING-LAYOUT === */
|
||||||
|
|
||||||
/* Nur der Page-Content bekommt den horizontalen Scrollbalken */
|
/* Der Inhaltsbereich wird absolut positioniert, um den Rest des Bildschirms auszufüllen */
|
||||||
.page-content-scroll {
|
.content-area {
|
||||||
flex: 1 1 auto;
|
position: absolute;
|
||||||
overflow-x: auto;
|
inset: 0 0 0 16rem; /* Shorthand für top, right, bottom, left */
|
||||||
padding: 16px; /* Optional: Abstand innerhalb des Contents */
|
display: flex;
|
||||||
height: 100%;
|
flex-direction: column;
|
||||||
box-sizing: border-box; /* Padding wird in die Breite/Höhe einbezogen */
|
transition: inset-inline-start 0.3s ease-in-out; /* Animiert die 'left' Eigenschaft */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Anpassung für die eingeklappte Sidebar */
|
||||||
|
.content-area.collapsed {
|
||||||
|
left: 5rem; /* Breite der eingeklappten Sidebar (w-20) */
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-header {
|
||||||
|
flex-shrink: 0; /* Header soll nicht schrumpfen */
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-content {
|
||||||
|
flex-grow: 1; /* Füllt den verbleibenden Platz */
|
||||||
|
overflow-y: auto; /* NUR dieser Bereich scrollt */
|
||||||
|
padding: 2rem;
|
||||||
|
background-color: #f3f4f6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* === ENDE: ROBUSTES ABSOLUTE-POSITIONING-LAYOUT === */
|
||||||
|
|
||||||
|
|
||||||
/* Kanban-Karten im Sidebar-Style */
|
/* Kanban-Karten im Sidebar-Style */
|
||||||
.e-kanban .e-card,
|
.e-kanban .e-card,
|
||||||
.e-kanban .e-card .e-card-content,
|
.e-kanban .e-card .e-card-content,
|
||||||
|
|||||||
@@ -116,10 +116,10 @@ const Layout: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
{/* Main Content */}
|
{/* Main Content */}
|
||||||
<div className="flex-1 flex flex-col">
|
<div className={`content-area ${collapsed ? 'collapsed' : ''}`}>
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<header
|
<header
|
||||||
className="flex items-center px-8 shadow"
|
className="content-header flex items-center px-8 shadow"
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: '#e5d8c7',
|
backgroundColor: '#e5d8c7',
|
||||||
color: '#78591c',
|
color: '#78591c',
|
||||||
@@ -140,7 +140,7 @@ const Layout: React.FC = () => {
|
|||||||
[Organisationsname]
|
[Organisationsname]
|
||||||
</span>
|
</span>
|
||||||
</header>
|
</header>
|
||||||
<main className="flex-1 p-8 bg-gray-100 page-content-scroll">
|
<main className="page-content">
|
||||||
<Outlet />
|
<Outlet />
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -139,6 +139,7 @@ const Programminfo: React.FC = () => {
|
|||||||
<div>
|
<div>
|
||||||
<h3 className="text-xl font-semibold mb-4">Verwendete Open-Source-Komponenten</h3>
|
<h3 className="text-xl font-semibold mb-4">Verwendete Open-Source-Komponenten</h3>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
|
||||||
|
{info.openSourceComponents.frontend && (
|
||||||
<div className="bg-white p-6 rounded-lg shadow">
|
<div className="bg-white p-6 rounded-lg shadow">
|
||||||
<h4 className="font-bold mb-3">Frontend</h4>
|
<h4 className="font-bold mb-3">Frontend</h4>
|
||||||
<ul className="list-disc list-inside space-y-1">
|
<ul className="list-disc list-inside space-y-1">
|
||||||
@@ -149,6 +150,8 @@ const Programminfo: React.FC = () => {
|
|||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
{info.openSourceComponents.backend && (
|
||||||
<div className="bg-white p-6 rounded-lg shadow">
|
<div className="bg-white p-6 rounded-lg shadow">
|
||||||
<h4 className="font-bold mb-3">Backend</h4>
|
<h4 className="font-bold mb-3">Backend</h4>
|
||||||
<ul className="list-disc list-inside space-y-1">
|
<ul className="list-disc list-inside space-y-1">
|
||||||
@@ -159,6 +162,7 @@ const Programminfo: React.FC = () => {
|
|||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,9 +5,16 @@ import react from '@vitejs/plugin-react';
|
|||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [react()],
|
plugins: [react()],
|
||||||
server: {
|
server: {
|
||||||
|
host: '0.0.0.0',
|
||||||
|
watch: {
|
||||||
|
usePolling: true,
|
||||||
|
},
|
||||||
|
fs: {
|
||||||
|
strict: false,
|
||||||
|
},
|
||||||
proxy: {
|
proxy: {
|
||||||
'/api': 'http://localhost:8000',
|
'/api': 'http://server:8000',
|
||||||
'/screenshots': 'http://localhost:8000',
|
'/screenshots': 'http://server:8000',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
24
dashboard/wait-for-backend.sh
Executable file
24
dashboard/wait-for-backend.sh
Executable file
@@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# wait-for-backend.sh
|
||||||
|
|
||||||
|
# Stellt sicher, dass das Skript bei einem Fehler abbricht
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Der erste Parameter ist der Host, der erreicht werden soll
|
||||||
|
host="$1"
|
||||||
|
# Alle weiteren Parameter bilden den Befehl, der danach ausgeführt werden soll
|
||||||
|
shift
|
||||||
|
cmd="$@"
|
||||||
|
|
||||||
|
# Schleife, die so lange läuft, bis der Host mit einem erfolgreichen HTTP-Status antwortet
|
||||||
|
# curl -s: silent mode (kein Fortschrittsbalken)
|
||||||
|
# curl -f: fail silently (gibt einen Fehlercode > 0 zurück, wenn der HTTP-Status nicht 2xx ist)
|
||||||
|
until curl -s -f "$host" > /dev/null; do
|
||||||
|
>&2 echo "Backend ist noch nicht erreichbar - schlafe für 2 Sekunden"
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
|
||||||
|
# Wenn die Schleife beendet ist, ist das Backend erreichbar
|
||||||
|
>&2 echo "Backend ist erreichbar - starte Vite-Server..."
|
||||||
|
# Führe den eigentlichen Befehl aus (z.B. npm run dev)
|
||||||
|
exec $cmd
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
networks:
|
networks:
|
||||||
infoscreen-net:
|
infoscreen-net:
|
||||||
driver: bridge
|
driver: bridge
|
||||||
@@ -18,19 +17,19 @@ services:
|
|||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
environment:
|
environment:
|
||||||
- DB_URL=mysql+pymysql://${DB_USER}:${DB_PASSWORD}@db/${DB_NAME}
|
- DB_URL=mysql+pymysql://${DB_USER}:${DB_PASSWORD}@db/${DB_NAME}
|
||||||
volumes:
|
# 🔧 ENTFERNT: Volume-Mount ist nur für die Entwicklung
|
||||||
- ./listener:/app:rw
|
|
||||||
networks:
|
networks:
|
||||||
- infoscreen-net
|
- infoscreen-net
|
||||||
|
|
||||||
proxy:
|
proxy:
|
||||||
image: nginx:stable
|
image: nginx:1.25 # 🔧 GEÄNDERT: Spezifische Version
|
||||||
container_name: infoscreen-proxy
|
container_name: infoscreen-proxy
|
||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "80:80"
|
||||||
- "443:443"
|
- "443:443"
|
||||||
volumes:
|
volumes:
|
||||||
- ${PWD}/nginx.conf:/etc/nginx/nginx.conf:ro
|
- ./nginx.conf:/etc/nginx/nginx.conf:ro # 🔧 GEÄNDERT: Relativer Pfad
|
||||||
- ${PWD}/certs:/etc/nginx/certs:ro
|
- ./certs:/etc/nginx/certs:ro # 🔧 GEÄNDERT: Relativer Pfad
|
||||||
depends_on:
|
depends_on:
|
||||||
- server
|
- server
|
||||||
- dashboard
|
- dashboard
|
||||||
@@ -38,7 +37,7 @@ services:
|
|||||||
- infoscreen-net
|
- infoscreen-net
|
||||||
|
|
||||||
db:
|
db:
|
||||||
image: mariadb:lts
|
image: mariadb:11.2 # 🔧 GEÄNDERT: Spezifische Version
|
||||||
container_name: infoscreen-db
|
container_name: infoscreen-db
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
@@ -60,7 +59,7 @@ services:
|
|||||||
start_period: 30s
|
start_period: 30s
|
||||||
|
|
||||||
mqtt:
|
mqtt:
|
||||||
image: eclipse-mosquitto:2.0.21
|
image: eclipse-mosquitto:2.0.21 # ✅ GUT: Version ist bereits spezifisch
|
||||||
container_name: infoscreen-mqtt
|
container_name: infoscreen-mqtt
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
volumes:
|
volumes:
|
||||||
@@ -114,9 +113,8 @@ services:
|
|||||||
build:
|
build:
|
||||||
context: ./dashboard
|
context: ./dashboard
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
# ✅ HINZUGEFÜGT: Build-Args für React Production Build
|
# 🔧 VEREINFACHT: Build-Args werden durch Umgebungsvariablen gesetzt
|
||||||
args:
|
args:
|
||||||
- NODE_ENV=production
|
|
||||||
- VITE_API_URL=${API_URL}
|
- VITE_API_URL=${API_URL}
|
||||||
image: infoscreen-dashboard:latest
|
image: infoscreen-dashboard:latest
|
||||||
container_name: infoscreen-dashboard
|
container_name: infoscreen-dashboard
|
||||||
@@ -125,20 +123,20 @@ services:
|
|||||||
server:
|
server:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
environment:
|
environment:
|
||||||
# ✅ GEÄNDERT: React-spezifische Umgebungsvariablen
|
|
||||||
- VITE_API_URL=${API_URL}
|
|
||||||
- NODE_ENV=production
|
- NODE_ENV=production
|
||||||
ports:
|
- VITE_API_URL=${API_URL}
|
||||||
- "3000:3000" # ✅ GEÄNDERT: Standard React/Vite Port
|
# 🔧 ENTFERNT: Port wird in Produktion nicht direkt freigegeben, Zugriff via Proxy
|
||||||
networks:
|
networks:
|
||||||
- infoscreen-net
|
- infoscreen-net
|
||||||
# ✅ GEÄNDERT: Healthcheck für React App
|
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "curl", "-f", "http://localhost:3000/"]
|
# 🔧 GEÄNDERT: Healthcheck prüft den Nginx-Server im Container
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost/"]
|
||||||
interval: 30s
|
interval: 30s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 3
|
retries: 3
|
||||||
start_period: 30s
|
# 🔧 ERHÖHT: Gibt dem Backend mehr Zeit zum Starten, bevor dieser
|
||||||
|
# Container als "gesund" markiert wird.
|
||||||
|
start_period: 60s
|
||||||
|
|
||||||
scheduler:
|
scheduler:
|
||||||
build:
|
build:
|
||||||
|
|||||||
@@ -1,16 +1,33 @@
|
|||||||
# server/Dockerfile
|
# server/Dockerfile
|
||||||
# Produktions-Dockerfile für die Flask-API mit Gunicorn
|
# 🔧 OPTIMIERT: Multi-Stage-Build für ein minimales und sicheres Produktions-Image
|
||||||
|
|
||||||
# --- Basisimage ---
|
# Stage 1: Builder - Installiert Abhängigkeiten
|
||||||
|
FROM python:3.13-slim AS builder
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Installiert nur die für den Build notwendigen Systemabhängigkeiten
|
||||||
|
RUN apt-get update \
|
||||||
|
&& apt-get install -y --no-install-recommends \
|
||||||
|
libmariadb-dev-compat libmariadb-dev gcc \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Kopiert nur die requirements.txt, um den Docker-Cache optimal zu nutzen
|
||||||
|
COPY requirements.txt .
|
||||||
|
|
||||||
|
# Installiert die Python-Pakete in ein separates Verzeichnis
|
||||||
|
RUN pip install --no-cache-dir --prefix="/install" -r requirements.txt
|
||||||
|
|
||||||
|
# Stage 2: Final - Das eigentliche Produktions-Image
|
||||||
FROM python:3.13-slim
|
FROM python:3.13-slim
|
||||||
|
|
||||||
# --- Arbeitsverzeichnis ---
|
# --- Arbeitsverzeichnis ---
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# --- Systemabhängigkeiten für MariaDB-Client & Locale ---
|
# Installiert nur die für die Laufzeit notwendigen Systemabhängigkeiten
|
||||||
RUN apt-get update \
|
RUN apt-get update \
|
||||||
&& apt-get install -y --no-install-recommends \
|
&& apt-get install -y --no-install-recommends \
|
||||||
libmariadb-dev-compat libmariadb-dev locales git\
|
libmariadb-dev-compat locales \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# --- Locale konfigurieren ---
|
# --- Locale konfigurieren ---
|
||||||
@@ -19,12 +36,12 @@ RUN sed -i 's/# de_DE.UTF-8 UTF-8/de_DE.UTF-8 UTF-8/' /etc/locale.gen \
|
|||||||
ENV LANG=de_DE.UTF-8 \
|
ENV LANG=de_DE.UTF-8 \
|
||||||
LC_ALL=de_DE.UTF-8
|
LC_ALL=de_DE.UTF-8
|
||||||
|
|
||||||
# --- Python-Abhängigkeiten ---
|
# Kopiert die installierten Pakete aus der Builder-Stage
|
||||||
COPY requirements.txt .
|
COPY --from=builder /install /usr/local
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
|
||||||
|
|
||||||
# --- Applikationscode ---
|
# --- Applikationscode ---
|
||||||
COPY server/ /app
|
# Kopiert den Server-Code in das Arbeitsverzeichnis
|
||||||
|
COPY server/ .
|
||||||
|
|
||||||
# --- Non-Root User anlegen und Rechte setzen ---
|
# --- Non-Root User anlegen und Rechte setzen ---
|
||||||
ARG USER_ID=1000
|
ARG USER_ID=1000
|
||||||
@@ -40,3 +57,4 @@ EXPOSE 8000
|
|||||||
|
|
||||||
# --- Startbefehl für Gunicorn ---
|
# --- Startbefehl für Gunicorn ---
|
||||||
CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:8000", "wsgi:app"]
|
CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:8000", "wsgi:app"]
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
# Datei: server/Dockerfile.dev
|
# Datei: server/Dockerfile.dev
|
||||||
# Entwicklungs-Dockerfile für die API (Flask + SQLAlchemy)
|
# 🔧 OPTIMIERT: Für die Entwicklung im Dev-Container
|
||||||
|
# ==========================================
|
||||||
|
|
||||||
FROM python:3.13-slim
|
FROM python:3.13-slim
|
||||||
|
|
||||||
# Build args für UID/GID
|
# Die Erstellung des non-root Users und die Locale-Konfiguration
|
||||||
|
# sind für den Dev-Container nicht zwingend nötig, da VS Code sich als 'root'
|
||||||
|
# verbindet (gemäß devcontainer.json). Sie schaden aber nicht.
|
||||||
ARG USER_ID=1000
|
ARG USER_ID=1000
|
||||||
ARG GROUP_ID=1000
|
ARG GROUP_ID=1000
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends locales curl git \
|
||||||
# Erstelle non-root User
|
|
||||||
RUN apt-get update \
|
|
||||||
&& apt-get install -y --no-install-recommends locales curl \
|
|
||||||
&& groupadd -g ${GROUP_ID} infoscreen_taa \
|
&& groupadd -g ${GROUP_ID} infoscreen_taa \
|
||||||
&& useradd -u ${USER_ID} -g ${GROUP_ID} --shell /bin/bash --create-home infoscreen_taa \
|
&& useradd -u ${USER_ID} -g ${GROUP_ID} --shell /bin/bash --create-home infoscreen_taa \
|
||||||
&& sed -i 's/# de_DE.UTF-8 UTF-8/de_DE.UTF-8 UTF-8/' /etc/locale.gen \
|
&& sed -i 's/# de_DE.UTF-8 UTF-8/de_DE.UTF-8 UTF-8/' /etc/locale.gen \
|
||||||
@@ -17,32 +17,26 @@ RUN apt-get update \
|
|||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
ENV LANG=de_DE.UTF-8 \
|
ENV LANG=de_DE.UTF-8 \
|
||||||
LANGUAGE=de_DE:de \
|
|
||||||
LC_ALL=de_DE.UTF-8
|
LC_ALL=de_DE.UTF-8
|
||||||
|
|
||||||
# Arbeitsverzeichnis
|
# Setze das Arbeitsverzeichnis auf den Workspace-Root, passend zu den Mounts.
|
||||||
WORKDIR /app
|
WORKDIR /workspace
|
||||||
|
|
||||||
# Kopiere nur Requirements für schnellen Rebuild
|
# Kopiere die Anforderungsdateien in das korrekte Unterverzeichnis.
|
||||||
COPY requirements.txt ./
|
# ✅ KORRIGIERT: Pfade sind jetzt relativ zum Build-Kontext (dem 'server'-Verzeichnis)
|
||||||
COPY requirements-dev.txt ./
|
COPY requirements.txt requirements-dev.txt ./
|
||||||
|
|
||||||
# Installiere Python-Abhängigkeiten (Prod + Dev)
|
# Installiere die Python-Abhängigkeiten
|
||||||
RUN pip install --upgrade pip \
|
RUN pip install --upgrade pip \
|
||||||
&& pip install --no-cache-dir -r requirements.txt \
|
&& pip install --no-cache-dir -r requirements.txt \
|
||||||
&& pip install --no-cache-dir -r requirements-dev.txt
|
&& pip install --no-cache-dir -r requirements-dev.txt
|
||||||
|
|
||||||
# Expose Ports für Flask API
|
# Das Kopieren des Codes ist nicht nötig, da das Verzeichnis gemountet wird.
|
||||||
EXPOSE 8000
|
|
||||||
EXPOSE 5678
|
|
||||||
|
|
||||||
# Setze Env für Dev
|
# Exponiere die Ports für die Flask API und den Debugger
|
||||||
ENV FLASK_ENV=development
|
EXPOSE 8000 5678
|
||||||
ENV ENV_FILE=.env
|
|
||||||
|
|
||||||
# Wechsle zum non-root User
|
# Der Startbefehl wird in der docker-compose.override.yml definiert.
|
||||||
USER infoscreen_taa
|
# Ein Standard-CMD dient als Fallback.
|
||||||
|
CMD ["python", "-m", "debugpy", "--listen", "0.0.0.0:5678", "-m", "flask", "run", "--host=0.0.0.0", "--port=8000"]
|
||||||
|
|
||||||
# Default Command: Flask Development Server
|
|
||||||
CMD ["python", "-m", "debugpy", "--listen", "0.0.0.0:5678", "wsgi.py"]
|
|
||||||
# CMD ["sleep", "infinity"]
|
|
||||||
|
|||||||
Reference in New Issue
Block a user