Skip to content

Docker Deployment

TCM365 stellt Docker Compose Konfigurationen für Entwicklung, Produktion und Self-hosted Deployments bereit. Dieser Guide behandelt alle drei Konfigurationen und die zugrunde liegende Container-Architektur.


Container-Architektur

TCM365 verwendet drei Docker Images:

Image Basis-Image Zweck
tcm365-backend node:18-alpine NestJS Backend API Server
tcm365-frontend node:22-alpine Vue 3 Static Assets via Nginx
nginx (Reverse Proxy) nginx:alpine Reverse Proxy für API und Frontend

Node Version Mismatch

Das Backend nutzt node:18-alpine, während das Frontend node:22-alpine verwendet. Dies ist bekannter Technical Debt, der im Projekt-Backlog getrackt wird. Der Grund: Vite 7 benötigt Node 22+, während das NestJS Backend auf Node 18 LTS läuft.


Docker Compose Konfigurationen

Entwicklung: docker-compose.local.yml

Startet ausschliesslich PostgreSQL und Redis für lokale Entwicklung. Backend und Frontend laufen nativ auf dem Entwicklungsrechner.

cd infrastructure/docker
docker compose -f docker-compose.local.yml up -d

Gestartete Services:

Service Port Zweck
postgres 5432 PostgreSQL 15 Datenbank
redis 6379 Redis 7 Cache (optional)

Verwendung mit lokalen Entwicklungsservern:

cd infrastructure/docker
docker compose -f docker-compose.local.yml up -d
cd backend-js
npm run start:dev
cd frontend
npm run dev

Services stoppen:

cd infrastructure/docker
docker compose -f docker-compose.local.yml down

Daten zurücksetzen (destruktiv):

cd infrastructure/docker
docker compose -f docker-compose.local.yml down -v

Volume-Löschung

Der Parameter -v löscht alle Named Volumes einschliesslich der PostgreSQL-Daten. Alle Snapshots, Konfigurationen und Benutzer gehen dabei verloren.

Produktion: docker-compose.yml

Startet den vollständigen Stack einschliesslich Backend, Frontend, PostgreSQL, Redis und Nginx Reverse Proxy.

cd infrastructure/docker
docker compose up --build -d

Gestartete Services:

Service Port Zweck
backend 8000 NestJS API Server (intern)
frontend 80 Nginx mit Vue Static Assets
postgres 5432 PostgreSQL 15 Datenbank
redis 6379 Redis 7 Cache
nginx 80/443 Reverse Proxy (externer Einstiegspunkt)

Zugriff auf die Applikation:

http://localhost       # Frontend (via Nginx)
http://localhost/api   # Backend API (via Nginx Proxy)

Coolify: docker-compose.coolify.yml

Optimiert für Coolify Self-hosted PaaS Deployment:

cd infrastructure/docker
docker compose -f docker-compose.coolify.yml up -d

Diese Konfiguration ist für die Zusammenarbeit mit Coolifys eingebautem Reverse Proxy und SSL Management konzipiert.


Dockerfiles

Backend: Dockerfile.backend-js

Multi-Stage Build für das NestJS Backend:

# Stage 1: Build
FROM node:18-alpine AS builder
WORKDIR /app
COPY backend-js/package*.json ./
RUN npm ci
COPY backend-js/ ./
COPY VERSION ../VERSION
RUN npm run build

# Stage 2: Production
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
EXPOSE 8000
CMD ["node", "dist/main.js"]

Wichtige Punkte:

  • Multi-Stage Build minimiert die Image-Größe
  • Die VERSION Datei wird in den Container kopiert für die Versionsanzeige
  • Die Produktions-Stage enthält nur kompiliertes JavaScript und Produktions-Dependencies
  • Port 8000 wird exponiert

Frontend: Dockerfile.frontend

Multi-Stage Build für das Vue 3 Frontend:

# Stage 1: Build
FROM node:22-alpine AS builder
WORKDIR /app
COPY frontend/package*.json ./
RUN npm ci
COPY frontend/ ./
COPY VERSION ../VERSION
RUN npm run build

# Stage 2: Auslieferung mit Nginx
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY infrastructure/docker/nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80

Wichtige Punkte:

  • Node 22 wird für die Build-Stage verwendet (Vite 7 benötigt dies)
  • Die Produktions-Stage nutzt Nginx zur Auslieferung statischer Assets
  • Die VERSION Datei steht während des Builds für Version Injection zur Verfügung

Nginx Konfiguration

Die infrastructure/docker/nginx.conf konfiguriert den Reverse Proxy:

server {
    listen 80;
    server_name _;

    # Frontend Static Assets
    location / {
        root /usr/share/nginx/html;
        try_files $uri $uri/ /index.html;
    }

    # Backend API Proxy
    location /api {
        proxy_pass http://backend:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    # Health Check Proxy
    location /health {
        proxy_pass http://backend:8000;
    }
}

Die Nginx Konfiguration:

  • Liefert die Vue 3 SPA mit try_files Fallback für Client-Side Routing aus
  • Leitet /api/* und /health Requests an den Backend Container weiter
  • Uebergibt die echte Client-IP via X-Forwarded-For
  • Behandelt den SPA History Mode (alle Nicht-API Routen liefern index.html aus)

Umgebungsvariablen für Docker

Backend Container

Umgebungsvariablen werden dem Backend Container via .env Datei oder Docker Compose environment Sektion übergeben:

# docker-compose.yml Auszug
services:
  backend:
    build:
      context: ../..
      dockerfile: infrastructure/docker/Dockerfile.backend-js
    environment:
      - PORT=8000
      - APP_SECRET_KEY=your-production-secret-min-32-chars
      - APP_DEBUG=false
      - DATABASE_HOST=postgres
      - DATABASE_PORT=5432
      - DATABASE_USERNAME=tcm_user
      - DATABASE_PASSWORD=tcm_password
      - DATABASE_NAME=tcm_db
      - STORAGE_BACKEND=local
      - LOCAL_STORAGE_PATH=/app/data
      - REDIS_URL=redis://redis:6379/0
      - CORS_ORIGINS=http://localhost,https://tcm.example.com
    volumes:
      - backend-data:/app/data
    depends_on:
      postgres:
        condition: service_healthy

DATABASE_HOST in Docker

Innerhalb von Docker Compose muss DATABASE_HOST auf den Service-Namen postgres gesetzt werden, nicht auf localhost. Docker Compose stellt die DNS-Aufloesung zwischen Containern über Service-Namen bereit.

PostgreSQL Container

services:
  postgres:
    image: postgres:15-alpine
    environment:
      - POSTGRES_USER=tcm_user
      - POSTGRES_PASSWORD=tcm_password
      - POSTGRES_DB=tcm_db
    volumes:
      - postgres-data:/var/lib/postgresql/data
    ports:
      - "5432:5432"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U tcm_user -d tcm_db"]
      interval: 10s
      timeout: 5s
      retries: 5

Redis Container

services:
  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    volumes:
      - redis-data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5

Volumes

Docker Compose verwendet Named Volumes für Datenpersistenz:

Volume Container Mount Zweck
postgres-data /var/lib/postgresql/data PostgreSQL Datenbankdateien
redis-data /data Redis Persistenz (falls aktiviert)
backend-data /app/data Lokaler Dateispeicher (Snapshots, Reports)

Volume-Persistenz

Named Volumes ueberleben Container-Neustarts und docker compose down. Um Daten vollständig zurückzusetzen, verwenden Sie docker compose down -v, was alle Volumes entfernt.


Bauen und Aktualisieren

Alle Images bauen

cd infrastructure/docker
docker compose build

Einzelnen Service neu bauen

docker compose build backend
docker compose build frontend

Aktualisieren und neu starten

cd infrastructure/docker
docker compose down
docker compose up --build -d

Migrationen in Docker ausführen

# Migrationen im laufenden Backend Container ausführen
docker compose exec backend npm run migration:run

# Admin-Benutzer erstellen
docker compose exec backend npm run db:seed

Health Checks

Die Docker Compose Konfiguration beinhaltet Health Checks für alle Services:

Service Health Check Intervall Retries
postgres pg_isready -U tcm_user -d tcm_db 10s 5
redis redis-cli ping 10s 5
backend curl -f http://localhost:8000/health 30s 3

Der Backend Container wartet auf einen gesunden PostgreSQL-Status bevor er startet (depends_on mit condition: service_healthy).


Troubleshooting Docker

Container startet nicht

# Container Logs prüfen
docker compose logs backend
docker compose logs postgres

# Container Status prüfen
docker compose ps

Datenbankverbindung abgelehnt

Stellen Sie sicher, dass das Backend den Docker Service-Namen (postgres) als Datenbank-Host verwendet, nicht localhost:

DATABASE_HOST=postgres   # Docker Service-Name (korrekt)
DATABASE_HOST=localhost  # Nur für host-basierte Entwicklung

Port-Konflikte

Falls die Ports 5432, 6379 oder 8000 bereits belegt sind:

# Prüfen welcher Prozess den Port nutzt
lsof -i :5432
# Prüfen welcher Prozess den Port nutzt
netstat -ano | findstr :5432

Ports in docker-compose.yml ändern:

ports:
  - "15432:5432"   # Auf einen anderen Host-Port mappen

Container Speicherverbrauch

# Docker Speicherverbrauch prüfen
docker system df

# Ungenutzte Images und Container bereinigen
docker system prune

# Alle gestoppten Container und ungenutzten Images entfernen (aggressiver)
docker system prune -a

Regelmäßige Bereinigung

Führen Sie docker system prune regelmäßig aus, um ungenutzten Speicherplatz durch alte Build-Caches und gestoppte Container freizugeben.