spawner/docs/guides/custom-templates.md
XPS\Micro 960e69bf62 docs: update custom-templates guide for .env-based template building
- Update overview to clarify that only .env-defined templates are built
- Update architecture diagram to reflect new .env-based process
- Add new 'Template Build-Prozess' section with detailed explanation
- Update 'Automatisiertes Deployment' with correct .env-based instructions
- Add emphasis to WICHTIG notes about .env configuration
- Update quick-start guide to show .env configuration as first step
- Update checklist to highlight critical .env step
- Clarify validation, error handling, and fallback behavior
2026-02-02 16:43:54 +01:00

1034 lines
24 KiB
Markdown

# Custom Templates - Vollständige Anleitung
## 📋 Inhaltsverzeichnis
1. [Überblick](#überblick)
2. [Template-System Architektur](#template-system-architektur)
3. [Anforderungen an Templates](#anforderungen-an-templates)
4. [Neues Template erstellen](#neues-template-erstellen)
5. [Template-Beispiele](#template-beispiele)
6. [Deployment](#deployment)
7. [Troubleshooting](#troubleshooting)
8. [Best Practices](#best-practices)
---
## Überblick
Das Container Spawner System verwendet ein **dynamisches Template-System**, das beliebig viele User-Templates unterstützt:
- **Konfigurationsgesteuert**: `install.sh` baut **nur** die in `.env` unter `USER_TEMPLATE_IMAGES` definierten Templates
- **Flexible Konfiguration**: Templates werden in `.env` definiert (semikolon-getrennt)
- **Metadaten-Driven**: Display-Namen und Beschreibungen kommen aus `templates.json`
- **Multi-Container Support**: Jeder User kann beliebig viele Container verschiedener Typen erstellen
**Standardtemplates:**
- `template-01`: Nginx Basic - Einfacher statischer Webserver
- `template-02`: Nginx Advanced - Nginx mit erweiterten Features
- `template-next`: Next.js Production - React-App mit Shadcn/UI
**Custom Templates hinzufügen:** Beliebig viele eigene Templates erstellen (Python, Node.js, etc.)
---
## Template-System Architektur
### Wie das System funktioniert
```
1. install.sh liest USER_TEMPLATE_IMAGES aus .env
2. Parst semikolon-getrennte Template-Liste
3. Baut NUR die definierten Docker Images
4. Validiert dass Verzeichnisse & Dockerfiles existieren
5. Warnt bei ungenutzten oder fehlenden Templates
6. Backend lädt aktualisierte Template-Liste aus .env
7. Metadaten werden aus templates.json geladen
8. Dashboard zeigt verfügbare Templates
9. User klickt "Erstellen" → Container spawnt
```
### Dateien im System
| Datei/Ordner | Zweck |
|--------------|-------|
| `user-template-xyz/` | Template-Verzeichnis (Dockerfile + Assets) |
| `.env``USER_TEMPLATE_IMAGES` | Liste aller verfügbaren Images |
| `templates.json` | Metadaten (Display-Name, Beschreibung) |
| `config.py` | Lädt Templates dynamisch beim Start |
| `container_manager.py` | Spawnt Container aus Templates |
### Template-Namen → Typ-Mapping
Das System extrahiert automatisch den Container-Typ aus dem Image-Namen:
```python
# Beispiele:
'user-template-01:latest' Typ: 'template-01'
'user-template-next:latest' Typ: 'template-next'
'user-template-python:latest' Typ: 'template-python'
'custom-nginx:v1.0' Typ: 'custom-nginx'
```
**Regel:** Image-Name ohne `user-` Prefix und ohne Tag (`:latest`) = Container-Typ
---
## Anforderungen an Templates
### Pflicht-Anforderungen
Jedes Template **MUSS**:
1. **Port 8080 exposen** (unprivileged, kein root)
```dockerfile
EXPOSE 8080
```
2. **Webserver auf Port 8080 laufen lassen**
- Nginx: `listen 8080;`
- Node.js: `app.listen(8080)`
- Flask: `app.run(port=8080, host='0.0.0.0')`
3. **Als unprivileged User laufen** (Sicherheit)
```dockerfile
USER nginx # oder node, www-data, etc.
```
4. **HTTP-Server bereitstellen** (Traefik routet HTTP-Traffic)
### Optionale Features
Templates **KÖNNEN**:
- Datenbank-Container integrieren (via Docker Compose in Template)
- Umgebungsvariablen nutzen (via ENV in Dockerfile)
- Volume-Mounts für persistente Daten (via docker-compose.yml)
- Build-Args für Konfiguration (z.B. `ARG NODE_VERSION=18`)
### Was NICHT funktioniert
Templates **KÖNNEN NICHT**:
- Andere Ports als 8080 nutzen (Traefik-Konfiguration)
- Root-Rechte benötigen (Security Policy)
- Direkten Zugriff auf Docker Socket (Isolation)
- Andere Container spawnen (nur eigener Container)
---
## Neues Template erstellen
### ⚠️ WICHTIG: .env-Konfiguration
**Bevor du ein Template hinzufügst, merke dir:**
- Nur Templates die in `.env``USER_TEMPLATE_IMAGES` definiert sind, werden gebaut
- Ohne `.env`-Eintrag wird `bash install.sh` das Template ignorieren
- Daher: `.env` ZUERST aktualisieren, dann Template erstellen
### Schritt 1: Verzeichnis erstellen
```bash
cd /path/to/spawner
mkdir user-template-myapp
cd user-template-myapp
```
**Namenskonvention:** `user-template-<name>`
- `<name>`: Eindeutiger Identifier (lowercase, keine Sonderzeichen außer `-`)
- Beispiele: `user-template-python`, `user-template-django`, `user-template-flask`
### Schritt 2: Dockerfile erstellen
**Basis-Vorlage (Nginx):**
```dockerfile
FROM nginx:alpine
# Expose Port 8080 (unprivileged)
EXPOSE 8080
# Kopiere statische Dateien
COPY index.html /usr/share/nginx/html/
# Nginx auf Port 8080 konfigurieren
RUN sed -i 's/listen 80;/listen 8080;/' /etc/nginx/conf.d/default.conf
# Run as unprivileged user
USER nginx
CMD ["nginx", "-g", "daemon off;"]
```
**Erweiterte Vorlage (Node.js):**
```dockerfile
FROM node:18-alpine
# Working Directory
WORKDIR /app
# Install Dependencies
COPY package*.json ./
RUN npm ci --only=production
# Copy Application Code
COPY . .
# Expose Port 8080
EXPOSE 8080
# Run as unprivileged user
USER node
# Start Application
CMD ["node", "server.js"]
```
**Wichtig:** Port 8080 ist Pflicht!
### Schritt 3: Template-Assets hinzufügen
**Beispiel: Nginx mit statischer index.html**
```bash
cat > index.html <<'EOF'
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>Mein Custom Template</title>
</head>
<body>
<h1>Willkommen zu meinem Custom Container!</h1>
<p>Dieser Container läuft auf Port 8080.</p>
</body>
</html>
EOF
```
**Beispiel: Node.js mit server.js**
```bash
cat > server.js <<'EOF'
const express = require('express');
const app = express();
const PORT = 8080;
app.get('/', (req, res) => {
res.send('<h1>Node.js Template</h1><p>Läuft auf Port 8080</p>');
});
app.listen(PORT, '0.0.0.0', () => {
console.log(`Server läuft auf Port ${PORT}`);
});
EOF
```
### Schritt 4: `.env` aktualisieren
Öffne die `.env` Datei im Hauptverzeichnis:
```bash
nano .env
```
Füge dein Template zur `USER_TEMPLATE_IMAGES` Liste hinzu:
```bash
# Vorher:
USER_TEMPLATE_IMAGES="user-template-01:latest;user-template-02:latest;user-template-next:latest"
# Nachher:
USER_TEMPLATE_IMAGES="user-template-01:latest;user-template-02:latest;user-template-next:latest;user-template-myapp:latest"
```
**Wichtig:** Semikolon-getrennt, keine Leerzeichen, mit `:latest` Tag!
### Schritt 5: `templates.json` aktualisieren
Öffne `templates.json`:
```bash
nano templates.json
```
Füge Metadaten für dein Template hinzu:
```json
{
"templates": [
{
"type": "template-01",
"image": "user-template-01:latest",
"display_name": "Nginx Basic",
"description": "Einfacher Nginx-Server mit statischen Dateien"
},
{
"type": "template-02",
"image": "user-template-02:latest",
"display_name": "Nginx Advanced",
"description": "Nginx mit erweiterten Features"
},
{
"type": "template-next",
"image": "user-template-next:latest",
"display_name": "Next.js Production",
"description": "React-App mit Shadcn/UI"
},
{
"type": "template-myapp",
"image": "user-template-myapp:latest",
"display_name": "Meine Custom App",
"description": "Mein eigenes Template mit Node.js"
}
]
}
```
**Felder:**
- `type`: Muss mit extrahiertem Typ übereinstimmen (`template-myapp`)
- `image`: Vollständiger Image-Name mit Tag
- `display_name`: Name im Dashboard (beliebig)
- `description`: Kurze Beschreibung für User
### Schritt 6: Template lokal bauen
```bash
cd /path/to/spawner
docker build -t user-template-myapp:latest user-template-myapp/
```
**Überprüfung:**
```bash
docker images | grep user-template-myapp
# Expected: user-template-myapp latest abc123def456 5 seconds ago 150MB
```
### Schritt 7: Template testen
Starte einen Test-Container:
```bash
docker run -d -p 8080:8080 --name test-myapp user-template-myapp:latest
```
Teste im Browser:
```bash
curl http://localhost:8080
# Expected: HTML-Output deines Templates
```
Cleanup:
```bash
docker stop test-myapp
docker rm test-myapp
```
### Schritt 8: Änderungen committen
```bash
git add user-template-myapp/ .env templates.json
git commit -m "feat: add custom template-myapp"
git push
```
---
## Template-Beispiele
### Beispiel 1: Python Flask Template
**Verzeichnisstruktur:**
```
user-template-flask/
├── Dockerfile
├── requirements.txt
└── app.py
```
**Dockerfile:**
```dockerfile
FROM python:3.11-slim
WORKDIR /app
# Install Dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy Application
COPY app.py .
# Expose Port 8080
EXPOSE 8080
# Run as unprivileged user
RUN useradd -m appuser
USER appuser
# Start Flask
CMD ["python", "app.py"]
```
**requirements.txt:**
```
Flask==3.0.0
gunicorn==21.2.0
```
**app.py:**
```python
from flask import Flask
app = Flask(__name__)
@app.route('/')
def home():
return '<h1>Flask Template</h1><p>Läuft auf Port 8080</p>'
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)
```
**In `.env` hinzufügen:**
```bash
USER_TEMPLATE_IMAGES="...;user-template-flask:latest"
```
**In `templates.json` hinzufügen:**
```json
{
"type": "template-flask",
"image": "user-template-flask:latest",
"display_name": "Python Flask",
"description": "Flask Web-Framework für Python"
}
```
### Beispiel 2: Static Site Generator (Hugo)
**Verzeichnisstruktur:**
```
user-template-hugo/
├── Dockerfile
├── config.toml
└── content/
└── _index.md
```
**Dockerfile:**
```dockerfile
FROM klakegg/hugo:alpine AS builder
WORKDIR /src
COPY . .
RUN hugo --minify
FROM nginx:alpine
# Copy built site
COPY --from=builder /src/public /usr/share/nginx/html
# Nginx on Port 8080
RUN sed -i 's/listen 80;/listen 8080;/' /etc/nginx/conf.d/default.conf
EXPOSE 8080
USER nginx
CMD ["nginx", "-g", "daemon off;"]
```
**config.toml:**
```toml
baseURL = "/"
languageCode = "de-de"
title = "Hugo Template"
theme = "ananke"
```
### Beispiel 3: Database-Backed Template (Node.js + PostgreSQL)
**Hinweis:** Für Multi-Container-Templates (mit DB) nutze `docker-compose.yml` **innerhalb** des Templates.
**Verzeichnisstruktur:**
```
user-template-node-db/
├── Dockerfile
├── docker-compose.yml
├── package.json
└── server.js
```
**Dockerfile:**
```dockerfile
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 8080
USER node
CMD ["node", "server.js"]
```
**docker-compose.yml (wird vom Container genutzt):**
```yaml
version: '3.8'
services:
app:
build: .
ports:
- "8080:8080"
environment:
- DATABASE_URL=postgresql://user:password@db:5432/mydb
depends_on:
- db
db:
image: postgres:15-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: password
POSTGRES_DB: mydb
volumes:
- db-data:/var/lib/postgresql/data
volumes:
db-data:
```
**Wichtig:** Spawner erstellt nur den Main-Container. Für Multi-Container nutze einen Wrapper-Script oder starte via `docker-compose` im Container.
---
## Deployment
### Lokale Entwicklung
```bash
# 1. Template erstellen
mkdir user-template-xyz
cd user-template-xyz
# ... Dockerfile erstellen ...
# 2. .env und templates.json aktualisieren
nano ../.env
nano ../templates.json
# 3. Template bauen
docker build -t user-template-xyz:latest .
# 4. Spawner neu starten
cd ..
docker-compose restart spawner
# 5. Dashboard öffnen
# Template sollte jetzt sichtbar sein
```
### Production Deployment (Server)
**Schritt 1: Code committen**
```bash
git add user-template-xyz/ .env templates.json
git commit -m "feat: add template-xyz"
git push
```
**Schritt 2: Auf Server deployen**
```bash
# SSH zum Server
ssh user@server
# Navigiere zum Spawner-Verzeichnis
cd /volume1/docker/spawner
# Pull neueste Änderungen
git pull
# Baue neues Template
docker build -t user-template-xyz:latest user-template-xyz/
# Kopiere aktualisierte Config-Dateien in Container
docker cp .env spawner:/app/.env
docker cp templates.json spawner:/app/templates.json
# Restart Spawner (lädt neue Konfiguration)
docker-compose restart spawner
```
**Schritt 3: Verifikation**
```bash
# Überprüfe ob Template geladen wurde
docker-compose logs spawner | grep "template-xyz"
# Teste via Debug-API
curl -H "X-Debug-Token: <token>" \
"http://localhost:5000/api/admin/debug?action=info"
# Dashboard öffnen und neues Template prüfen
```
### Automatisiertes Deployment (install.sh)
Das `install.sh` Script baut **nur die in `.env` unter `USER_TEMPLATE_IMAGES` definierten** Templates:
```bash
# Lokale Installation
cd /path/to/spawner
cp .env.example .env # Falls .env nicht existiert
# Optional: nano .env # USER_TEMPLATE_IMAGES anpassen
bash install.sh # Baut nur definierte Templates
```
```bash
# Auf Server (mit git pull)
ssh user@server
cd /volume1/docker/spawner
git pull # Neue Templates/Änderungen herunterladen
bash install.sh # Baut nur definierte Templates
```
**Was install.sh macht:**
1. Liest `USER_TEMPLATE_IMAGES` aus `.env`
2. Parst semikolon-getrennte Template-Liste
3. Baut Docker Images **nur** für definierte Templates
4. Validiert dass Verzeichnisse und Dockerfiles existieren
5. Warnt bei fehlenden oder ungenutzten Verzeichnissen
6. Startet Services neu
7. Templates erscheinen automatisch im Dashboard
**Wichtig:**
- Alle in `USER_TEMPLATE_IMAGES` definierten Templates müssen entsprechende Verzeichnisse haben
- Verzeichnisse ohne `.env`-Eintrag werden NICHT gebaut
- Falls `USER_TEMPLATE_IMAGES` nicht definiert ist, fallback auf alte Logik (baue alle)
**Vorteil:**
- Schnellere Installation (nur nötige Templates)
- Volle Kontrolle über welche Templates verfügbar sind
- Keine unnötigen Docker-Builds
---
## Template Build-Prozess (.env-basiert)
### Wie install.sh Templates auswählt
Das System nutzt `USER_TEMPLATE_IMAGES` in `.env` um zu bestimmen, welche Templates gebaut werden:
```bash
# In .env definiert:
USER_TEMPLATE_IMAGES="user-template-01:latest;user-template-next:latest"
# Verzeichnisstruktur:
user-template-01/Dockerfile ✅ wird gebaut
user-template-02/Dockerfile ⏭️ wird NICHT gebaut (nicht in .env)
user-template-next/Dockerfile ✅ wird gebaut
```
### Validation & Fehlerbehandlung
`install.sh` prüft automatisch:
1. **Verzeichnis-Existenz:**
- ✅ Template in `.env` + Verzeichnis vorhanden → baue
- ⚠️ Template in `.env` + Verzeichnis fehlt → Warnung, überspringe
2. **Dockerfile-Existenz:**
- ✅ Dockerfile vorhanden → baue
- ⚠️ Dockerfile fehlt → Warnung, überspringe
3. **Ungekonfigurierte Verzeichnisse:**
- ⚠️ Verzeichnis existiert, aber nicht in `USER_TEMPLATE_IMAGES` → Warnung
4. **Build-Fehler:**
- ❌ Docker-Build schlägt fehl → Exit mit Fehler
### Beispiel: Teilmenge Templates bauen
**Szenario:** Nur Nginx Basic und Next.js bauen (nicht Nginx Advanced)
```bash
# 1. Bearbeite .env
nano .env
# 2. Ändere USER_TEMPLATE_IMAGES:
# ALT:
USER_TEMPLATE_IMAGES="user-template-01:latest;user-template-02:latest;user-template-next:latest"
# NEU (nur zwei):
USER_TEMPLATE_IMAGES="user-template-01:latest;user-template-next:latest"
# 3. Starte install.sh
bash install.sh
# Output:
# Baue Templates aus .env Konfiguration...
# [1/2] Baue Template: user-template-01:latest
# ✅ user-template-01: OK
# [2/2] Baue Template: user-template-next:latest
# ✅ user-template-next: OK (kann 2-5 Min dauern)
# ✅ 2/2 Template(s) erfolgreich gebaut.
#
# ⚠️ Ungekonfigurierte Template-Verzeichnisse:
# - user-template-02 (nicht in USER_TEMPLATE_IMAGES definiert)
```
### Fallback bei fehlender Konfiguration
Falls `USER_TEMPLATE_IMAGES` nicht definiert ist:
```bash
# .env fehlt oder USER_TEMPLATE_IMAGES leer
bash install.sh
# Output:
# ⚠️ USER_TEMPLATE_IMAGES nicht konfiguriert
# Fallback: Baue alle user-template-* Verzeichnisse (alte Logik)...
#
# → Baut alle verfügbaren Templates (Alt-Verhalten für Kompatibilität)
```
---
## Troubleshooting
### Problem: Template erscheint nicht im Dashboard
**Symptom:** Neues Template ist nicht in der Container-Liste sichtbar
**Lösung:**
```bash
# 1. Überprüfe .env im Container
docker exec spawner cat /app/.env | grep USER_TEMPLATE_IMAGES
# 2. Überprüfe templates.json im Container
docker exec spawner cat /app/templates.json
# 3. Überprüfe Backend-Logs
docker-compose logs spawner | grep -i template
# 4. Falls nicht aktualisiert, kopiere Dateien manuell:
docker cp .env spawner:/app/.env
docker cp templates.json spawner:/app/templates.json
docker-compose restart spawner
```
### Problem: Container spawnt nicht / Fehler beim Start
**Symptom:** Klick auf "Erstellen" → Fehler "Container konnte nicht erstellt werden"
**Lösung:**
```bash
# 1. Überprüfe ob Image existiert
docker images | grep user-template-xyz
# 2. Falls nicht vorhanden, baue neu:
docker build -t user-template-xyz:latest user-template-xyz/
# 3. Teste Image manuell
docker run -d -p 8080:8080 --name test-xyz user-template-xyz:latest
# 4. Überprüfe Logs
docker logs test-xyz
# 5. Cleanup
docker stop test-xyz && docker rm test-xyz
# 6. Überprüfe Spawner-Logs
docker-compose logs spawner | tail -50
```
### Problem: Port 8080 nicht erreichbar
**Symptom:** Container läuft, aber `curl http://localhost:8080` gibt Timeout
**Lösung:**
```bash
# 1. Überprüfe ob Container wirklich auf 8080 hört
docker exec <container-id> netstat -tlnp | grep 8080
# 2. Überprüfe Dockerfile
cat user-template-xyz/Dockerfile | grep EXPOSE
# Expected: EXPOSE 8080
# 3. Überprüfe Webserver-Konfiguration
# Nginx: listen 8080;
# Node.js: app.listen(8080, '0.0.0.0')
# Flask: app.run(port=8080, host='0.0.0.0')
# 4. Rebuilde Template mit korrektem Port
docker build -t user-template-xyz:latest user-template-xyz/
```
### Problem: Traefik routet nicht zum Container
**Symptom:** URL öffnet, aber zeigt 404 oder Timeout
**Lösung:**
```bash
# 1. Überprüfe Container-Labels
docker inspect user-<slug>-<type>-<id> | grep -A10 traefik
# 2. Überprüfe Traefik Dashboard
# http://<server>:8080 → HTTP Routers
# 3. Überprüfe StripPrefix Middleware
curl http://localhost:8080/api/http/middlewares | jq . | grep user
# 4. Überprüfe Traefik Logs
docker-compose logs traefik | grep user-<slug>
# 5. Starte Traefik neu
docker-compose restart traefik
```
### Problem: Datei-Änderungen werden nicht übernommen
**Symptom:** Dockerfile geändert, aber Container nutzt alte Version
**Lösung:**
```bash
# 1. IMMER --no-cache beim Rebuild verwenden
docker build --no-cache -t user-template-xyz:latest user-template-xyz/
# 2. Alte Container entfernen
docker ps -a | grep user-template-xyz | awk '{print $1}' | xargs docker rm -f
# 3. Neue Container spawnen (via Dashboard oder API)
# 4. Überprüfe Image-Erstellungsdatum
docker images | grep user-template-xyz
# Should show recent timestamp
```
---
## Best Practices
### Sicherheit
1. **Unprivileged Users verwenden**
```dockerfile
# NICHT als root laufen
USER nginx # oder node, www-data, appuser, etc.
```
2. **Minimale Base Images**
```dockerfile
# Bevorzuge alpine-Varianten
FROM node:18-alpine # statt node:18
FROM python:3.11-slim # statt python:3.11
```
3. **Keine Secrets im Image**
```dockerfile
# ❌ FALSCH
ENV API_KEY=secret123
# ✅ RICHTIG - Via Runtime-Env
# Secrets werden vom Spawner injiziert
```
### Performance
1. **Multi-Stage Builds nutzen**
```dockerfile
# Build Stage
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Runtime Stage
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
```
2. **Layer Caching optimieren**
```dockerfile
# Dependencies zuerst (ändern sich selten)
COPY package*.json ./
RUN npm ci
# Code danach (ändert sich oft)
COPY . .
```
3. **Image-Größe minimieren**
```dockerfile
# Cleanup in einer RUN-Anweisung
RUN apt-get update && \
apt-get install -y pkg1 pkg2 && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
```
### Wartbarkeit
1. **Versionierung nutzen**
```bash
# Statt :latest auch spezifische Versionen taggen
docker build -t user-template-xyz:v1.0.0 .
docker tag user-template-xyz:v1.0.0 user-template-xyz:latest
```
2. **README.md pro Template**
```markdown
# Template XYZ
## Was macht dieses Template?
- Beschreibung
- Features
- Use Cases
## Konfiguration
- Umgebungsvariablen
- Volumes
- Ports
## Entwicklung
- Lokales Setup
- Tests
- Debugging
```
3. **Dokumentierte Umgebungsvariablen**
```dockerfile
# ENV-Variablen mit Defaults
ENV NODE_ENV=production \
PORT=8080 \
LOG_LEVEL=info
```
### Testing
1. **Health Checks definieren**
```dockerfile
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8080/health || exit 1
```
2. **Test-Script erstellen**
```bash
#!/bin/bash
# test-template.sh
IMAGE="user-template-xyz:latest"
CONTAINER="test-xyz"
# Build
docker build -t $IMAGE .
# Run
docker run -d -p 8080:8080 --name $CONTAINER $IMAGE
# Wait
sleep 5
# Test
curl -f http://localhost:8080 || exit 1
# Cleanup
docker stop $CONTAINER && docker rm $CONTAINER
echo "✅ Template funktioniert!"
```
3. **Automatisierte Tests (optional)**
```bash
# CI/CD Pipeline (GitHub Actions, GitLab CI)
# .github/workflows/test-templates.yml
name: Test Templates
on: [push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Test Template XYZ
run: bash user-template-xyz/test-template.sh
```
---
## Zusammenfassung
### Schnell-Anleitung
```bash
# 0. ZUERST: .env aktualisieren!
nano .env
# USER_TEMPLATE_IMAGES="...;user-template-myapp:latest"
# 1. Verzeichnis erstellen
mkdir user-template-myapp
# 2. Dockerfile erstellen (Port 8080, unprivileged user)
nano user-template-myapp/Dockerfile
# 3. Assets hinzufügen (z.B. index.html für Nginx)
cp index.html user-template-myapp/
# 4. templates.json aktualisieren
nano templates.json
# { "type": "template-myapp", "image": "user-template-myapp:latest", ... }
# 5. Bauen & Testen (lokal)
docker build -t user-template-myapp:latest user-template-myapp/
docker run -d -p 8080:8080 --name test user-template-myapp:latest
curl http://localhost:8080
docker stop test && docker rm test
# 6. Committen & Pushen
git add user-template-myapp/ .env templates.json
git commit -m "feat: add template-myapp"
git push
# 7. Auf Server deployen
ssh user@server
cd /volume1/docker/spawner
# Wichtig: git pull BEVOR install.sh!
git pull
# install.sh baut automatisch nur die in .env definierten Templates
bash install.sh
# → Baut user-template-myapp (weil in .env definiert)
# 8. Überprüfung
docker-compose logs spawner | tail -20
# Dashboard öffnen und Template prüfen
```
### Checkliste
- [ ] Template-Verzeichnis `user-template-<name>/` erstellt
- [ ] Dockerfile mit Port 8080 und unprivileged user
- [ ] **WICHTIG: `.env` → `USER_TEMPLATE_IMAGES` aktualisiert** (sonst wird Template nicht gebaut!)
- [ ] Template lokal gebaut und getestet
- [ ] `templates.json` mit Metadaten erweitert
- [ ] Änderungen committed und gepusht
- [ ] Auf Server deployed:
- [ ] `git pull` (holt neue Änderungen)
- [ ] `bash install.sh` (baut Templates aus `.env`)
- [ ] Überprüfe Logs: `docker-compose logs spawner`
- [ ] Dashboard überprüft (Template sichtbar?)
- [ ] Container erfolgreich erstellt und erreichbar
---
## Support & Weitere Informationen
- **Hauptdokumentation**: `docs/install/DEPLOYMENT_GUIDE.md`
- **Architektur**: `CLAUDE.md`
- **Troubleshooting**: `docs/install/DEPLOYMENT_GUIDE.md#troubleshooting`
- **API-Dokumentation**: `docs/api/` (falls vorhanden)
Bei Fragen: Issue auf GitHub/Gitea erstellen oder Admin kontaktieren.