This commit is contained in:
CanbiZ 2025-09-02 21:46:53 +02:00
parent 5aedc07b3c
commit 8086160fbd

View File

@ -2,7 +2,7 @@
# Copyright (c) 2021-2025 community-scripts ORG
# Author: thost96 (thost96) | Co-Author: michelroegl-brunner
# Refactor (q35 + PVE9 virt-customize network fix): MickLesk
# Refactor (q35 + PVE9 virt-customize network fix + robustness): MickLesk
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
set -e
@ -162,9 +162,7 @@ function arch_check() {
function ssh_check() {
if command -v pveversion >/dev/null 2>&1 && [ -n "${SSH_CLIENT:+x}" ]; then
if whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "SSH DETECTED" --yesno "It's suggested to use the Proxmox shell instead of SSH, since SSH can create issues while gathering variables. Proceed anyway?" 10 62; then
:
else
if whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "SSH DETECTED" --yesno "It's suggested to use the Proxmox shell instead of SSH, since SSH can create issues while gathering variables. Proceed anyway?" 10 62; then :; else
clear
exit
fi
@ -224,7 +222,6 @@ function advanced_settings() {
else exit-script; fi
done
# Force q35 like our other scripts
FORMAT=",efitype=4m"
echo -e "${CONTAINERTYPE}${BOLD}${DGN}Machine Type: ${BGN}q35${CL}"
@ -241,11 +238,11 @@ function advanced_settings() {
if DISK_CACHE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "DISK CACHE" --radiolist "Choose" --cancel-button Exit-Script 10 58 2 \
"0" "None (Default)" ON "1" "Write Through" OFF 3>&1 1>&2 2>&3); then
if [ "$DISK_CACHE" = "1" ]; then
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Cache: ${BGN}Write Through${CL}"
DISK_CACHE="cache=writethrough,"
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Cache: ${BGN}Write Through${CL}"
else
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Cache: ${BGN}None${CL}"
DISK_CACHE=""
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Cache: ${BGN}None${CL}"
fi
else exit-script; fi
@ -257,11 +254,11 @@ function advanced_settings() {
if CPU_TYPE1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "CPU MODEL" --radiolist "Choose" --cancel-button Exit-Script 10 58 2 \
"0" "KVM64 (Default)" ON "1" "Host" OFF 3>&1 1>&2 2>&3); then
if [ "$CPU_TYPE1" = "1" ]; then
echo -e "${OS}${BOLD}${DGN}CPU Model: ${BGN}Host${CL}"
CPU_TYPE=" -cpu host"
echo -e "${OS}${BOLD}${DGN}CPU Model: ${BGN}Host${CL}"
else
echo -e "${OS}${BOLD}${DGN}CPU Model: ${BGN}KVM64${CL}"
CPU_TYPE=""
echo -e "${OS}${BOLD}${DGN}CPU Model: ${BGN}KVM64${CL}"
fi
else exit-script; fi
@ -369,7 +366,6 @@ function choose_os() {
}
PVE_VER=$(pveversion | awk -F'/' '{print $2}' | cut -d'-' -f1 | cut -d'.' -f1)
if [ "$PVE_VER" -eq 8 ]; then
INSTALL_MODE="direct"
elif [ "$PVE_VER" -eq 9 ]; then
@ -409,13 +405,22 @@ fi
msg_ok "Using ${CL}${BL}$STORAGE${CL} ${GN}for Storage Location."
msg_ok "Virtual Machine ID is ${CL}${BL}$VMID${CL}."
# ---------- Download Debian Cloud Image ----------
# ---------- Download Cloud Image ----------
choose_os
msg_info "Retrieving Cloud Image for $var_os $var_version"
curl -f#SL -o "$(basename "$URL")" "$URL"
curl --retry 30 --retry-delay 3 --retry-connrefused -fSL -o "$(basename "$URL")" "$URL"
FILE=$(basename "$URL")
msg_ok "Downloaded ${CL}${BL}${FILE}${CL}"
# Ubuntu RAW → qcow2
if [[ "$FILE" == *.img ]]; then
msg_info "Converting RAW image to qcow2"
qemu-img convert -O qcow2 "$FILE" "${FILE%.img}.qcow2"
rm -f "$FILE"
FILE="${FILE%.img}.qcow2"
msg_ok "Converted to ${CL}${BL}${FILE}${CL}"
fi
# ---------- Ensure libguestfs-tools ----------
if ! command -v virt-customize &>/dev/null; then
msg_info "Installing libguestfs-tools on host"
@ -424,8 +429,7 @@ if ! command -v virt-customize &>/dev/null; then
msg_ok "Installed libguestfs-tools"
fi
# ---------- Decide distro codename & Docker repo base from chosen URL ----------
# (choose_os must have set $URL and we've downloaded $FILE above; we only need URL to derive codename)
# ---------- Decide distro codename & Docker repo base ----------
if [[ "$URL" == *"/bookworm/"* || "$FILE" == *"debian-12-"* ]]; then
CODENAME="bookworm"
DOCKER_BASE="https://download.docker.com/linux/debian"
@ -439,24 +443,22 @@ else
CODENAME="bookworm"
DOCKER_BASE="https://download.docker.com/linux/debian"
fi
# ---------- Detect PVE major version and select install mode ----------
PVE_MAJ=$(pveversion | awk -F'/' '{print $2}' | cut -d'-' -f1 | cut -d'.' -f1)
if [ "$PVE_MAJ" -eq 8 ]; then
INSTALL_MODE="direct" # fast path: install Docker directly into image
else
INSTALL_MODE="firstboot" # robust path for PVE9: install Docker at first boot inside guest
# Map Debian trixie → bookworm (Docker-Repo oft später)
REPO_CODENAME="$CODENAME"
if [[ "$DOCKER_BASE" == *"linux/debian"* && "$CODENAME" == "trixie" ]]; then
REPO_CODENAME="bookworm"
fi
# ---------- Detect PVE major version (again; independent var) ----------
PVE_MAJ=$(pveversion | awk -F'/' '{print $2}' | cut -d'-' -f1 | cut -d'.' -f1)
if [ "$PVE_MAJ" -eq 8 ]; then INSTALL_MODE="direct"; else INSTALL_MODE="firstboot"; fi
# ---------- Optional: allow manual override ----------
if whiptail --backtitle "Proxmox VE Helper Scripts" --title "Docker Installation Mode" \
--yesno "Detected PVE ${PVE_MAJ}. Use ${INSTALL_MODE^^} mode?\n\nYes = ${INSTALL_MODE^^}\nNo = Switch to the other mode" 11 70; then
: # keep detected mode
else
--yesno "Detected PVE ${PVE_MAJ}. Use ${INSTALL_MODE^^} mode?\n\nYes = ${INSTALL_MODE^^}\nNo = Switch to the other mode" 11 70; then :; else
if [ "$INSTALL_MODE" = "direct" ]; then INSTALL_MODE="firstboot"; else INSTALL_MODE="direct"; fi
fi
# ---------- PVE8: Direct install into image via virt-customize ----------
# ---------- PVE8: Direct install into image via virt-customize ----------
if [ "$INSTALL_MODE" = "direct" ]; then
msg_info "Injecting Docker directly into image (${CODENAME}, $(basename "$DOCKER_BASE"))"
@ -465,18 +467,19 @@ if [ "$INSTALL_MODE" = "direct" ]; then
--run-command "install -m 0755 -d /etc/apt/keyrings" \
--run-command "curl -fsSL ${DOCKER_BASE}/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg" \
--run-command "chmod a+r /etc/apt/keyrings/docker.gpg" \
--run-command "echo 'deb [arch=\$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] ${DOCKER_BASE} ${CODENAME} stable' > /etc/apt/sources.list.d/docker.list" \
--run-command "echo 'deb [arch=\$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] ${DOCKER_BASE} ${REPO_CODENAME} stable' > /etc/apt/sources.list.d/docker.list" \
--run-command "apt-get update -qq" \
--run-command "apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin" \
--run-command "systemctl enable docker" \
--run-command "systemctl enable qemu-guest-agent"
--run-command "systemctl enable qemu-guest-agent" >/dev/null
# ensure PATH in the guest for root (non-login shells, qm terminal, etc.)
--run-command "sed -i 's#^ENV_SUPATH.*#ENV_SUPATH PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin#' /etc/login.defs || true" \
# PATH-Fix separat
virt-customize -q -a "${FILE}" \
--run-command "sed -i 's#^ENV_SUPATH.*#ENV_SUPATH PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin#' /etc/login.defs || true" \
--run-command "sed -i 's#^ENV_PATH.*#ENV_PATH PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin#' /etc/login.defs || true" \
--run-command "printf 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\n' >/etc/environment" \
--run-command "grep -q 'export PATH=' /root/.bashrc || echo 'export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' >> /root/.bashrc" \
>/dev/null
--run-command "grep -q 'export PATH=' /root/.bashrc || echo 'export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' >> /root/.bashrc" >/dev/null
msg_ok "Docker injected into image"
fi
@ -491,25 +494,12 @@ set -euxo pipefail
LOG=/var/log/firstboot-docker.log
exec >>"$LOG" 2>&1
mark_done() {
mkdir -p /var/lib/firstboot
date > /var/lib/firstboot/docker.done
}
retry() {
local tries=$1; shift
local n=0
until "$@"; do
n=$((n+1))
if [ "$n" -ge "$tries" ]; then return 1; fi
sleep 5
done
}
mark_done() { mkdir -p /var/lib/firstboot; date > /var/lib/firstboot/docker.done; }
retry() { local t=$1; shift; local n=0; until "$@"; do n=$((n+1)); [ "$n" -ge "$t" ] && return 1; sleep 5; done; }
wait_network() {
# DNS + HTTPS reachability
retry 30 getent hosts deb.debian.org || retry 30 getent hosts archive.ubuntu.com
retry 30 bash -c 'curl -fsS https://download.docker.com/ >/dev/null'
retry 60 getent hosts deb.debian.org || retry 60 getent hosts archive.ubuntu.com
retry 60 bash -lc 'curl -fsS https://download.docker.com/ >/dev/null'
}
fix_path() {
@ -522,37 +512,36 @@ fix_path() {
main() {
export DEBIAN_FRONTEND=noninteractive
mkdir -p /etc/apt/apt.conf.d
printf 'Acquire::Retries "10";\nAcquire::http::Timeout "60";\nAcquire::https::Timeout "60";\n' >/etc/apt/apt.conf.d/80-retries-timeouts
wait_network
# Distro erkennen -> Codename + Docker-Repo
. /etc/os-release
CODENAME="${VERSION_CODENAME:-bookworm}"
case "$ID" in
ubuntu) DOCKER_BASE="https://download.docker.com/linux/ubuntu" ;;
debian|*) DOCKER_BASE="https://download.docker.com/linux/debian" ;;
esac
REPO_CODENAME="$CODENAME"
if [ "$ID" = "debian" ] && [ "$CODENAME" = "trixie" ]; then REPO_CODENAME="bookworm"; fi
# Basispakete mit Retries
retry 10 apt-get update -qq
retry 5 apt-get install -y ca-certificates curl gnupg qemu-guest-agent apt-transport-https lsb-release software-properties-common
retry 20 apt-get update -qq
retry 10 apt-get install -y ca-certificates curl gnupg qemu-guest-agent apt-transport-https lsb-release software-properties-common
# Docker GPG + Repo
install -m 0755 -d /etc/apt/keyrings
curl -fsSL "${DOCKER_BASE}/gpg" | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] ${DOCKER_BASE} ${CODENAME} stable" > /etc/apt/sources.list.d/docker.list
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] ${DOCKER_BASE} ${REPO_CODENAME} stable" > /etc/apt/sources.list.d/docker.list
retry 10 apt-get update -qq
retry 5 apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
retry 20 apt-get update -qq
retry 10 apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
systemctl enable --now qemu-guest-agent || true
systemctl enable --now docker
# PATH sicherstellen
fix_path
# Erfolg validieren
command -v docker >/dev/null
systemctl is-active --quiet docker
@ -575,13 +564,13 @@ Type=oneshot
ExecStart=/usr/local/sbin/firstboot-docker.sh
Restart=on-failure
RestartSec=10s
TimeoutStartSec=0
RemainAfterExit=no
[Install]
WantedBy=multi-user.target
EOUNIT
# hostname + machine-id reset for cloud-init style behaviour
echo "$HN" >firstboot/hostname
virt-customize -q -a "${FILE}" \
@ -592,6 +581,7 @@ EOUNIT
--run-command "systemctl enable firstboot-docker.service" \
--run-command "echo -n > /etc/machine-id" \
--run-command "truncate -s 0 /etc/hostname && mv /etc/hostname /etc/hostname.orig && echo '${HN}' >/etc/hostname" >/dev/null
msg_ok "First-boot Docker installer injected"
fi
@ -611,11 +601,7 @@ msg_ok "Created VM shell"
# ---------- Import disk ----------
msg_info "Importing disk into storage ($STORAGE)"
if qm disk import --help >/dev/null 2>&1; then
IMPORT_CMD=(qm disk import)
else
IMPORT_CMD=(qm importdisk)
fi
if qm disk import --help >/dev/null 2>&1; then IMPORT_CMD=(qm disk import); else IMPORT_CMD=(qm importdisk); fi
IMPORT_OUT="$("${IMPORT_CMD[@]}" "$VMID" "${FILE}" "$STORAGE" --format qcow2 2>&1 || true)"
DISK_REF="$(printf '%s\n' "$IMPORT_OUT" | sed -n "s/.*successfully imported disk '\([^']\+\)'.*/\1/p" | tr -d "\r\"'")"
[[ -z "$DISK_REF" ]] && DISK_REF="$(pvesm list "$STORAGE" | awk -v id="$VMID" '$5 ~ ("vm-"id"-disk-") {print $1":"$5}' | sort | tail -n1)"