#!/usr/bin/env bash # ============================================================================= # docker-setup.sh # Docker + Docker Compose (+ optional Portainer) Installer / Uninstaller # Unterstützte Systeme: Debian, Ubuntu (und deren Derivate) # Zeitlos durch Verwendung der offiziellen Docker-Installationsmethode # ============================================================================= # Verwendung: # sudo bash docker-setup.sh → Interaktive Installation # sudo bash docker-setup.sh --remove → Vollständige Deinstallation # sudo bash docker-setup.sh --help → Hilfe anzeigen # ============================================================================= set -euo pipefail # ─── Farben & Symbole ──────────────────────────────────────────────────────── RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' BOLD='\033[1m' DIM='\033[2m' RESET='\033[0m' OK="${GREEN}✔${RESET}" WARN="${YELLOW}⚠${RESET}" ERR="${RED}✖${RESET}" INFO="${CYAN}ℹ${RESET}" ARROW="${BLUE}➜${RESET}" # ─── Globale Variablen ─────────────────────────────────────────────────────── SCRIPT_VERSION="2.0.0" LOG_FILE="/var/log/docker-setup.log" DOCKER_GPG_KEY="/etc/apt/keyrings/docker.asc" DOCKER_REPO_FILE="/etc/apt/sources.list.d/docker.list" PORTAINER_VOLUME="portainer_data" PORTAINER_CONTAINER="portainer" INSTALL_PORTAINER="yes" ACTION="install" DETECTED_ENV="" DETECTED_OS="" DETECTED_VERSION="" # ─── Hilfsfunktionen ───────────────────────────────────────────────────────── log() { echo "$(date '+%Y-%m-%d %H:%M:%S') $*" >> "$LOG_FILE" 2>/dev/null || true } print_banner() { echo "" echo -e "${BOLD}${BLUE}╔══════════════════════════════════════════════════════════════╗${RESET}" echo -e "${BOLD}${BLUE}║ 🐳 Docker Setup Script v${SCRIPT_VERSION} ║${RESET}" echo -e "${BOLD}${BLUE}║ Docker · Docker Compose · Portainer für Debian/Ubuntu ║${RESET}" echo -e "${BOLD}${BLUE}╚══════════════════════════════════════════════════════════════╝${RESET}" echo "" } print_section() { echo "" echo -e "${BOLD}${CYAN}── $1 ${DIM}─────────────────────────────────────────────────────${RESET}" } info() { echo -e " ${INFO} $*"; log "INFO: $*"; } success() { echo -e " ${OK} $*"; log "OK: $*"; } warn() { echo -e " ${WARN} ${YELLOW}$*${RESET}"; log "WARN: $*"; } error() { echo -e " ${ERR} ${RED}$*${RESET}"; log "ERROR: $*"; } die() { error "$*"; exit 1; } # Fortschrittsanzeige step() { echo -e "\n ${ARROW} ${BOLD}$*${RESET}" log "STEP: $*" } # Ja/Nein-Abfrage mit konfigurierbarem Standard ask_yes_no() { local prompt="$1" local default="${2:-yes}" local answer if [[ "$default" == "yes" ]]; then local hint="[J/n]" else local hint="[j/N]" fi while true; do echo -en " ${ARROW} ${BOLD}${prompt}${RESET} ${DIM}${hint}${RESET} " read -r answer answer="${answer:-$default}" case "${answer,,}" in j|ja|y|yes) return 0 ;; n|nein|no) return 1 ;; *) warn "Bitte mit j (ja) oder n (nein) antworten." ;; esac done } # ─── Root-Prüfung ──────────────────────────────────────────────────────────── check_root() { if [[ $EUID -ne 0 ]]; then die "Dieses Skript muss als root ausgeführt werden. Bitte 'sudo bash $0' verwenden." fi } # ─── Hilfe ─────────────────────────────────────────────────────────────────── print_help() { cat </dev/null; then DETECTED_OS="ubuntu" else DETECTED_OS="debian" fi fi info "Betriebssystem erkannt: ${BOLD}${os_pretty}${RESET}" log "OS: $os_pretty | ID: $DETECTED_OS | Codename: $DETECTED_VERSION" } # ─── Umgebung erkennen (Proxmox, Virtualmin, etc.) ─────────────────────────── detect_environment() { DETECTED_ENV="standalone" # Proxmox erkennen if [[ -f /etc/pve/pve-root-ca.pem ]] || command -v pvesh &>/dev/null 2>&1 || \ [[ -d /etc/pve ]] || grep -qi "proxmox" /etc/os-release 2>/dev/null; then DETECTED_ENV="proxmox" # Virtuozzo / OpenVZ LXC elif [[ -f /proc/vz/veinfo ]] || [[ -d /proc/vz ]]; then DETECTED_ENV="openvz" # Virtualmin erkennen elif [[ -f /etc/webmin/virtualmin-nginx/config ]] || \ [[ -f /usr/share/webmin/virtual-server/config ]] || \ command -v virtualmin &>/dev/null 2>&1; then DETECTED_ENV="virtualmin" # Plesk erkennen elif command -v plesk &>/dev/null 2>&1 || [[ -d /opt/psa ]]; then DETECTED_ENV="plesk" # cPanel erkennen elif command -v whmapi1 &>/dev/null 2>&1 || [[ -d /usr/local/cpanel ]]; then DETECTED_ENV="cpanel" # Systemd-nspawn Container elif systemd-detect-virt --container 2>/dev/null | grep -q "systemd-nspawn"; then DETECTED_ENV="nspawn" # Docker-in-Docker elif [[ -f /.dockerenv ]]; then DETECTED_ENV="docker" fi } # ─── Umgebungs-Infoboxen ───────────────────────────────────────────────────── show_environment_info() { case "$DETECTED_ENV" in proxmox) echo "" echo -e "${BOLD}${YELLOW}╔══════════════════════════════════════════════════════════════╗${RESET}" echo -e "${BOLD}${YELLOW}║ ⚠ PROXMOX UMGEBUNG ERKANNT ⚠ ║${RESET}" echo -e "${BOLD}${YELLOW}╠══════════════════════════════════════════════════════════════╣${RESET}" echo -e "${YELLOW}║ ║${RESET}" echo -e "${YELLOW}║ Docker wird auf einem Proxmox-Host oder in einer Proxmox- ║${RESET}" echo -e "${YELLOW}║ VM/LXC installiert. Bitte beachte folgendes: ║${RESET}" echo -e "${YELLOW}║ ║${RESET}" echo -e "${YELLOW}║ ${BOLD}Empfehlung: Installation in einer VM (KVM), nicht im Host${RESET}${YELLOW} ║${RESET}" echo -e "${YELLOW}║ ║${RESET}" echo -e "${YELLOW}║ Bei LXC-Containern: ║${RESET}" echo -e "${YELLOW}║ • Container muss 'privilegiert' sein ODER ║${RESET}" echo -e "${YELLOW}║ 'nesting=1' und 'keyctl=1' in den Features haben ║${RESET}" echo -e "${YELLOW}║ • Kernel-Module (overlay, ip_tables) müssen verfügbar sein ║${RESET}" echo -e "${YELLOW}║ • Im Proxmox-GUI: Datacenter → Node → CT → Options ║${RESET}" echo -e "${YELLOW}║ → Features: Nesting + keyctl aktivieren ║${RESET}" echo -e "${YELLOW}║ ║${RESET}" echo -e "${YELLOW}║ Proxmox-Host selbst: ║${RESET}" echo -e "${YELLOW}║ • Möglich, aber nicht empfohlen (Ressourcenkonflikte) ║${RESET}" echo -e "${YELLOW}║ • cgroup v2 kann Probleme verursachen ║${RESET}" echo -e "${YELLOW}║ ║${RESET}" echo -e "${BOLD}${YELLOW}╚══════════════════════════════════════════════════════════════╝${RESET}" echo "" ask_yes_no "Trotzdem fortfahren?" "yes" || { info "Abgebrochen."; exit 0; } ;; virtualmin) echo "" echo -e "${BOLD}${CYAN}╔══════════════════════════════════════════════════════════════╗${RESET}" echo -e "${BOLD}${CYAN}║ ℹ VIRTUALMIN UMGEBUNG ERKANNT ℹ ║${RESET}" echo -e "${BOLD}${CYAN}╠══════════════════════════════════════════════════════════════╣${RESET}" echo -e "${CYAN}║ ║${RESET}" echo -e "${CYAN}║ Virtualmin (Webmin) wurde erkannt. Hinweise: ║${RESET}" echo -e "${CYAN}║ ║${RESET}" echo -e "${CYAN}║ • Docker läuft problemlos neben Virtualmin ║${RESET}" echo -e "${CYAN}║ • Port-Konflikte prüfen: 80, 443, 8080 könnten belegt sein ║${RESET}" echo -e "${CYAN}║ • Firewall-Regeln (ufw/iptables) können Docker-Netz ║${RESET}" echo -e "${CYAN}║ beeinflussen → ggf. 'DOCKER-USER' Chain beachten ║${RESET}" echo -e "${CYAN}║ • Portainer auf Port 9443 (HTTPS) oder 9000 (HTTP) ║${RESET}" echo -e "${CYAN}║ ║${RESET}" echo -e "${BOLD}${CYAN}╚══════════════════════════════════════════════════════════════╝${RESET}" echo "" ;; plesk) echo "" echo -e "${BOLD}${CYAN}╔══════════════════════════════════════════════════════════════╗${RESET}" echo -e "${BOLD}${CYAN}║ ℹ PLESK UMGEBUNG ERKANNT ℹ ║${RESET}" echo -e "${BOLD}${CYAN}╠══════════════════════════════════════════════════════════════╣${RESET}" echo -e "${CYAN}║ ║${RESET}" echo -e "${CYAN}║ Plesk wurde erkannt. Hinweise: ║${RESET}" echo -e "${CYAN}║ • Plesk hat eine eigene Docker-Erweiterung ║${RESET}" echo -e "${CYAN}║ • Manuelle Installation möglich, aber Konflikte prüfen ║${RESET}" echo -e "${CYAN}║ • Port-Konflikte möglich: 80, 443, 8443, 8880 ║${RESET}" echo -e "${CYAN}║ ║${RESET}" echo -e "${BOLD}${CYAN}╚══════════════════════════════════════════════════════════════╝${RESET}" echo "" ;; openvz) echo "" echo -e "${BOLD}${RED}╔══════════════════════════════════════════════════════════════╗${RESET}" echo -e "${BOLD}${RED}║ ✖ OPENVZ/VIRTUOZZO ERKANNT ✖ ║${RESET}" echo -e "${BOLD}${RED}╠══════════════════════════════════════════════════════════════╣${RESET}" echo -e "${RED}║ ║${RESET}" echo -e "${RED}║ OpenVZ/Virtuozzo-Container werden erkannt. ║${RESET}" echo -e "${RED}║ Docker ist in OpenVZ-Containern NICHT unterstützt, ║${RESET}" echo -e "${RED}║ da der Host-Kernel geteilt wird und die nötigen ║${RESET}" echo -e "${RED}║ Kernel-Features (namespaces, cgroups) fehlen. ║${RESET}" echo -e "${RED}║ ║${RESET}" echo -e "${RED}║ Empfehlung: KVM/QEMU-VM oder Bare-Metal verwenden. ║${RESET}" echo -e "${RED}║ ║${RESET}" echo -e "${BOLD}${RED}╚══════════════════════════════════════════════════════════════╝${RESET}" echo "" ask_yes_no "Trotzdem versuchen? (wird wahrscheinlich fehlschlagen)" "no" || { info "Abgebrochen."; exit 0; } ;; docker) warn "Docker-in-Docker erkannt. Funktioniert, aber nicht empfohlen für Produktion." ;; esac } # ─── Systemvoraussetzungen prüfen ──────────────────────────────────────────── check_prerequisites() { print_section "Systemprüfung" # Architektur prüfen local arch arch=$(uname -m) case "$arch" in x86_64|aarch64|armv7l|s390x) success "Architektur unterstützt: ${arch}" ;; *) die "Nicht unterstützte Architektur: ${arch}" ;; esac # Kernel-Version prüfen (mindestens 3.10 für Docker) local kernel kernel=$(uname -r) local kernel_major kernel_major=$(echo "$kernel" | cut -d. -f1) local kernel_minor kernel_minor=$(echo "$kernel" | cut -d. -f2) if (( kernel_major > 4 )) || (( kernel_major == 4 && kernel_minor >= 0 )) || \ (( kernel_major == 3 && kernel_minor >= 10 )); then success "Kernel-Version ausreichend: ${kernel}" else warn "Kernel ${kernel} ist sehr alt. Docker benötigt mindestens 3.10." fi # Internetverbindung testen if curl -fsS --max-time 10 https://download.docker.com/linux/ > /dev/null 2>&1; then success "Internetverbindung zu download.docker.com vorhanden" else die "Keine Verbindung zu download.docker.com. Bitte Netzwerk und Firewall prüfen." fi # Systemd prüfen if command -v systemctl &>/dev/null && systemctl is-system-running &>/dev/null; then success "Systemd verfügbar" else warn "Systemd nicht verfügbar oder nicht aktiv. Docker-Autostart ggf. manuell konfigurieren." fi # Freier Speicherplatz (mindestens 2 GB) local free_gb free_gb=$(df -BG / | awk 'NR==2 {gsub("G",""); print $4}') if (( free_gb >= 2 )); then success "Freier Speicherplatz: ${free_gb}GB" else warn "Weniger als 2GB freier Speicherplatz (${free_gb}GB). Installation möglicherweise fehlerhaft." fi } # ─── Abhängigkeiten installieren ───────────────────────────────────────────── install_dependencies() { print_section "Abhängigkeiten installieren" step "Paketliste aktualisieren" apt-get update -qq success "Paketliste aktualisiert" step "Benötigte Pakete installieren" apt-get install -y -qq \ ca-certificates \ curl \ gnupg \ lsb-release \ apt-transport-https \ software-properties-common \ >/dev/null 2>&1 success "Abhängigkeiten installiert" } # ─── Docker Repository einrichten ──────────────────────────────────────────── setup_docker_repo() { print_section "Docker Repository einrichten" step "Docker GPG-Schlüssel herunterladen" install -m 0755 -d /etc/apt/keyrings curl -fsSL "https://download.docker.com/linux/${DETECTED_OS}/gpg" \ -o "$DOCKER_GPG_KEY" chmod a+r "$DOCKER_GPG_KEY" success "GPG-Schlüssel installiert: ${DOCKER_GPG_KEY}" step "Docker Repository hinzufügen" # Zeitlos: Immer den aktuellen Codename verwenden local codename codename=$(. /etc/os-release && echo "${VERSION_CODENAME}") # Fallback falls kein Codename verfügbar (z.B. Rolling-Release-Derivate) if [[ -z "$codename" ]]; then codename=$(lsb_release -cs 2>/dev/null || echo "stable") warn "Kein Versionsname gefunden, verwende: ${codename}" fi local arch arch=$(dpkg --print-architecture) echo "deb [arch=${arch} signed-by=${DOCKER_GPG_KEY}] \ https://download.docker.com/linux/${DETECTED_OS} ${codename} stable" \ > "$DOCKER_REPO_FILE" success "Docker Repository konfiguriert (${DETECTED_OS}/${codename}/${arch})" log "Docker Repo: ${DETECTED_OS} ${codename} ${arch}" } # ─── Docker installieren ───────────────────────────────────────────────────── install_docker() { print_section "Docker installieren" step "Paketliste aktualisieren" apt-get update -qq step "Docker Engine, CLI, Containerd und Compose-Plugin installieren" apt-get install -y -qq \ docker-ce \ docker-ce-cli \ containerd.io \ docker-buildx-plugin \ docker-compose-plugin \ >/dev/null 2>&1 success "Docker Engine installiert" step "Docker-Dienst aktivieren und starten" systemctl enable docker >/dev/null 2>&1 systemctl start docker # Kurz warten bis Docker bereit ist local retries=10 while ! docker info &>/dev/null 2>&1 && (( retries-- > 0 )); do sleep 1 done if docker info &>/dev/null 2>&1; then success "Docker-Daemon läuft" else die "Docker-Daemon konnte nicht gestartet werden. Bitte 'journalctl -xe' prüfen." fi # Versionen ausgeben local docker_version docker_version=$(docker --version 2>/dev/null | awk '{print $3}' | tr -d ',') local compose_version compose_version=$(docker compose version 2>/dev/null | awk '{print $NF}') success "Docker Version: ${docker_version}" success "Docker Compose Version: ${compose_version}" log "Installed: Docker ${docker_version}, Compose ${compose_version}" # Aktuellen Benutzer zur docker-Gruppe hinzufügen if [[ -n "${SUDO_USER:-}" ]] && id "$SUDO_USER" &>/dev/null; then usermod -aG docker "$SUDO_USER" success "Benutzer '${SUDO_USER}' zur Gruppe 'docker' hinzugefügt" warn "Bitte ab- und wieder anmelden oder 'newgrp docker' ausführen, damit die Gruppe aktiv wird." fi } # ─── Docker funktionstest ──────────────────────────────────────────────────── test_docker() { print_section "Docker testen" step "Hello-World Container starten" if docker run --rm hello-world >/dev/null 2>&1; then success "Docker-Test erfolgreich! hello-world Container läuft." else warn "hello-world Test fehlgeschlagen. Docker ist möglicherweise noch nicht vollständig bereit." fi # Temporäres Image aufräumen docker rmi hello-world >/dev/null 2>&1 || true } # ─── Portainer installieren ────────────────────────────────────────────────── install_portainer() { print_section "Portainer installieren" step "Portainer-Volume erstellen" docker volume create "${PORTAINER_VOLUME}" >/dev/null 2>&1 success "Volume '${PORTAINER_VOLUME}' erstellt" step "Portainer CE Container starten" docker run -d \ --name "${PORTAINER_CONTAINER}" \ --restart=always \ -p 8000:8000 \ -p 9443:9443 \ -v /var/run/docker.sock:/var/run/docker.sock \ -v "${PORTAINER_VOLUME}:/data" \ portainer/portainer-ce:latest \ >/dev/null 2>&1 # Warten bis Portainer erreichbar local retries=20 local started=false while (( retries-- > 0 )); do if curl -fsk https://localhost:9443 >/dev/null 2>&1; then started=true break fi sleep 2 done if $started; then success "Portainer läuft!" else warn "Portainer wurde gestartet, ist aber noch nicht über HTTPS erreichbar." warn "Bitte einige Sekunden warten und dann https://SERVER-IP:9443 aufrufen." fi local server_ip server_ip=$(hostname -I 2>/dev/null | awk '{print $1}' || echo "SERVER-IP") echo "" echo -e "${BOLD}${GREEN}╔══════════════════════════════════════════════════════════════╗${RESET}" echo -e "${BOLD}${GREEN}║ 🎉 Portainer erfolgreich installiert! ║${RESET}" echo -e "${BOLD}${GREEN}╠══════════════════════════════════════════════════════════════╣${RESET}" echo -e "${GREEN}║ ║${RESET}" echo -e "${GREEN}║ Portainer Web-UI (HTTPS): ║${RESET}" echo -e "${GREEN}║ ${BOLD}https://${server_ip}:9443${RESET}${GREEN} ║${RESET}" echo -e "${GREEN}║ ║${RESET}" echo -e "${GREEN}║ Beim ersten Aufruf muss ein Admin-Passwort gesetzt werden. ║${RESET}" echo -e "${GREEN}║ Bitte innerhalb von 5 Minuten nach Start aufrufen! ║${RESET}" echo -e "${GREEN}║ ║${RESET}" echo -e "${BOLD}${GREEN}╚══════════════════════════════════════════════════════════════╝${RESET}" echo "" log "Portainer installed: https://${server_ip}:9443" } # ─── Installation abschließen ──────────────────────────────────────────────── finish_install() { echo "" echo -e "${BOLD}${GREEN}╔══════════════════════════════════════════════════════════════╗${RESET}" echo -e "${BOLD}${GREEN}║ 🐳 Installation abgeschlossen! ║${RESET}" echo -e "${BOLD}${GREEN}╠══════════════════════════════════════════════════════════════╣${RESET}" echo -e "${GREEN}║ ║${RESET}" local docker_ver compose_ver docker_ver=$(docker --version 2>/dev/null | awk '{print $3}' | tr -d ',') compose_ver=$(docker compose version 2>/dev/null | awk '{print $NF}') echo -e "${GREEN}║ ${OK} Docker Engine: ${BOLD}${docker_ver}${RESET}${GREEN} ║${RESET}" echo -e "${GREEN}║ ${OK} Docker Compose: ${BOLD}${compose_ver}${RESET}${GREEN} ║${RESET}" if [[ "$INSTALL_PORTAINER" == "yes" ]] && docker ps --filter "name=${PORTAINER_CONTAINER}" --format "{{.Names}}" | grep -q "^${PORTAINER_CONTAINER}$" 2>/dev/null; then echo -e "${GREEN}║ ${OK} Portainer CE: ${BOLD}läuft${RESET}${GREEN} ║${RESET}" fi echo -e "${GREEN}║ ║${RESET}" echo -e "${GREEN}║ Log-Datei: /var/log/docker-setup.log ║${RESET}" echo -e "${GREEN}║ Deinstallieren: sudo bash $(basename "$0") --remove ║${RESET}" echo -e "${GREEN}║ ║${RESET}" echo -e "${BOLD}${GREEN}╚══════════════════════════════════════════════════════════════╝${RESET}" echo "" } # ─── DEINSTALLATION ────────────────────────────────────────────────────────── do_remove() { print_section "Docker vollständig entfernen" echo "" echo -e "${BOLD}${RED}╔══════════════════════════════════════════════════════════════╗${RESET}" echo -e "${BOLD}${RED}║ ⚠ ACHTUNG: DEINSTALLATION ⚠ ║${RESET}" echo -e "${BOLD}${RED}╠══════════════════════════════════════════════════════════════╣${RESET}" echo -e "${RED}║ ║${RESET}" echo -e "${RED}║ Folgendes wird UNWIDERRUFLICH gelöscht: ║${RESET}" echo -e "${RED}║ • Docker Engine, CLI, Containerd, Compose ║${RESET}" echo -e "${RED}║ • Alle Docker-Images, Container, Volumes, Netzwerke ║${RESET}" echo -e "${RED}║ • Portainer (inkl. Konfiguration und Volumes) ║${RESET}" echo -e "${RED}║ • Docker Repository und GPG-Schlüssel ║${RESET}" echo -e "${RED}║ • /var/lib/docker (ALLE Docker-Daten!) ║${RESET}" echo -e "${RED}║ ║${RESET}" echo -e "${RED}║ Nicht gelöscht: ║${RESET}" echo -e "${RED}║ • Daten außerhalb von Docker (Host-Bind-Mounts) ║${RESET}" echo -e "${RED}║ ║${RESET}" echo -e "${BOLD}${RED}╚══════════════════════════════════════════════════════════════╝${RESET}" echo "" if ! ask_yes_no "Bist du SICHER, dass alles gelöscht werden soll?" "no"; then info "Deinstallation abgebrochen." exit 0 fi # Nochmals bestätigen echo -en " ${ARROW} ${BOLD}${RED}Zur Bestätigung 'LÖSCHEN' eingeben:${RESET} " local confirm read -r confirm if [[ "$confirm" != "LÖSCHEN" ]]; then info "Bestätigung fehlgeschlagen. Abgebrochen." exit 0 fi print_section "Portainer entfernen" if docker ps -a --format "{{.Names}}" 2>/dev/null | grep -q "^${PORTAINER_CONTAINER}$"; then step "Portainer Container stoppen und entfernen" docker stop "${PORTAINER_CONTAINER}" >/dev/null 2>&1 || true docker rm "${PORTAINER_CONTAINER}" >/dev/null 2>&1 || true success "Portainer Container entfernt" fi if docker volume ls --format "{{.Name}}" 2>/dev/null | grep -q "^${PORTAINER_VOLUME}$"; then step "Portainer Volume löschen" docker volume rm "${PORTAINER_VOLUME}" >/dev/null 2>&1 || true success "Portainer Volume gelöscht" fi print_section "Alle Docker-Ressourcen bereinigen" if command -v docker &>/dev/null && docker info &>/dev/null 2>&1; then step "Alle Container stoppen" local containers containers=$(docker ps -aq 2>/dev/null) if [[ -n "$containers" ]]; then echo "$containers" | xargs docker stop 2>/dev/null || true echo "$containers" | xargs docker rm -f 2>/dev/null || true success "Container entfernt" else info "Keine Container vorhanden" fi step "Alle Images löschen" local images images=$(docker images -aq 2>/dev/null) if [[ -n "$images" ]]; then echo "$images" | xargs docker rmi -f 2>/dev/null || true success "Images gelöscht" else info "Keine Images vorhanden" fi step "Alle Volumes löschen" local volumes volumes=$(docker volume ls -q 2>/dev/null) if [[ -n "$volumes" ]]; then echo "$volumes" | xargs docker volume rm -f 2>/dev/null || true success "Volumes gelöscht" else info "Keine Volumes vorhanden" fi step "Alle Netzwerke löschen (außer Standard)" docker network prune -f >/dev/null 2>&1 || true success "Netzwerke bereinigt" fi print_section "Docker-Dienst stoppen" step "Docker-Dienste deaktivieren" systemctl stop docker docker.socket containerd 2>/dev/null || true systemctl disable docker docker.socket containerd 2>/dev/null || true success "Docker-Dienste gestoppt und deaktiviert" print_section "Docker-Pakete entfernen" step "Docker-Pakete deinstallieren" apt-get purge -y -qq \ docker-ce \ docker-ce-cli \ containerd.io \ docker-buildx-plugin \ docker-compose-plugin \ docker-compose \ docker.io \ docker-doc \ podman-docker \ 2>/dev/null || true apt-get autoremove -y -qq 2>/dev/null || true success "Docker-Pakete entfernt" print_section "Docker-Daten und Konfiguration löschen" step "Docker-Datenverzeichnis löschen" rm -rf /var/lib/docker 2>/dev/null || true rm -rf /var/lib/containerd 2>/dev/null || true success "/var/lib/docker und /var/lib/containerd gelöscht" step "Docker-Konfiguration löschen" rm -rf /etc/docker 2>/dev/null || true success "/etc/docker gelöscht" step "Repository und GPG-Schlüssel entfernen" rm -f "$DOCKER_REPO_FILE" 2>/dev/null || true rm -f "$DOCKER_GPG_KEY" 2>/dev/null || true # Alte Repo-Formate aufräumen rm -f /etc/apt/sources.list.d/docker*.list 2>/dev/null || true rm -f /etc/apt/trusted.gpg.d/docker*.gpg 2>/dev/null || true rm -f /usr/share/keyrings/docker*.gpg 2>/dev/null || true success "Repository-Dateien entfernt" step "Paketliste aktualisieren" apt-get update -qq 2>/dev/null || true success "Paketliste aktualisiert" step "Benutzergruppe bereinigen" if getent group docker &>/dev/null; then groupdel docker 2>/dev/null || true success "docker-Gruppe entfernt" fi # Systemd-Unit-Dateien bereinigen rm -f /etc/systemd/system/docker*.service 2>/dev/null || true systemctl daemon-reload 2>/dev/null || true echo "" echo -e "${BOLD}${GREEN}╔══════════════════════════════════════════════════════════════╗${RESET}" echo -e "${BOLD}${GREEN}║ 🗑️ Deinstallation abgeschlossen! ║${RESET}" echo -e "${BOLD}${GREEN}╠══════════════════════════════════════════════════════════════╣${RESET}" echo -e "${GREEN}║ ║${RESET}" echo -e "${GREEN}║ Docker, Compose und Portainer wurden vollständig entfernt. ║${RESET}" echo -e "${GREEN}║ Das System ist wieder im ursprünglichen Zustand. ║${RESET}" echo -e "${GREEN}║ ║${RESET}" echo -e "${BOLD}${GREEN}╚══════════════════════════════════════════════════════════════╝${RESET}" echo "" log "Uninstallation complete." } # ─── Hauptprogramm ─────────────────────────────────────────────────────────── main() { # Argumente verarbeiten case "${1:-}" in --remove|-r|remove) ACTION="remove" ;; --help|-h|help) print_banner; print_help; exit 0 ;; "") ACTION="install" ;; *) die "Unbekannte Option: $1. Verwende --help für Hilfe." ;; esac print_banner check_root # Log-Datei initialisieren touch "$LOG_FILE" 2>/dev/null || true log "=== docker-setup.sh v${SCRIPT_VERSION} START === ACTION: ${ACTION}" # Betriebssystem erkennen detect_os if [[ "$ACTION" == "remove" ]]; then do_remove log "=== END ===" exit 0 fi # Umgebung erkennen und Hinweise anzeigen detect_environment show_environment_info # ── Interaktive Konfiguration ── print_section "Installationskonfiguration" echo "" info "Folgende Komponenten werden installiert:" echo -e " ${BOLD}• Docker Engine${RESET} (neueste stabile Version)" echo -e " ${BOLD}• Docker Compose Plugin${RESET} (als 'docker compose' Befehl)" echo -e " ${BOLD}• Docker Buildx Plugin${RESET}" echo "" if ask_yes_no "Soll Portainer CE (Web-UI für Docker) ebenfalls installiert werden?" "yes"; then INSTALL_PORTAINER="yes" info "Portainer CE wird installiert (Port 9443 HTTPS, Port 8000 Edge Agent)" else INSTALL_PORTAINER="no" info "Portainer wird übersprungen" fi # ── Zusammenfassung ── print_section "Installationsübersicht" echo "" echo -e " ${BOLD}System:${RESET} ${DETECTED_OS} (${DETECTED_VERSION})" echo -e " ${BOLD}Umgebung:${RESET} ${DETECTED_ENV}" echo -e " ${BOLD}Docker:${RESET} wird installiert (neueste Version)" echo -e " ${BOLD}Compose:${RESET} wird installiert (Plugin)" echo -e " ${BOLD}Portainer:${RESET} $([ "$INSTALL_PORTAINER" == "yes" ] && echo "wird installiert" || echo "übersprungen")" echo -e " ${BOLD}Log:${RESET} ${LOG_FILE}" echo "" if ! ask_yes_no "Installation jetzt starten?" "yes"; then info "Abgebrochen." exit 0 fi # ── Installation durchführen ── install_dependencies setup_docker_repo install_docker test_docker if [[ "$INSTALL_PORTAINER" == "yes" ]]; then install_portainer fi finish_install log "=== docker-setup.sh END === SUCCESS" } # ─── Skript starten ────────────────────────────────────────────────────────── main "$@"