Ziel: Automatische Erkennung und Auswahl der passenden Docker-Compose-Datei basierend auf:
- Docker-Modus (rootful/rootless)
- Swarm-Status (aktiv/inaktiv)
Ansatz: Separate Dateien für jeden Modus - einfach und klar
✅ Entscheidung: Option B - Service-relativ (./logs/)
- Rootful:
/var/log/... - Rootless:
./logs/...
✅ Entscheidung: Option A - CAP_NET_BIND_SERVICE
- Rootless kann Ports < 1024 nutzen wenn CAP gesetzt ist
- Traefik:
80:80,443:443(beide Modi) - Pi-hole:
53:53(beide Modi)
✅ Entscheidung: <category>-<service>
- Beispiel:
gateway-management-traefik-crowdsec - Format: Kategorie + Bindestrich + Service-Name
✅ Entscheidung:
- Generierte Dateien: NEIN (keine generierten Dateien)
- Alle Dateien werden committed (docker-compose.yml, docker-compose.rootless.yml, docker-stack.yml)
✅ Entscheidung: Separate Dateien
docker/
service-name/
docker-compose.yml # Rootful (Standard)
docker-compose.rootless.yml # Rootless-Variante
docker-stack.yml # Swarm
Zweck: Docker-Modus-Erkennung und Helper-Funktionen
Funktionen:
# Hauptfunktion
detect_docker_mode()
# Gibt zurück: "rootful", "rootless", oder "swarm"
# Helper-Funktionen
is_docker_rootless()
is_docker_root()
is_swarm_active()
get_compose_file() # Gibt passende Datei zurückErkennungslogik:
- Swarm prüfen:
docker info 2>/dev/null | grep -q "Swarm: active"- Wenn JA →
docker-stack.yml
- Wenn JA →
- Rootless prüfen:
[ -S "$XDG_RUNTIME_DIR/docker.sock" ]- Wenn JA →
docker-compose.rootless.yml
- Wenn JA →
- Root prüfen:
[ -S "/var/run/docker.sock" ](Fallback)- Wenn JA →
docker-compose.yml
- Wenn JA →
Implementierung:
detect_docker_mode() {
if is_swarm_active; then
DOCKER_MODE="swarm"
COMPOSE_FILE="docker-stack.yml"
elif is_docker_rootless; then
DOCKER_MODE="rootless"
COMPOSE_FILE="docker-compose.rootless.yml"
elif is_docker_root; then
DOCKER_MODE="rootful"
COMPOSE_FILE="docker-compose.yml"
else
DOCKER_MODE="unknown"
COMPOSE_FILE="docker-compose.yml" # Fallback
fi
export DOCKER_MODE
export COMPOSE_FILE
}
is_swarm_active() {
docker info 2>/dev/null | grep -q "Swarm: active"
}
is_docker_rootless() {
[ -S "${XDG_RUNTIME_DIR}/docker.sock" ] 2>/dev/null
}
is_docker_root() {
[ -S "/var/run/docker.sock" ] 2>/dev/null
}
get_compose_file() {
local service_dir=$1
detect_docker_mode
# Prüfe ob Datei existiert
if [ -f "$service_dir/$COMPOSE_FILE" ]; then
echo "$COMPOSE_FILE"
return 0
fi
# Fallback: docker-compose.yml
if [ -f "$service_dir/docker-compose.yml" ]; then
echo "docker-compose.yml"
return 0
fi
return 1
}Änderungen in start_docker_container():
start_docker_container() {
local container=$1
local docker_dir=$(get_docker_dir "$container")
if [ -z "$docker_dir" ]; then
print_status "Invalid container: $container" "error"
return 1
fi
print_status "Starting $container" "info"
# Check for update-env.sh
if [ -f "$docker_dir/update-env.sh" ]; then
print_status "Running environment updates..." "info"
(cd "$docker_dir" && bash update-env.sh)
fi
# NEU: Docker-Modus erkennen und passende Datei wählen
detect_docker_mode
local compose_file=$(get_compose_file "$docker_dir")
if [ -z "$compose_file" ]; then
print_status "No compose file found for $container" "error"
return 1
fi
print_status "Using $DOCKER_MODE mode with $compose_file" "info"
if [ -d "$docker_dir" ]; then
# NEU: Swarm vs Compose unterscheiden
if [ "$DOCKER_MODE" = "swarm" ]; then
local stack_name=$(get_stack_name "$container")
(cd "$docker_dir" && docker stack deploy -c "$compose_file" "$stack_name")
else
(cd "$docker_dir" && docker compose -f "$compose_file" up -d)
fi
print_status "Container started successfully" "success"
return 0
else
print_status "Container directory not found" "error"
return 1
fi
}Neue Funktion:
get_stack_name() {
local container=$1
local category=$(get_container_category "$container")
if [ -z "$category" ]; then
echo "$container" # Fallback
return 1
fi
# Format: <category>-<service>
echo "${category}-${container}"
}Anpassung in restart_docker_container():
restart_docker_container() {
local container=$1
local docker_dir=$(get_docker_dir "$container")
if [ -z "$docker_dir" ]; then
print_status "Invalid container: $container" "error"
return 1
fi
detect_docker_mode
local compose_file=$(get_compose_file "$docker_dir")
if [ -z "$compose_file" ]; then
print_status "No compose file found for $container" "error"
return 1
fi
if [ -d "$docker_dir" ]; then
print_status "Restarting $container" "info"
if [ "$DOCKER_MODE" = "swarm" ]; then
local stack_name=$(get_stack_name "$container")
(cd "$docker_dir" && docker stack deploy -c "$compose_file" "$stack_name")
else
(cd "$docker_dir" && docker compose -f "$compose_file" up -d --force-recreate)
fi
print_status "Container restarted successfully" "success"
return 0
else
print_status "Container directory not found" "error"
return 1
fi
}Kritisch (Docker Socket + System-Pfade):
-
✅ traefik-crowdsec
/var/run/docker.sock→${XDG_RUNTIME_DIR}/docker.sock(rootless)/var/log/traefik→./logs/traefik(rootless)/var/log/auth.log→./logs/auth.log(rootless)- Ports bleiben gleich (CAP_NET_BIND_SERVICE)
-
✅ cloudflare-companion
/var/run/docker.sock→${XDG_RUNTIME_DIR}/docker.sock(rootless)
-
✅ portainer
/var/run/docker.sock→${XDG_RUNTIME_DIR}/docker.sock(rootless)
-
✅ watchtower
/var/run/docker.sock→${XDG_RUNTIME_DIR}/docker.sock(rootless)
Optional (nur Ports < 1024):
5.
- Port
53:53bleibt gleich (CAP_NET_BIND_SERVICE) - Keine Änderung nötig wenn CAP gesetzt ist
Nicht betroffen:
- Services ohne Docker Socket
- Services ohne System-Pfade
- Services ohne Ports < 1024
Für jeden betroffenen Service:
-
Kopieren:
docker-compose.yml→docker-compose.rootless.yml -
Anpassen:
# Vorher (rootful): volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - /var/log/traefik:/var/log/traefik ports: - "80:80" - "443:443" # Nachher (rootless): volumes: - ${XDG_RUNTIME_DIR}/docker.sock:/var/run/docker.sock:ro - ./logs/traefik:/var/log/traefik ports: - "80:80" # Funktioniert mit CAP_NET_BIND_SERVICE - "443:443"
-
Log-Verzeichnisse: Erstelle
./logs/Verzeichnisse für rootless
Wichtig: ${XDG_RUNTIME_DIR} muss in der Shell-Umgebung exportiert sein!
Mit NixOSControlCenter:
- ✅ Automatisch:
XDG_RUNTIME_DIRwird von NixOS-Config exportiert - ✅ Keine manuelle Konfiguration nötig
- ✅
${XDG_RUNTIME_DIR}/docker.sockfunktioniert direkt in docker-compose.rootless.yml
Ohne NixOSControlCenter (andere Systeme):
⚠️ Manuell setzen: Variable muss exportiert sein- Option 1: In Shell-Config (
.bashrc/.zshrc):export XDG_RUNTIME_DIR=/run/user/$(id -u) export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock
- Option 2: Vor docker compose Befehl:
export XDG_RUNTIME_DIR=/run/user/$(id -u) docker compose -f docker-compose.rootless.yml up -d
- Option 3: In .env Datei (falls Docker Compose es nicht aus Shell liest):
# .env Datei DOCKER_SOCKET_PATH=/run/user/1000/docker.sock# docker-compose.rootless.yml volumes: - ${DOCKER_SOCKET_PATH}:/var/run/docker.sock:ro
Prüfen ob Variable gesetzt ist:
echo $XDG_RUNTIME_DIR
# Sollte zeigen: /run/user/1000 (oder ähnlich)traefik-crowdsec:
crowdsecService:/var/log/auth.log→./logs/auth.logtraefikService:/var/log/traefik→./logs/traefikip-updater: Keine Änderung (nur relative Pfade)
pihole:
- Port 53 bleibt gleich (CAP_NET_BIND_SERVICE)
- Keine Änderung nötig
Neue Verzeichnisse erstellen:
# In init-homelab.sh oder separatem Script
if is_rootless; then
# Für traefik-crowdsec
mkdir -p "$DOCKER_BASE_DIR/gateway-management/traefik-crowdsec/logs/traefik"
mkdir -p "$DOCKER_BASE_DIR/gateway-management/traefik-crowdsec/logs/auth"
# ... weitere Services
fiOder: Automatisch beim ersten Start erstellen
# In docker.sh vor docker compose up
if [ "$DOCKER_MODE" = "rootless" ]; then
# Erstelle Log-Verzeichnisse falls nötig
create_log_directories "$docker_dir"
fiAnpassung: docker-scripts/lib/core/imports.sh
# Core modules
CORE_MODULES=(
"containers.sh"
"path.sh"
"docker-mode.sh" # NEU
)Phase 7.1.1: Vorbereitung
- Neue Module erstellen (
docker-mode.sh) - Integration in
docker.sh - Integration in
imports.sh - Testing mit einem Service (z.B. cloudflare-companion)
Phase 7.1.2: Migration Services
- cloudflare-companion (einfachster Fall - nur Docker Socket)
- portainer (einfach - nur Docker Socket)
- watchtower (einfach - nur Docker Socket)
- traefik-crowdsec (komplex - Docker Socket + Logs)
- pihole (optional - nur Port, aber CAP_NET_BIND_SERVICE)
Phase 7.1.3: Dokumentation
- README aktualisieren
- Migration-Guide erstellen
- Troubleshooting-Section
Fallback-Mechanismus:
get_compose_file() {
# ... Erkennung ...
# Wenn spezifische Datei nicht existiert, Fallback auf docker-compose.yml
if [ -f "$service_dir/$COMPOSE_FILE" ]; then
echo "$COMPOSE_FILE"
elif [ -f "$service_dir/docker-compose.yml" ]; then
echo "docker-compose.yml" # Fallback
else
return 1
fi
}Verhalten:
- Service hat nur
docker-compose.yml→ funktioniert weiterhin - Service hat
docker-compose.rootless.yml→ wird automatisch verwendet wenn rootless - Service hat
docker-stack.yml→ wird automatisch verwendet wenn Swarm aktiv
Test 1: Rootful Docker
# Prüfen: docker-compose.yml wird verwendet
detect_docker_mode # → "rootful"
get_compose_file "$docker_dir" # → "docker-compose.yml"
# Container startet mit docker-compose.ymlTest 2: Rootless Docker
# Prüfen: docker-compose.rootless.yml wird verwendet
detect_docker_mode # → "rootless"
get_compose_file "$docker_dir" # → "docker-compose.rootless.yml"
# Container startet mit docker-compose.rootless.ymlTest 3: Docker Swarm
# Prüfen: docker-stack.yml wird verwendet
detect_docker_mode # → "swarm"
get_compose_file "$docker_dir" # → "docker-stack.yml"
# Stack wird deployed mit docker stack deployTest 4: Service ohne rootless-Variante
# Prüfen: Fallback auf docker-compose.yml
# Service hat nur docker-compose.yml
# Funktioniert weiterhin (rückwärtskompatibel)- cloudflare-companion (minimal, nur Docker Socket)
- portainer (einfach, nur Docker Socket)
- traefik-crowdsec (komplex, Docker Socket + Logs)
docker-scripts/
├── lib/
│ └── core/
│ └── docker-mode.sh # NEU: Docker-Modus-Erkennung
└── modules/
└── services/
└── docker.sh # ANGEPASST: Integration
docker/
└── gateway-management/
└── traefik-crowdsec/
├── docker-compose.yml # Rootful
├── docker-compose.rootless.yml # Rootless (NEU)
├── docker-stack.yml # Swarm (unverändert)
├── logs/ # NEU: Für rootless
│ ├── traefik/
│ └── auth.log
├── traefik.env
└── ...
-
docker-mode.sherstellen - Erkennungslogik implementieren
-
get_compose_file()Funktion - Testing der Erkennung
-
docker.shanpassen (start_docker_container) -
docker.shanpassen (restart_docker_container) -
get_stack_name()Funktion - Integration in
imports.sh - Fallback-Mechanismus
- cloudflare-companion:
docker-compose.rootless.ymlerstellen - portainer:
docker-compose.rootless.ymlerstellen - watchtower:
docker-compose.rootless.ymlerstellen - Testing
- traefik-crowdsec:
docker-compose.rootless.ymlerstellen - Log-Verzeichnisse erstellen (
./logs/) - Testing
- Prüfen ob CAP_NET_BIND_SERVICE gesetzt ist
- Dokumentation aktualisieren
- README aktualisieren
- Migration-Guide erstellen
- Troubleshooting-Section
Gesamt: ~9-14 Stunden
- Rootful:
/var/run/docker.sock - Rootless:
${XDG_RUNTIME_DIR}/docker.sock(z.B./run/user/1000/docker.sock)
- Rootful:
/var/log/... - Rootless:
./logs/...(service-relativ)
- Beide: Funktionieren mit
CAP_NET_BIND_SERVICE - Rootless: Braucht
sudo setcap cap_net_bind_service=+ep $(which rootlesskit)
- Beide: Identisch, keine Änderung nötig
✅ Docker-Modus wird automatisch erkannt
✅ Passende Datei wird automatisch ausgewählt
✅ Rootful/Rootless/Swarm funktionieren
✅ Bestehende Services ohne rootless-Variante funktionieren weiter
✅ Dokumentation ist vollständig
✅ Migration ist einfach durchzuführen
-
docker-mode.sherstellen - Integration in
imports.sh - Testing der Erkennung
-
docker.shanpassen -
get_stack_name()Funktion - Testing
- Nur für Services die es brauchen (siehe Status-Liste unten)
- Schrittweise: Einfache zuerst, dann komplexe
- Prüfen welche bereits existieren
- Fehlende erstellen (falls nötig)
Alle Services haben bereits docker-compose.yml:
- ✅ adblocker-management/pihole
- ✅ companion-management/cloudflare
- ✅ dashboard-management/organizr
- ✅ games-management/pufferpanel
- ✅ gateway-management/ddns-updater
- ✅ gateway-management/traefik-crowdsec
- ✅ honeypot-management/tarpit
- ✅ media-management/jellyfin
- ✅ media-management/plex
- ✅ password-management/bitwarden
- ✅ storage-management/owncloud
- ✅ system-management/portainer
- ✅ system-management/watchtower
- ✅ url-management/yourls
- ✅ vpn-management/wireguard
✅ Existiert bereits:
- ✅ adblocker-management/pihole/docker-stack.yml
- ✅ gateway-management/traefik-crowdsec/docker-stack.yml
- ✅ system-management/portainer/docker-stack.yml
❌ Fehlt noch:
- ❌ companion-management/cloudflare/docker-stack.yml (optional - nur wenn Swarm nötig)
- ❌ system-management/watchtower/docker-stack.yml (optional - nur wenn Swarm nötig)
- ❌ Alle anderen Services (nicht kritisch, nur wenn Swarm gewünscht)
Kritisch (müssen erstellt werden):
-
❌ companion-management/cloudflare/docker-compose.rootless.yml
- Grund:
/var/run/docker.sock→${XDG_RUNTIME_DIR}/docker.sock
- Grund:
-
❌ gateway-management/traefik-crowdsec/docker-compose.rootless.yml
- Grund:
/var/run/docker.sock+/var/log/traefik+/var/log/auth.log - Komplex: Log-Verzeichnisse + Docker Socket
- Grund:
-
❌ system-management/portainer/docker-compose.rootless.yml
- Grund:
/var/run/docker.sock→${XDG_RUNTIME_DIR}/docker.sock
- Grund:
-
❌ system-management/watchtower/docker-compose.rootless.yml
- Grund:
/var/run/docker.sock→${XDG_RUNTIME_DIR}/docker.sock
- Grund:
Optional (nur Ports < 1024, aber CAP_NET_BIND_SERVICE sollte reichen):
⚠️ adblocker-management/pihole/docker-compose.rootless.yml- Grund: Port 53 (privileged port)
- Aber: Mit CAP_NET_BIND_SERVICE sollte normale docker-compose.yml funktionieren
- Entscheidung: Erstmal nicht nötig, nur wenn Probleme auftreten
Nicht betroffen (keine Änderung nötig):
- ✅ dashboard-management/organizr (kein Docker Socket, keine System-Pfade)
- ✅ games-management/pufferpanel (kein Docker Socket, keine System-Pfade)
- ✅ gateway-management/ddns-updater (kein Docker Socket, keine System-Pfade)
- ✅ honeypot-management/tarpit (kein Docker Socket, keine System-Pfade)
- ✅ media-management/jellyfin (kein Docker Socket, keine System-Pfade)
- ✅ media-management/plex (kein Docker Socket, keine System-Pfade)
- ✅ password-management/bitwarden (kein Docker Socket, keine System-Pfade)
- ✅ storage-management/owncloud (kein Docker Socket, keine System-Pfade)
- ✅ url-management/yourls (kein Docker Socket, keine System-Pfade)
- ✅ vpn-management/wireguard (kein Docker Socket, keine System-Pfade)
Was zuerst gemacht wird:
- ✅ Docker-Modus-Erkennung (
docker-mode.sh) - NEU erstellen - ✅ Integration (
docker.shanpassen) - ANPASSEN - ✅ docker-compose.rootless.yml - 4 Dateien NEU erstellen:
- cloudflare-companion
- traefik-crowdsec
- portainer
- watchtower
Was bereits existiert:
- ✅ Alle
docker-compose.yml(rootful) - ✅ 3x
docker-stack.yml(pihole, traefik-crowdsec, portainer)
Was optional ist:
⚠️ Weiteredocker-stack.yml(nur wenn Swarm für andere Services gewünscht)⚠️ pihole/docker-compose.rootless.yml(nur wenn Port 53 Probleme macht)
- Review dieses Plans ✅
- Mit Implementierung starten (Schritt 1: docker-mode.sh)
- Iterativ testen (jeder Schritt einzeln)
- Dokumentation parallel (während Implementierung)