docker-install.sh aktualisiert

This commit is contained in:
2026-05-26 16:30:54 +02:00
parent 53a76f4dad
commit 7e8e0e90b9
+767 -65
View File
@@ -1,84 +1,786 @@
#!/usr/bin/env bash #!/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 set -euo pipefail
# ------------------------------------------------------------ # ─── Farben & Symbole ────────────────────────────────────────────────────────
# Docker + Docker Compose Plugin Installer for Debian/Ubuntu 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'
if [[ "${EUID}" -ne 0 ]]; then OK="${GREEN}${RESET}"
echo "Bitte als root oder mit sudo ausführen." WARN="${YELLOW}${RESET}"
exit 1 ERR="${RED}${RESET}"
fi INFO="${CYAN}${RESET}"
ARROW="${BLUE}${RESET}"
echo "==> Prüfe Betriebssystem ..." # ─── Globale Variablen ───────────────────────────────────────────────────────
if [[ ! -f /etc/os-release ]]; then SCRIPT_VERSION="2.0.0"
echo "Fehler: /etc/os-release nicht gefunden." LOG_FILE="/var/log/docker-setup.log"
exit 1 DOCKER_GPG_KEY="/etc/apt/keyrings/docker.asc"
fi 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=""
# shellcheck disable=SC1091 # ─── Hilfsfunktionen ─────────────────────────────────────────────────────────
source /etc/os-release
if [[ "${ID}" != "ubuntu" && "${ID}" != "debian" ]]; then log() {
echo "Dieses Skript unterstützt nur Debian und Ubuntu." echo "$(date '+%Y-%m-%d %H:%M:%S') $*" >> "$LOG_FILE" 2>/dev/null || true
echo "Erkanntes System: ${ID}" }
exit 1
fi
ARCH="$(dpkg --print-architecture)" print_banner() {
KEYRING_DIR="/etc/apt/keyrings" echo ""
DOCKER_GPG="${KEYRING_DIR}/docker.asc" echo -e "${BOLD}${BLUE}╔══════════════════════════════════════════════════════════════╗${RESET}"
REPO_FILE="/etc/apt/sources.list.d/docker.list" 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 ""
}
echo "==> Installiere Basis-Pakete ..." print_section() {
apt-get update echo ""
apt-get install -y ca-certificates curl gnupg lsb-release echo -e "${BOLD}${CYAN}── $1 ${DIM}─────────────────────────────────────────────────────${RESET}"
}
echo "==> Erstelle Keyring-Verzeichnis ..." info() { echo -e " ${INFO} $*"; log "INFO: $*"; }
install -m 0755 -d "${KEYRING_DIR}" 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; }
echo "==> Lade Docker GPG-Key ..." # Fortschrittsanzeige
curl -fsSL "https://download.docker.com/linux/${ID}/gpg" -o "${DOCKER_GPG}" step() {
chmod a+r "${DOCKER_GPG}" echo -e "\n ${ARROW} ${BOLD}$*${RESET}"
log "STEP: $*"
}
echo "==> Konfiguriere Docker APT-Repository ..." # Ja/Nein-Abfrage mit konfigurierbarem Standard
echo \ ask_yes_no() {
"deb [arch=${ARCH} signed-by=${DOCKER_GPG}] https://download.docker.com/linux/${ID} \ local prompt="$1"
${VERSION_CODENAME} stable" | tee "${REPO_FILE}" > /dev/null local default="${2:-yes}"
local answer
echo "==> Aktualisiere Paketquellen ..." if [[ "$default" == "yes" ]]; then
apt-get update local hint="[J/n]"
else
local hint="[j/N]"
fi
echo "==> Installiere Docker Engine, CLI, Containerd und Compose Plugin ..." while true; do
apt-get install -y \ echo -en " ${ARROW} ${BOLD}${prompt}${RESET} ${DIM}${hint}${RESET} "
docker-ce \ read -r answer
docker-ce-cli \ answer="${answer:-$default}"
containerd.io \ case "${answer,,}" in
docker-buildx-plugin \ j|ja|y|yes) return 0 ;;
docker-compose-plugin n|nein|no) return 1 ;;
*) warn "Bitte mit j (ja) oder n (nein) antworten." ;;
esac
done
}
echo "==> Aktiviere und starte Docker-Dienst ..." # ─── Root-Prüfung ────────────────────────────────────────────────────────────
systemctl enable docker
systemctl restart docker
# Optional: Benutzer zur docker-Gruppe hinzufügen, falls per sudo gestartet check_root() {
if [[ -n "${SUDO_USER:-}" && "${SUDO_USER}" != "root" ]]; then if [[ $EUID -ne 0 ]]; then
echo "==> Füge Benutzer '${SUDO_USER}' zur docker-Gruppe hinzu ..." die "Dieses Skript muss als root ausgeführt werden. Bitte 'sudo bash $0' verwenden."
usermod -aG docker "${SUDO_USER}" || true fi
echo "HINWEIS: Damit Gruppenrechte greifen, bitte einmal ab- und wieder anmelden." }
fi
echo "==> Installation abgeschlossen." # ─── Hilfe ───────────────────────────────────────────────────────────────────
echo
echo "Installierte Versionen:"
docker --version || true
docker compose version || true
echo print_help() {
echo "Teste Docker ..." cat <<EOF
docker run --rm hello-world || true
echo ${BOLD}Verwendung:${RESET}
echo "Fertig." sudo bash $(basename "$0") [OPTION]
echo "Verwendung von Compose:"
echo " docker compose up -d" ${BOLD}Optionen:${RESET}
(keine) Interaktive Installation von Docker, Docker Compose und optional Portainer
--remove Vollständige Deinstallation aller installierten Komponenten
--help Diese Hilfe anzeigen
${BOLD}Beispiele:${RESET}
sudo bash $(basename "$0")
sudo bash $(basename "$0") --remove
EOF
}
# ─── Betriebssystem erkennen ─────────────────────────────────────────────────
detect_os() {
if [[ ! -f /etc/os-release ]]; then
die "Kann Betriebssystem nicht erkennen /etc/os-release fehlt."
fi
# shellcheck source=/dev/null
source /etc/os-release
DETECTED_OS="${ID:-unknown}"
DETECTED_VERSION="${VERSION_CODENAME:-${VERSION_ID:-unknown}}"
local os_pretty="${PRETTY_NAME:-$ID $VERSION_ID}"
# Prüfen ob Debian-basiert
local supported=false
local base_id="${ID_LIKE:-$ID}"
for id in $ID $base_id; do
case "$id" in
debian|ubuntu|raspbian|linuxmint|pop|elementary|kali|parrot|mx|zorin|deepin|neon)
supported=true
break
;;
esac
done
if ! $supported; then
die "Nicht unterstütztes Betriebssystem: ${os_pretty}. Dieses Skript unterstützt nur Debian-basierte Systeme."
fi
# Für Ubuntu-Derivate den Ubuntu-Codename ermitteln
if [[ "$ID" != "debian" && "$ID" != "ubuntu" ]]; then
if grep -qi ubuntu /etc/os-release 2>/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 "$@"