Files
Docker-LXC/docker-lxc.sh
T
2026-05-24 08:25:42 +02:00

251 lines
13 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# ==============================================================================
# Proxmox LXC: Debian + Docker + Portainer (optional)
# Aufruf auf dem PVE-Host:
# bash <(curl -fsSL https://your-host/debian-docker-portainer-lxc.sh)
# ==============================================================================
set -euo pipefail
# ── Farben ─────────────────────────────────────────────────────────────────────
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
CYAN='\033[0;36m'; BOLD='\033[1m'; NC='\033[0m'
info() { echo -e "${CYAN}[INFO]${NC} $*"; }
success() { echo -e "${GREEN}[OK]${NC} $*"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
error() { echo -e "${RED}[ERROR]${NC} $*" >&2; exit 1; }
# ── Voraussetzungen prüfen ─────────────────────────────────────────────────────
[[ $EUID -ne 0 ]] && error "Dieses Skript muss als root auf dem Proxmox-Host ausgeführt werden."
command -v pct &>/dev/null || error "'pct' nicht gefunden läuft das Skript auf einem PVE-Host?"
command -v pvesh &>/dev/null || error "'pvesh' nicht gefunden läuft das Skript auf einem PVE-Host?"
# ══════════════════════════════════════════════════════════════════════════════
echo -e "\n${BOLD}╔══════════════════════════════════════════════════════════╗${NC}"
echo -e "${BOLD}║ Proxmox LXC Debian + Docker + Portainer Installer ║${NC}"
echo -e "${BOLD}╚══════════════════════════════════════════════════════════╝${NC}\n"
# ── Standardwerte ──────────────────────────────────────────────────────────────
DEFAULT_CTID=$(pvesh get /cluster/nextid)
DEFAULT_HOSTNAME="debian-docker"
DEFAULT_PASSWORD="ChangeMe123!"
DEFAULT_STORAGE="local-lvm"
DEFAULT_DISK=8 # GB
DEFAULT_RAM=2048 # MB
DEFAULT_SWAP=512 # MB
DEFAULT_CORES=2
DEFAULT_BRIDGE="vmbr0"
DEFAULT_IP="dhcp" # oder z.B. 192.168.1.100/24
DEFAULT_GW="" # Gateway (nur bei statischer IP)
# ── Interaktive Eingabe ────────────────────────────────────────────────────────
ask() {
local prompt="$1" default="$2" var_name="$3"
echo -ne "${BOLD}${prompt}${NC} [${YELLOW}${default}${NC}]: "
read -r input
printf -v "$var_name" '%s' "${input:-$default}"
}
ask_yn() {
local prompt="$1" default="${2:-y}"
echo -ne "${BOLD}${prompt}${NC} [${YELLOW}${default}${NC}]: "
read -r yn
[[ "${yn:-$default}" =~ ^[Jj1Yy] ]]
}
echo -e "${CYAN}── Container-Grundkonfiguration ────────────────────────────${NC}"
ask "Container-ID" "$DEFAULT_CTID" CTID
ask "Hostname" "$DEFAULT_HOSTNAME" HOSTNAME
ask "Root-Passwort" "$DEFAULT_PASSWORD" PASSWORD
ask "Storage" "$DEFAULT_STORAGE" STORAGE
ask "Disk-Größe (GB)" "$DEFAULT_DISK" DISK
ask "RAM (MB)" "$DEFAULT_RAM" RAM
ask "Swap (MB)" "$DEFAULT_SWAP" SWAP
ask "CPU-Kerne" "$DEFAULT_CORES" CORES
ask "Netzwerk-Bridge" "$DEFAULT_BRIDGE" BRIDGE
echo ""
echo -e "${CYAN}── Netzwerk ────────────────────────────────────────────────${NC}"
echo -e " Für DHCP einfach '${YELLOW}dhcp${NC}' eingeben."
echo -e " Für statische IP z.B. '${YELLOW}192.168.1.100/24${NC}'"
ask "IP-Adresse" "$DEFAULT_IP" IP_ADDR
if [[ "$IP_ADDR" != "dhcp" ]]; then
ask "Gateway" "$DEFAULT_GW" GATEWAY
fi
echo ""
echo -e "${CYAN}── Optionale Komponenten ───────────────────────────────────${NC}"
if ask_yn "Portainer CE installieren? (Web-UI für Docker)" "j"; then
INSTALL_PORTAINER=true
ask "Portainer HTTPS-Port" "9443" PORTAINER_PORT
else
INSTALL_PORTAINER=false
fi
if ask_yn "SSH-Zugriff für root aktivieren?" "j"; then
ENABLE_ROOT_SSH=true
else
ENABLE_ROOT_SSH=false
fi
if ask_yn "Unprivilegierten Container erstellen? (empfohlen)" "j"; then
UNPRIVILEGED=1
else
UNPRIVILEGED=0
fi
# ── Zusammenfassung ────────────────────────────────────────────────────────────
echo ""
echo -e "${BOLD}╔══════════════ Zusammenfassung ════════════════╗${NC}"
printf "${BOLD}${NC} %-22s %-20s ${BOLD}${NC}\n" "Container-ID:" "$CTID"
printf "${BOLD}${NC} %-22s %-20s ${BOLD}${NC}\n" "Hostname:" "$HOSTNAME"
printf "${BOLD}${NC} %-22s %-20s ${BOLD}${NC}\n" "Storage:" "$STORAGE"
printf "${BOLD}${NC} %-22s %-20s ${BOLD}${NC}\n" "Disk:" "${DISK} GB"
printf "${BOLD}${NC} %-22s %-20s ${BOLD}${NC}\n" "RAM / Swap:" "${RAM} MB / ${SWAP} MB"
printf "${BOLD}${NC} %-22s %-20s ${BOLD}${NC}\n" "CPU-Kerne:" "$CORES"
printf "${BOLD}${NC} %-22s %-20s ${BOLD}${NC}\n" "Netzwerk:" "$IP_ADDR"
printf "${BOLD}${NC} %-22s %-20s ${BOLD}${NC}\n" "Portainer:" "$( $INSTALL_PORTAINER && echo "Ja (:${PORTAINER_PORT})" || echo "Nein" )"
printf "${BOLD}${NC} %-22s %-20s ${BOLD}${NC}\n" "Root-SSH:" "$( $ENABLE_ROOT_SSH && echo "Ja" || echo "Nein" )"
printf "${BOLD}${NC} %-22s %-20s ${BOLD}${NC}\n" "Unprivilegiert:" "$( [[ $UNPRIVILEGED -eq 1 ]] && echo "Ja" || echo "Nein" )"
echo -e "${BOLD}╚══════════════════════════════════════════════╝${NC}"
echo ""
ask_yn "Jetzt installieren?" "j" || { echo "Abgebrochen."; exit 0; }
# ── Debian-Template herunterladen ──────────────────────────────────────────────
info "Suche aktuelles Debian-LXC-Template …"
TEMPLATE_STORAGE="local"
TEMPLATE=$(pveam available --section system | awk '/debian-1[2-9]/ {print $2}' | sort -V | tail -1)
[[ -z "$TEMPLATE" ]] && error "Kein Debian-Template in der PVE-Datenbank gefunden. 'pveam update' ausführen!"
DOWNLOADED=$(pveam list "$TEMPLATE_STORAGE" 2>/dev/null | awk '{print $1}' | grep -F "$TEMPLATE" || true)
if [[ -z "$DOWNLOADED" ]]; then
info "Lade Template herunter: $TEMPLATE"
pveam download "$TEMPLATE_STORAGE" "$TEMPLATE"
success "Template geladen."
else
success "Template bereits vorhanden: $TEMPLATE"
fi
TEMPLATE_PATH="${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}"
# ── LXC-Container erstellen ────────────────────────────────────────────────────
info "Erstelle LXC-Container $CTID"
NET_CONFIG="name=eth0,bridge=${BRIDGE}"
if [[ "$IP_ADDR" == "dhcp" ]]; then
NET_CONFIG+=",ip=dhcp"
else
NET_CONFIG+=",ip=${IP_ADDR}"
[[ -n "${GATEWAY:-}" ]] && NET_CONFIG+=",gw=${GATEWAY}"
fi
pct create "$CTID" "$TEMPLATE_PATH" \
--hostname "$HOSTNAME" \
--password "$PASSWORD" \
--storage "$STORAGE" \
--rootfs "${STORAGE}:${DISK}" \
--memory "$RAM" \
--swap "$SWAP" \
--cores "$CORES" \
--net0 "$NET_CONFIG" \
--unprivileged "$UNPRIVILEGED" \
--features "keyctl=1,nesting=1" \
--onboot 1 \
--start 0
success "Container $CTID erstellt."
# ── Container starten ──────────────────────────────────────────────────────────
info "Starte Container …"
pct start "$CTID"
sleep 5
# ── Hilfsfunktion: Befehl im Container ausführen ──────────────────────────────
lxc_exec() { pct exec "$CTID" -- bash -c "$*"; }
# ── System aktualisieren ───────────────────────────────────────────────────────
info "System aktualisieren (apt update & upgrade) …"
lxc_exec "apt-get update -qq && apt-get upgrade -y -qq"
lxc_exec "apt-get install -y -qq ca-certificates curl gnupg lsb-release wget"
success "System aktuell."
# ── Docker installieren (offizieller Weg) ─────────────────────────────────────
info "Docker Engine installieren …"
lxc_exec "
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg \
| gpg --dearmor -o /etc/apt/keyrings/docker.gpg --yes
chmod a+r /etc/apt/keyrings/docker.gpg
echo \"deb [arch=\$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/debian \
\$(. /etc/os-release && echo \"\$VERSION_CODENAME\") stable\" \
> /etc/apt/sources.list.d/docker.list
apt-get update -qq
apt-get install -y -qq \
docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin
systemctl enable docker --now
"
success "Docker installiert."
# ── Docker testen ──────────────────────────────────────────────────────────────
info "Docker-Funktionstest …"
if lxc_exec "docker run --rm hello-world" &>/dev/null; then
success "Docker läuft korrekt."
else
warn "Docker-Test fehlgeschlagen bitte manuell prüfen."
fi
# ── Portainer installieren ─────────────────────────────────────────────────────
if $INSTALL_PORTAINER; then
info "Portainer CE installieren (Port ${PORTAINER_PORT}) …"
lxc_exec "
docker volume create portainer_data
docker run -d \
--name portainer \
--restart always \
-p 8000:8000 \
-p ${PORTAINER_PORT}:9443 \
-v /var/run/docker.sock:/var/run/docker.sock \
-v portainer_data:/data \
portainer/portainer-ce:latest
"
success "Portainer CE gestartet."
fi
# ── SSH konfigurieren ──────────────────────────────────────────────────────────
if $ENABLE_ROOT_SSH; then
info "Aktiviere Root-SSH-Login …"
lxc_exec "
sed -i 's/^#*PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config
sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication yes/' /etc/ssh/sshd_config
systemctl restart ssh
"
success "Root-SSH aktiviert."
fi
# ── Abschluss ──────────────────────────────────────────────────────────────────
CONTAINER_IP=$(pct exec "$CTID" -- hostname -I 2>/dev/null | awk '{print $1}' || echo "unbekannt")
echo ""
echo -e "${BOLD}${GREEN}╔═══════════════════════ Fertig! ═══════════════════════╗${NC}"
echo -e "${GREEN}${NC}"
echo -e "${GREEN}${NC} Container-ID : ${BOLD}${CTID}${NC}"
echo -e "${GREEN}${NC} Hostname : ${BOLD}${HOSTNAME}${NC}"
echo -e "${GREEN}${NC} IP-Adresse : ${BOLD}${CONTAINER_IP}${NC}"
echo -e "${GREEN}${NC}"
echo -e "${GREEN}${NC} Docker : ${BOLD}installiert & aktiv${NC}"
if $INSTALL_PORTAINER; then
echo -e "${GREEN}${NC} Portainer : ${BOLD}https://${CONTAINER_IP}:${PORTAINER_PORT}${NC}"
fi
if $ENABLE_ROOT_SSH; then
echo -e "${GREEN}${NC} SSH : ${BOLD}ssh root@${CONTAINER_IP}${NC}"
fi
echo -e "${GREEN}${NC}"
echo -e "${GREEN}${NC} ${YELLOW}Bitte das Root-Passwort nach dem ersten Login ändern!${NC}"
echo -e "${GREEN}${NC}"
echo -e "${BOLD}${GREEN}╚═══════════════════════════════════════════════════════╝${NC}\n"