146 lines
4.5 KiB
Bash
146 lines
4.5 KiB
Bash
#!/usr/bin/env bash
|
||
set -euo pipefail
|
||
|
||
# ===============================
|
||
# 仅使用你指定的 Docker 离线包
|
||
# ===============================
|
||
URL_PRIMARY="https://pub-b69a7194f4ea42fba6aa990c49bded91.r2.dev/xui/dockde12.zip"
|
||
URL_BACKUP="https://freeyx.vps3344.dpdns.org/xui/dockde12.zip"
|
||
|
||
WORKDIR="/root/docker_offline_install"
|
||
ZIP_FILE="$WORKDIR/dockde12.zip"
|
||
|
||
log(){ echo -e "\033[32m[✔]\033[0m $*"; }
|
||
warn(){ echo -e "\033[33m[!]\033[0m $*"; }
|
||
err(){ echo -e "\033[31m[✘]\033[0m $*"; }
|
||
|
||
# ===============================
|
||
# 基础检查
|
||
# ===============================
|
||
[ "$(id -u)" -eq 0 ] || { err "请使用 root 运行"; exit 1; }
|
||
[ "$(uname -m)" = "x86_64" ] || { err "仅支持 x86_64 架构"; exit 1; }
|
||
|
||
# ===============================
|
||
# dpkg / apt 锁等待
|
||
# ===============================
|
||
wait_lock() {
|
||
for i in {1..60}; do
|
||
if fuser /var/lib/dpkg/lock-frontend >/dev/null 2>&1 || \
|
||
fuser /var/lib/dpkg/lock >/dev/null 2>&1 || \
|
||
fuser /var/cache/apt/archives/lock >/dev/null 2>&1; then
|
||
sleep 2
|
||
else
|
||
return
|
||
fi
|
||
done
|
||
err "dpkg/apt 锁长期占用,请稍后再试"
|
||
exit 1
|
||
}
|
||
|
||
# ===============================
|
||
# 环境提示(不强退)
|
||
# ===============================
|
||
if command -v systemd-detect-virt >/dev/null 2>&1; then
|
||
virt=$(systemd-detect-virt || true)
|
||
if [ "$virt" != "none" ] && [ -n "$virt" ]; then
|
||
warn "检测到虚拟化/容器环境:$virt(非特权容器可能无法运行 Docker)"
|
||
fi
|
||
fi
|
||
|
||
# ===============================
|
||
# 准备工具(不涉及 Docker 来源)
|
||
# ===============================
|
||
wait_lock
|
||
apt-get update -y >/dev/null 2>&1 || true
|
||
apt-get install -y curl wget unzip python3 >/dev/null 2>&1 || true
|
||
|
||
# ===============================
|
||
# 停服务 + 清理冲突
|
||
# ===============================
|
||
log "停止旧 Docker / containerd"
|
||
systemctl stop docker >/dev/null 2>&1 || true
|
||
systemctl stop containerd >/dev/null 2>&1 || true
|
||
|
||
log "清理可能冲突的旧包"
|
||
wait_lock
|
||
apt-get remove -y docker.io docker-doc docker-compose podman-docker \
|
||
docker-ce docker-ce-cli containerd containerd.io runc >/dev/null 2>&1 || true
|
||
apt-get purge -y docker.io docker-doc docker-compose podman-docker \
|
||
docker-ce docker-ce-cli containerd containerd.io runc >/dev/null 2>&1 || true
|
||
apt-get autoremove -y >/dev/null 2>&1 || true
|
||
|
||
# containerd 老配置是最大坑,直接备份移走
|
||
if [ -f /etc/containerd/config.toml ]; then
|
||
warn "发现旧 containerd 配置,已备份并移除"
|
||
mv /etc/containerd/config.toml /etc/containerd/config.toml.bak.$(date +%s)
|
||
fi
|
||
|
||
# ===============================
|
||
# 下载离线包(双线路)
|
||
# ===============================
|
||
rm -rf "$WORKDIR"
|
||
mkdir -p "$WORKDIR"
|
||
|
||
log "下载 Docker 离线包(主线路)"
|
||
if ! curl -L -k --retry 3 --connect-timeout 10 -o "$ZIP_FILE" "$URL_PRIMARY"; then
|
||
warn "主线路失败,切换备用线路"
|
||
curl -L -k --retry 3 --connect-timeout 10 -o "$ZIP_FILE" "$URL_BACKUP" \
|
||
|| { err "离线包下载失败"; exit 1; }
|
||
fi
|
||
|
||
[ -s "$ZIP_FILE" ] || { err "下载的 ZIP 文件为空"; exit 1; }
|
||
|
||
# ===============================
|
||
# 解压并整理 deb
|
||
# ===============================
|
||
log "解压离线包"
|
||
cd "$WORKDIR"
|
||
unzip -oq "$ZIP_FILE" || python3 - <<PY
|
||
import zipfile
|
||
zipfile.ZipFile("$ZIP_FILE").extractall("$WORKDIR")
|
||
PY
|
||
|
||
find "$WORKDIR" -name "*.deb" -exec mv -f {} "$WORKDIR" \; 2>/dev/null
|
||
ls *.deb >/dev/null 2>&1 || { err "未找到 deb 文件"; exit 1; }
|
||
|
||
# ===============================
|
||
# 安装(两段式,保证成功率)
|
||
# ===============================
|
||
log "安装 Docker(第一次 dpkg)"
|
||
set +e
|
||
dpkg -i --force-overwrite *.deb >/dev/null 2>&1
|
||
set -e
|
||
|
||
log "修复依赖"
|
||
wait_lock
|
||
apt-get -f install -y || { err "依赖修复失败"; exit 1; }
|
||
|
||
log "重新安装 Docker(第二次 dpkg)"
|
||
dpkg -i --force-overwrite *.deb >/dev/null 2>&1 || { err "dpkg 安装失败"; exit 1; }
|
||
|
||
# ===============================
|
||
# 启动并验证
|
||
# ===============================
|
||
log "启动 Docker"
|
||
systemctl daemon-reload >/dev/null 2>&1 || true
|
||
systemctl unmask docker >/dev/null 2>&1 || true
|
||
systemctl enable docker >/dev/null 2>&1 || true
|
||
systemctl restart docker >/dev/null 2>&1 || true
|
||
sleep 1
|
||
|
||
if docker info >/dev/null 2>&1; then
|
||
log "Docker 安装成功"
|
||
docker --version
|
||
docker compose version >/dev/null 2>&1 && docker compose version
|
||
else
|
||
err "Docker 启动失败"
|
||
journalctl -xeu docker.service | tail -n 30
|
||
exit 1
|
||
fi
|
||
|
||
# ===============================
|
||
# 清理
|
||
# ===============================
|
||
rm -rf "$WORKDIR"
|
||
log "完成"
|