#!/bin/bash # 使用 set -e 但允许关键步骤有错误处理 set -e # 定义错误处理函数 handle_error() { local exit_code=$? if [[ $exit_code -ne 0 ]]; then echo "❌ 命令执行失败,退出码: $exit_code" return $exit_code fi return 0 } # ============================================================================ # 免责声明 / Disclaimer # ============================================================================ # 本脚本为开源代码,仅供学习和参考使用。 # 使用本脚本前,请务必: # 1. 在本地测试环境充分测试,确认脚本功能符合预期 # 2. 在生产环境使用前,备份重要数据和配置 # 3. 了解脚本执行的操作及其可能产生的影响 # # 虽然脚本经过充分测试,但由于系统环境差异、网络状况等因素, # 无法保证在所有环境下都能完美运行。使用本脚本所产生的任何后果, # 包括但不限于数据丢失、服务中断等,均由使用者自行承担。 # # This script is open source code, provided for learning and reference purposes only. # Before using this script, please: # 1. Fully test in a local test environment to ensure the script functions as expected # 2. Backup important data and configurations before using in production environments # 3. Understand the operations performed by the script and their potential impacts # # Although the script has been thoroughly tested, due to differences in system # environments, network conditions, and other factors, we cannot guarantee # perfect operation in all environments. Any consequences arising from the use # of this script, including but not limited to data loss and service interruptions, # shall be borne by the user. # ============================================================================ # 检查是否安装了 sudo,如果没有则创建一个函数来模拟 sudo if ! command -v sudo &> /dev/null; then echo "⚠️ 未检测到 sudo 命令,将直接使用 root 权限执行命令" # 创建一个模拟 sudo 的函数 sudo() { "$@" } export -f sudo else echo "✅ 检测到 sudo 命令" fi # 恢复 /etc/docker/daemon.json 中与轩辕镜像相关的配置(需交互确认) restore_docker_daemon_config() { local DETECTED_RESTORE_OS DETECTED_RESTORE_OS=$(uname -s 2>/dev/null || echo "Unknown") if [[ "$DETECTED_RESTORE_OS" == "Darwin" ]]; then echo "" echo "❌ macOS 不适用本脚本修改 Linux 路径下的 /etc/docker/daemon.json。" echo "💡 请在 Docker Desktop「设置 → Docker Engine」中编辑或重置配置。" return 1 fi if [[ "$DETECTED_RESTORE_OS" == MINGW* ]] || [[ "$DETECTED_RESTORE_OS" == MSYS* ]] || [[ "$DETECTED_RESTORE_OS" == CYGWIN* ]]; then echo "" echo "❌ 当前为 Windows(Git Bash / MSYS / Cygwin 等),不适用本脚本的 Linux daemon.json 路径。" echo "💡 请在 Docker Desktop 中配置镜像;若在 WSL 内使用 Linux,请在 WSL 内运行本脚本。" return 1 fi if ! [[ -t 0 ]]; then echo "" echo "❌ 恢复配置需在交互式终端中运行(未检测到 TTY),已跳过,未修改任何文件。" return 1 fi echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo " 恢复 Docker 镜像相关配置" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo " 将修改 /etc/docker/daemon.json:可移除轩辕镜像加速、insecure-registries," echo " 以及脚本曾写入的 dns 等。之后拉取镜像将更多依赖官方 registry(视网络而定)。" echo " 若选择「重置为默认 {}」,当前文件中的其它自定义项也会一并清空,请谨慎。" echo " 💡 确认时请完整输入 yes(不区分大小写,YES / Yes 均可);其它输入视为取消。" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" local _confirm local _confirm_lower read -r -p "确认继续恢复?输入 yes 继续,其它任意键取消: " _confirm _confirm_lower=$(printf '%s' "$_confirm" | tr '[:upper:]' '[:lower:]') if [[ "$_confirm_lower" != "yes" ]]; then echo "ℹ️ 已取消,未修改任何文件。" return 0 fi echo "" echo "请选择恢复方式:" echo " 1) 从最新一份 daemon.json.backup.* 恢复(排除 before_restore 备份)" echo " 2) 重置为 Docker 默认(写入空对象 {},不依赖备份)" local sub while true; do read -r -p "请输入 [1/2]: " sub if [[ "$sub" == "1" || "$sub" == "2" ]]; then break fi echo "❌ 无效选择,请输入 1 或 2" done sudo mkdir -p /etc/docker if [[ "$sub" == "1" ]]; then local latest="" while IFS= read -r line; do [[ -z "$line" ]] && continue [[ "$line" == *before_restore* ]] && continue latest="$line" break done < <(ls -1t /etc/docker/daemon.json.backup.* 2>/dev/null || true) if [[ -z "$latest" ]] || [[ ! -f "$latest" ]]; then echo "" echo "❌ 未找到可用的 daemon.json.backup.*(不含 before_restore),无法从历史备份还原。" echo "💡 请重新运行本功能并选择 2) 重置为 {},或手动编辑 /etc/docker/daemon.json。" return 1 fi local ts ts=$(date +%Y%m%d_%H%M%S) if [[ -f /etc/docker/daemon.json ]]; then sudo cp /etc/docker/daemon.json "/etc/docker/daemon.json.backup.before_restore.$ts" echo "✅ 已备份当前配置到 /etc/docker/daemon.json.backup.before_restore.$ts" fi sudo cp "$latest" /etc/docker/daemon.json echo "✅ 已从备份恢复: $latest" else local ts ts=$(date +%Y%m%d_%H%M%S) if [[ -f /etc/docker/daemon.json ]]; then sudo cp /etc/docker/daemon.json "/etc/docker/daemon.json.backup.before_restore.$ts" echo "✅ 已备份当前配置到 /etc/docker/daemon.json.backup.before_restore.$ts" fi local _y read -r -p "确认将 /etc/docker/daemon.json 重置为 {}?[y/N]: " _y if [[ ! "$_y" =~ ^[Yy]$ ]]; then echo "ℹ️ 已取消重置(若已生成 before_restore 备份,可自行保留或删除)。" return 0 fi echo '{}' | sudo tee /etc/docker/daemon.json > /dev/null echo "✅ 已重置为 {}" fi local SCRIPT_RESTORE_SYSTEMD_OK=false if command -v systemctl &>/dev/null; then local PID1_COMM_RESTORE PID1_COMM_RESTORE=$(tr -d '\0' < /proc/1/comm 2>/dev/null || echo "") if [[ "$PID1_COMM_RESTORE" == "systemd" ]] && systemctl show-environment &>/dev/null 2>&1; then SCRIPT_RESTORE_SYSTEMD_OK=true fi fi if [[ "$SCRIPT_RESTORE_SYSTEMD_OK" == "true" ]]; then sudo systemctl daemon-reexec || true sudo systemctl restart docker || true echo "✅ 已尝试重载 Docker 服务" else echo "ℹ️ 未检测到可用 systemd,请手动执行: sudo systemctl restart docker(或按需启动 dockerd)" fi echo "" echo "💡 可通过 docker info 查看 Registry Mirrors 是否已变更。" return 0 } # daemon.json 安全写入:备份、检测敏感项、用户确认、合并写入、重启 Docker # 默认只维护 registry-mirrors(HTTPS 无需 insecure-registries);不写 dns;保留 runtime 等其它字段 DAEMON_DATA_ROOT="" DAEMON_STORAGE_DRIVER="" DAEMON_OTHER_KEYS="" DAEMON_HAS_CUSTOM_CONFIG=false DAEMON_PARSE_ERROR=false _daemon_merge_tools_available() { command -v jq &>/dev/null || command -v python3 &>/dev/null } _daemon_append_other_key() { local key="$1" [[ -z "$key" ]] && return 0 if [[ -n "$DAEMON_OTHER_KEYS" ]]; then DAEMON_OTHER_KEYS="${DAEMON_OTHER_KEYS}, ${key}" else DAEMON_OTHER_KEYS="$key" fi } backup_daemon_json() { sudo mkdir -p /etc/docker if [[ -f /etc/docker/daemon.json ]]; then local ts ts=$(date +%Y%m%d_%H%M%S) sudo cp /etc/docker/daemon.json "/etc/docker/daemon.json.backup.${ts}" echo "✅ 已备份现有配置到 /etc/docker/daemon.json.backup.${ts}" fi } # 无工具可安全覆盖:顶层键 ⊆ {registry-mirrors, insecure-registries} # dns / runtimes 等均视为自定义,禁止无工具整文件写入 read_daemon_sensitive_keys() { DAEMON_DATA_ROOT="" DAEMON_STORAGE_DRIVER="" DAEMON_OTHER_KEYS="" DAEMON_HAS_CUSTOM_CONFIG=false DAEMON_PARSE_ERROR=false if [[ ! -f /etc/docker/daemon.json ]]; then return 0 fi local content content=$(sudo cat /etc/docker/daemon.json 2>/dev/null || echo "{}") if [[ -z "$content" || "$content" == "{}" || "$content" == "null" ]]; then return 0 fi if command -v jq &>/dev/null; then if ! echo "$content" | jq -e 'type == "object"' >/dev/null 2>&1; then DAEMON_PARSE_ERROR=true DAEMON_HAS_CUSTOM_CONFIG=true return 0 fi DAEMON_DATA_ROOT=$(echo "$content" | jq -r '."data-root" // empty' 2>/dev/null) DAEMON_STORAGE_DRIVER=$(echo "$content" | jq -r '."storage-driver" // empty' 2>/dev/null) local key while IFS= read -r key; do [[ -z "$key" ]] && continue case "$key" in registry-mirrors|insecure-registries) ;; data-root|storage-driver) ;; *) _daemon_append_other_key "$key" ;; esac done < <(echo "$content" | jq -r 'keys[]?' 2>/dev/null) elif command -v python3 &>/dev/null; then local py_out py_rc=0 py_out=$(echo "$content" | python3 -c " import json, sys try: d = json.load(sys.stdin) except Exception: print('PARSE_ERROR') sys.exit(0) if not isinstance(d, dict): print('PARSE_ERROR') sys.exit(0) skip = {'registry-mirrors', 'insecure-registries'} for k, v in d.items(): if k == 'data-root': print('DATA_ROOT:' + str(v)) elif k == 'storage-driver': print('STORAGE_DRIVER:' + str(v)) elif k not in skip: print('OTHER:' + k) " 2>/dev/null) || py_rc=$? if [[ $py_rc -ne 0 ]]; then DAEMON_PARSE_ERROR=true DAEMON_HAS_CUSTOM_CONFIG=true return 0 fi while IFS= read -r line; do case "$line" in PARSE_ERROR) DAEMON_PARSE_ERROR=true ;; DATA_ROOT:*) DAEMON_DATA_ROOT="${line#DATA_ROOT:}" ;; STORAGE_DRIVER:*) DAEMON_STORAGE_DRIVER="${line#STORAGE_DRIVER:}" ;; OTHER:*) _daemon_append_other_key "${line#OTHER:}" ;; esac done <<< "$py_out" else # 无 jq/python3:凡出现非白名单键名特征即视为自定义(偏安全,避免漏检 runtimes 等) local key_token while IFS= read -r key_token; do [[ -z "$key_token" ]] && continue case "$key_token" in registry-mirrors|insecure-registries) ;; data-root) DAEMON_DATA_ROOT=$(echo "$content" | grep -oE '"data-root"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed -E 's/.*:[[:space:]]*"([^"]*)".*/\1/') ;; storage-driver) DAEMON_STORAGE_DRIVER=$(echo "$content" | grep -oE '"storage-driver"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed -E 's/.*:[[:space:]]*"([^"]*)".*/\1/') ;; *) _daemon_append_other_key "$key_token" ;; esac done < <(echo "$content" | grep -oE '"[a-zA-Z0-9_-]+"[[:space:]]*:' | sed -E 's/^"([^"]+)".*/\1/' | sort -u) fi if [[ "$DAEMON_PARSE_ERROR" == "true" || -n "$DAEMON_DATA_ROOT" || -n "$DAEMON_STORAGE_DRIVER" || -n "$DAEMON_OTHER_KEYS" ]]; then DAEMON_HAS_CUSTOM_CONFIG=true fi return 0 } _validate_json_object_file() { local file="$1" if command -v jq &>/dev/null; then jq -e 'type == "object"' "$file" >/dev/null 2>&1 return $? fi if command -v python3 &>/dev/null; then python3 -c "import json,sys; d=json.load(open(sys.argv[1],encoding='utf-8')); assert isinstance(d, dict)" "$file" >/dev/null 2>&1 return $? fi # 无工具路径仅写入极简固定结构,跳过二次解析 return 0 } confirm_apply_daemon_config() { read_daemon_sensitive_keys echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo " 即将修改 /etc/docker/daemon.json" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo " 将更新:registry-mirrors(整表替换为本次选择)" echo " 不会写入 insecure-registries(默认 HTTPS,一般无需配置)" echo " 不会修改 dns;其它自定义项(如 runtime)将保留" echo " 若存在历史轩辕 insecure-registries 条目,有合并工具时会清理,并保留您的其它 insecure 项" echo "" echo " ⚠️ 应用配置后将重启 Docker 服务" echo " 运行中的容器会停止,但不会删除镜像和容器数据" echo " 可用 docker start 或 docker compose 重新拉起" echo "" if [[ "$DAEMON_PARSE_ERROR" == "true" ]]; then echo "❌ 现有 /etc/docker/daemon.json 不是合法 JSON 对象,已中止,未修改文件。" echo "💡 请先修复或备份后删除该文件,再重新运行本脚本。" return 1 fi if [[ "$DAEMON_HAS_CUSTOM_CONFIG" == "true" ]]; then echo " 检测到现有 Docker 自定义配置,以下项将被保留:" [[ -n "$DAEMON_DATA_ROOT" ]] && echo " data-root: $DAEMON_DATA_ROOT" [[ -n "$DAEMON_STORAGE_DRIVER" ]] && echo " storage-driver: $DAEMON_STORAGE_DRIVER" [[ -n "$DAEMON_OTHER_KEYS" ]] && echo " 其它: $DAEMON_OTHER_KEYS" echo "" echo " 本脚本仅更新 registry-mirrors,不会改动 data-root / runtime 等。" echo "" fi if ! _daemon_merge_tools_available; then if [[ "$DAEMON_HAS_CUSTOM_CONFIG" == "true" ]]; then echo "❌ 检测到自定义 Docker 配置(或含 dns 等非镜像字段),但系统缺少 jq / python3,无法安全合并。" echo "💡 请安装 jq 后重试(如: sudo apt-get install -y jq),或手动编辑 /etc/docker/daemon.json" return 1 fi echo " ⚠️ 系统缺少 jq / python3,将写入最小镜像配置(仅 registry-mirrors,当前可安全覆盖)。" echo "" fi local _confirm read -r -p "确认继续?[y/N]: " _confirm if [[ ! "$_confirm" =~ ^[Yy]$ ]]; then return 2 fi return 0 } write_merged_daemon_json() { local mirror_list="$1" if ! _daemon_merge_tools_available && [[ "$DAEMON_HAS_CUSTOM_CONFIG" == "true" ]]; then echo "❌ 无法安全写入:存在自定义配置但缺少 jq / python3。" return 1 fi if [[ "$DAEMON_PARSE_ERROR" == "true" ]]; then echo "❌ 无法写入:现有 daemon.json 解析失败。" return 1 fi local tmp_json tmp_json=$(mktemp) if command -v jq &>/dev/null; then local base_json="{}" if [[ -f /etc/docker/daemon.json ]]; then base_json=$(sudo cat /etc/docker/daemon.json 2>/dev/null || echo "{}") fi if ! echo "$base_json" | jq -e 'type == "object"' >/dev/null 2>&1; then rm -f "$tmp_json" echo "❌ 现有 daemon.json 不是合法 JSON 对象,已中止" return 1 fi if ! echo "$base_json" | jq --argjson mirrors "$mirror_list" ' ."registry-mirrors" = $mirrors | ."insecure-registries" = ( (."insecure-registries" // []) | map(select( (. | tostring | sub("^https?://"; "") | split("/")[0] | split(":")[0]) as $h | ($h != "docker.xuanyuan.me") and ($h | test("\\.xuanyuan\\.(run|dev)$") | not) )) ) | if (."insecure-registries" | length) == 0 then del(."insecure-registries") else . end ' > "$tmp_json" 2>/dev/null; then rm -f "$tmp_json" echo "❌ jq 合并配置失败" return 1 fi elif command -v python3 &>/dev/null; then local existing_for_py="{}" if [[ -f /etc/docker/daemon.json ]]; then existing_for_py=$(sudo cat /etc/docker/daemon.json 2>/dev/null || echo "{}") fi local py_status if ! py_status=$(python3 - "$mirror_list" "$existing_for_py" <<'PYEOF' import json, sys def is_xuanyuan_insecure(entry): h = str(entry) if h.startswith("http://") or h.startswith("https://"): h = h.split("://", 1)[1] h = h.split("/", 1)[0] host = h.split(":", 1)[0] if host == "docker.xuanyuan.me": return True if host.endswith(".xuanyuan.run") or host.endswith(".xuanyuan.dev"): return True return False mirrors = json.loads(sys.argv[1]) raw = sys.argv[2].strip() if len(sys.argv) > 2 else "" try: data = json.loads(raw) if raw else {} except Exception as e: print("parse_error: " + str(e), file=sys.stderr) sys.exit(1) if not isinstance(data, dict): print("parse_error: root is not object", file=sys.stderr) sys.exit(1) data["registry-mirrors"] = mirrors existing_insecure = data.get("insecure-registries") if isinstance(existing_insecure, list): kept = [x for x in existing_insecure if not is_xuanyuan_insecure(x)] if kept: data["insecure-registries"] = kept else: data.pop("insecure-registries", None) elif "insecure-registries" in data: data.pop("insecure-registries", None) print(json.dumps(data, indent=2, ensure_ascii=False)) PYEOF ); then rm -f "$tmp_json" echo "❌ python3 合并配置失败(请检查 daemon.json 是否为合法 JSON)" return 1 fi printf '%s\n' "$py_status" > "$tmp_json" else cat > "$tmp_json" </dev/null; then local PID1_COMM PID1_COMM=$(tr -d '\0' < /proc/1/comm 2>/dev/null || echo "") if [[ "$PID1_COMM" == "systemd" ]] && systemctl show-environment &>/dev/null 2>&1; then SCRIPT_SYSTEMD_OK=true fi fi if [[ "$SCRIPT_SYSTEMD_OK" == "true" ]]; then if systemctl is-active --quiet docker 2>/dev/null || systemctl list-unit-files docker.service &>/dev/null 2>&1; then echo "正在重启 Docker 服务以应用新配置..." sudo systemctl daemon-reexec || true sudo systemctl restart docker || true sleep 3 if systemctl is-active --quiet docker 2>/dev/null; then echo "✅ Docker 服务重启成功,新配置已生效" else echo "❌ Docker 服务重启失败,请手动重启" fi else echo "⚠️ Docker 服务未运行,配置将在下次启动时生效" fi else echo "ℹ️ 未检测到可用 systemd,请手动执行: sudo systemctl restart docker(或按需启动 dockerd)" fi echo "" echo "ℹ️ 重启 Docker 会停止运行中的容器,但不会删除镜像和容器数据。" echo "💡 请执行 docker ps -a 和 docker images 确认;可用 docker start 或 compose 重新拉起服务。" } apply_docker_mirror_config() { local mirror_list="$1" local confirm_rc confirm_apply_daemon_config confirm_rc=$? if [[ $confirm_rc -eq 2 ]]; then echo "已取消,未修改 /etc/docker/daemon.json" return 2 elif [[ $confirm_rc -ne 0 ]]; then return 1 fi if ! write_merged_daemon_json "$mirror_list"; then return 1 fi restart_docker_for_config return 0 } echo "==========================================" echo "🐳 欢迎使用轩辕镜像 Docker 一键安装配置脚本" echo "==========================================" echo "官方网站: https://xuanyuan.cloud/" echo "" echo "请选择操作模式:" echo "1) 一键安装配置(推荐)" echo "2) 修改轩辕镜像专属域名" echo "3) 恢复 Docker 镜像相关配置" echo "" # 循环等待用户输入有效选择 while true; do read -p "请输入选择 [1/2/3]: " mode_choice if [[ "$mode_choice" == "1" ]]; then echo "" echo ">>> 模式:一键安装配置" # 检查是否已经安装了 Docker if command -v docker &> /dev/null; then DOCKER_VERSION=$(docker --version | grep -oE '[0-9]+\.[0-9]+' | head -1) MAJOR_VERSION=$(echo "$DOCKER_VERSION" | cut -d. -f1) echo "" echo "⚠️ 检测到系统已安装 Docker 版本: $DOCKER_VERSION" echo "" if [[ "$MAJOR_VERSION" -ge 20 ]]; then echo "ℹ️ 重要提示:" echo " 您的 Docker 版本已满足要求,本次将仅配置镜像加速" echo " 不会重装或升级 Docker" echo " 配置完成后将重启 Docker 服务,运行中的容器会停止" echo " 镜像与容器数据不会删除,可用 docker start 或 compose 重新拉起" echo "" echo "请确认是否继续:" echo "1) 确认继续配置镜像加速" echo "2) 返回选择菜单" else echo "⚠️ 重要提示:" echo " 选择此选项将进行 Docker 升级或重装操作" echo " 这可能会影响现有的 Docker 容器和数据" echo " 建议在操作前备份重要的容器和数据" echo "" echo "请确认是否继续:" echo "1) 确认继续安装/升级 Docker" echo "2) 返回选择菜单" fi echo "" # 循环等待用户输入有效选择 while true; do read -p "请输入选择 [1/2]: " confirm_choice if [[ "$confirm_choice" == "1" ]]; then echo "" if [[ "$MAJOR_VERSION" -ge 20 ]]; then echo "✅ 用户确认继续,将进行镜像加速配置..." else echo "✅ 用户确认继续,将进行 Docker 安装/升级..." fi echo "" break elif [[ "$confirm_choice" == "2" ]]; then echo "" echo "🔄 返回选择菜单..." echo "" # 重新显示菜单选项 echo "请选择操作模式:" echo "1) 一键安装配置(推荐)" echo "2) 修改轩辕镜像专属域名" echo "3) 恢复 Docker 镜像相关配置" echo "" # 重置 mode_choice 以重新进入循环 mode_choice="" break else echo "❌ 无效选择,请输入 1 或 2" echo "" fi done # 如果用户选择了返回菜单,继续外层循环 if [[ "$confirm_choice" == "2" ]]; then continue fi fi echo "" break elif [[ "$mode_choice" == "2" ]]; then echo "" echo ">>> 模式:仅修改镜像地址" echo "" # 检查 Docker 是否已安装 if ! command -v docker &> /dev/null; then echo "❌ 检测到 Docker 未安装!" echo "" echo "⚠️ 风险提示:" echo " - 无法验证镜像配置是否生效" echo " - 可能导致后续 Docker 操作失败" echo " - 建议先完成 Docker 安装" echo "" echo "💡 建议:选择选项 1 进行一键安装配置" echo "" echo "已退出脚本,请重新运行并选择选项 1 进行完整安装配置" exit 1 else # 检查 Docker 版本 DOCKER_VERSION=$(docker --version | grep -oE '[0-9]+\.[0-9]+' | head -1) MAJOR_VERSION=$(echo $DOCKER_VERSION | cut -d. -f1) if [[ "$MAJOR_VERSION" -lt 20 ]]; then echo "⚠️ 检测到 Docker 版本 $DOCKER_VERSION 低于 20.0" echo "" echo "⚠️ 风险提示:" echo " - 低版本 Docker 可能存在安全漏洞" echo " - 某些新功能可能不可用" echo " - 建议升级到 Docker 20+ 版本" echo "" echo "💡 建议:选择选项 1 进行一键安装配置和升级" echo "" read -p "是否仍要继续?[y/N]: " continue_choice if [[ ! "$continue_choice" =~ ^[Yy]$ ]]; then echo "已取消操作,建议选择选项 1 进行完整安装配置" exit 0 fi fi fi echo "" echo ">>> 配置轩辕镜像地址" echo "" echo "请选择版本:" echo "1) 轩辕镜像免费版 (域名: docker.xuanyuan.me)" echo "2) 轩辕镜像专业版 (专属域名 *.xuanyuan.run / *.xuanyuan.dev ,不含免费版域名)" echo "3) 恢复/重置镜像相关配置" # 循环等待用户输入有效选择 while true; do read -p "请输入选择 [1/2/3]: " choice if [[ "$choice" == "1" || "$choice" == "2" ]]; then break elif [[ "$choice" == "3" ]]; then restore_docker_daemon_config exit $? else echo "❌ 无效选择,请输入 1、2 或 3" echo "" fi done mirror_list="" if [[ "$choice" == "2" ]]; then read -p "请输入您的轩辕镜像专属域名 (访问官网获取:https://xuanyuan.cloud): " custom_domain # 清理用户输入的域名,移除协议前缀 custom_domain=$(echo "$custom_domain" | sed 's|^https\?://||') # 清理用户输入的域名,移除协议前缀 custom_domain=$(echo "$custom_domain" | sed 's|^https\?://||') # 清理用户输入的域名,移除协议前缀 custom_domain=$(echo "$custom_domain" | sed 's|^https\?://||') # 专业版:*.xuanyuan.run / *.xuanyuan.dev 成对配置(不含 docker.xuanyuan.me) if [[ "$custom_domain" == *.xuanyuan.run ]]; then custom_domain_dev="${custom_domain%.xuanyuan.run}.xuanyuan.dev" mirror_list=$(cat <>> 模式:恢复 Docker 镜像相关配置" restore_docker_daemon_config exit $? else echo "❌ 无效选择,请输入 1、2 或 3" echo "" fi done # 检测 macOS 和 Windows 系统 DETECTED_OS=$(uname -s 2>/dev/null || echo "Unknown") # macOS 检测 if [[ "$DETECTED_OS" == "Darwin" ]]; then echo "🍎 检测到 macOS 系统" echo "" echo "==========================================" echo "⚠️ macOS 不支持此 Linux 安装脚本" echo "==========================================" echo "" echo "📋 macOS 安装 Docker 的正确方式:" echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "方法一:使用 Homebrew 安装(推荐)" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo " 1. 如果未安装 Homebrew,先安装:" echo " /bin/bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\"" echo "" echo " 2. 使用 Homebrew 安装 Docker Desktop:" echo " brew install --cask docker" echo "" echo " 3. 启动 Docker Desktop:" echo " 打开「应用程序」文件夹,双击 Docker 图标" echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "方法二:下载官方安装包" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo " 访问:https://www.docker.com/products/docker-desktop" echo " 下载 Docker Desktop for Mac (Apple Silicon 或 Intel)" echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "🚀 配置轩辕镜像" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo " 1. 启动 Docker Desktop" echo " 2. 点击菜单栏 Docker 图标 → Settings (设置)" echo " 3. 选择 Docker Engine" echo " 4. 在 JSON 配置中添加:" echo "" echo ' {' echo ' "registry-mirrors": [' echo ' "https://docker.xuanyuan.me"' echo ' ]' echo ' }' echo "" echo " (默认 HTTPS,一般无需配置 insecure-registries)" echo " 5. 点击 Apply & Restart(应用并重启)" echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "📚 更多信息" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo " 官方网站:https://xuanyuan.cloud/" echo " Docker 文档:https://docs.docker.com/desktop/install/mac-install/" echo "" echo "==========================================" exit 0 fi # Windows 检测(Git Bash、WSL、Cygwin、MSYS2 等) if [[ "$DETECTED_OS" == MINGW* ]] || [[ "$DETECTED_OS" == MSYS* ]] || [[ "$DETECTED_OS" == CYGWIN* ]]; then echo "🪟 检测到 Windows 系统" echo "" echo "==========================================" echo "⚠️ Windows 不支持此 Linux 安装脚本" echo "==========================================" echo "" echo "📋 Windows 安装 Docker 的正确方式:" echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "方法一:Docker Desktop(推荐)" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo " 1. 访问官方网站:" echo " https://www.docker.com/products/docker-desktop" echo "" echo " 2. 下载 Docker Desktop for Windows" echo "" echo " 3. 运行安装程序并按提示完成安装" echo "" echo " 4. 重启计算机(如果需要)" echo "" echo " 📌 系统要求:" echo " - Windows 10/11 64位专业版、企业版或教育版" echo " - 启用 WSL 2(Windows Subsystem for Linux 2)" echo " - 启用 Hyper-V 和容器功能" echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "方法二:在 WSL 2 中使用(高级用户)" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo " 1. 安装 WSL 2:" echo " wsl --install" echo "" echo " 2. 安装 Ubuntu 或其他 Linux 发行版" echo "" echo " 3. 在 WSL 2 中运行本安装脚本:" echo " bash <(curl -fsSL https://xuanyuan.cloud/docker.sh)" echo " 备用地址1:bash <(curl -fsSL https://get.xuanyuan.dev/docker.sh)" echo " 备用地址2:bash <(curl -fsSL https://get.xuanyuan.me/docker.sh)" echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "🚀 配置轩辕镜像" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo " 1. 启动 Docker Desktop" echo " 2. 点击系统托盘 Docker 图标 → Settings (设置)" echo " 3. 选择 Docker Engine" echo " 4. 在 JSON 配置中添加:" echo "" echo ' {' echo ' "registry-mirrors": [' echo ' "https://docker.xuanyuan.me"' echo ' ]' echo ' }' echo "" echo " (默认 HTTPS,一般无需配置 insecure-registries)" echo " 5. 点击 Apply & Restart(应用并重启)" echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "📚 更多信息" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo " 官方网站:https://xuanyuan.cloud/" echo " Docker 文档:https://docs.docker.com/desktop/install/windows-install/" echo " WSL 2 安装:https://docs.microsoft.com/windows/wsl/install" echo "" echo "==========================================" exit 0 fi echo ">>> [1/8] 检查系统信息..." OS=$(awk -F= '/^ID=/{print $2}' /etc/os-release | tr -d '"') ARCH=$(uname -m) VERSION_ID=$(awk -F= '/^VERSION_ID=/{print $2}' /etc/os-release | tr -d '"') echo "系统: $OS $VERSION_ID 架构: $ARCH" # 映射架构标识到 Docker 官方使用的架构名称 case "$ARCH" in x86_64) DOCKER_ARCH="x86_64" echo "✅ 检测到 x86_64 架构(Intel/AMD 64位)" ;; aarch64|arm64) DOCKER_ARCH="aarch64" echo "✅ 检测到 ARM 64位架构(aarch64),支持鲲鹏、飞腾等处理器" ;; armv7l|armhf) DOCKER_ARCH="armhf" echo "✅ 检测到 ARM 32位硬浮点架构(armhf)" ;; armv6l|armel) DOCKER_ARCH="armel" echo "✅ 检测到 ARM 32位软浮点架构(armel)" ;; s390x) DOCKER_ARCH="s390x" echo "✅ 检测到 IBM Z 架构(s390x)" ;; ppc64le) DOCKER_ARCH="ppc64le" echo "✅ 检测到 PowerPC 64位小端架构(ppc64le)" ;; *) echo "⚠️ 检测到架构: $ARCH" echo "⚠️ Docker 官方静态二进制包可能不支持此架构" echo "⚠️ 将尝试使用 $ARCH 作为架构标识,如果下载失败请手动安装" DOCKER_ARCH="$ARCH" ;; esac echo "📦 Docker 将使用架构标识: $DOCKER_ARCH" # 针对 Debian 10 和 Ubuntu 16.04 显示特殊提示 if [[ "$OS" == "debian" && "$VERSION_ID" == "10" ]]; then echo "" echo "⚠️ 检测到 Debian 10 (Buster) 系统" echo "📋 系统状态说明:" echo " - Debian 10 已于 2022 年 8 月结束生命周期" echo " - 官方软件源已迁移到 archive.debian.org" echo " - 本脚本将自动配置国内镜像源以提高下载速度" echo " - 建议考虑升级到 Debian 11+ 或 Ubuntu 20.04+" echo "" echo "🚀 优化措施:" echo " - 使用阿里云/腾讯云/华为云镜像源" echo " - 自动检测并切换可用的镜像源" echo " - 使用二进制安装方式避免包依赖问题" echo "" elif [[ "$OS" == "ubuntu" && "$VERSION_ID" == "16.04" ]]; then echo "" echo "⚠️ 检测到 Ubuntu 16.04 (Xenial) 系统" echo "📋 系统状态说明:" echo " - Ubuntu 16.04 已于 2021 年 4 月结束标准支持" echo " - Docker 官方仓库缺少部分新组件(如 docker-buildx-plugin)" echo " - 本脚本将使用二进制安装方式以确保兼容性" echo " - 强烈建议升级到 Ubuntu 20.04 LTS 或 Ubuntu 22.04 LTS" echo "" echo "🚀 优化措施:" echo " - 使用 Docker 二进制包直接安装" echo " - 自动配置多个国内镜像源" echo " - 跳过不兼容的组件安装" echo "" elif [[ "$OS" == "centos" && "$VERSION_ID" == "7" ]]; then echo "" echo "⚠️ ═══════════════════════════════════════════════════════════════════════════════" echo "⚠️ 重要提醒:CentOS 7 生命周期已结束" echo "⚠️ ═══════════════════════════════════════════════════════════════════════════════" echo "⚠️ 📅 2024 年 6 月 30 日:CentOS 7 结束生命周期(EOL)" echo "⚠️ " echo "⚠️ 之后,不再接收官方更新或安全补丁" echo "⚠️ 建议升级到受支持的操作系统版本" echo "⚠️ " echo "⚠️ 推荐替代方案:" echo "⚠️ - Rocky Linux 8/9(CentOS 的社区替代品)" echo "⚠️ - AlmaLinux 8/9(企业级长期支持)" echo "⚠️ - CentOS Stream 8/9(滚动发布版本)" echo "⚠️ - Red Hat Enterprise Linux 8/9(商业支持)" echo "⚠️ " echo "⚠️ 当前将使用归档源继续安装,但强烈建议尽快升级系统" echo "⚠️ ═══════════════════════════════════════════════════════════════════════════════" echo "" elif [[ "$OS" == "centos" && "$VERSION_ID" == "8" ]]; then echo "" echo "⚠️ ═══════════════════════════════════════════════════════════════════════════════" echo "⚠️ 重要提醒:CentOS 8 生命周期已结束" echo "⚠️ ═══════════════════════════════════════════════════════════════════════════════" echo "⚠️ 📅 2021 年 12 月 31 日:CentOS 8 结束生命周期(EOL)" echo "⚠️ " echo "⚠️ 之后,不再接收官方更新或安全补丁" echo "⚠️ 建议升级到受支持的操作系统版本" echo "⚠️ " echo "⚠️ 推荐替代方案:" echo "⚠️ - Rocky Linux 8/9(CentOS 的社区替代品)" echo "⚠️ - AlmaLinux 8/9(企业级长期支持)" echo "⚠️ - CentOS Stream 8/9(滚动发布版本)" echo "⚠️ - Red Hat Enterprise Linux 8/9(商业支持)" echo "⚠️ " echo "⚠️ 当前将使用归档源继续安装,但强烈建议尽快升级系统" echo "⚠️ ═══════════════════════════════════════════════════════════════════════════════" echo "" elif [[ "$OS" == "kylin" || "$OS" == "uos" || "$OS" == "uniontechos" ]]; then echo "" if [[ "$OS" == "kylin" ]]; then # 规范显示银河麒麟版本,避免出现 Vv10 等重复前缀 if [[ "$VERSION_ID" =~ ^[Vv] ]]; then KYLIN_VERSION_DISPLAY="$VERSION_ID" else KYLIN_VERSION_DISPLAY="V$VERSION_ID" fi echo "✅ 检测到银河麒麟操作系统 (Kylin Linux) $KYLIN_VERSION_DISPLAY" echo "📋 系统信息:" echo " - Kylin Linux 基于 RHEL,与 CentOS/RHEL 兼容" echo " - 使用 yum/dnf 包管理器" echo " - 支持国内镜像" else echo "✅ 检测到统信操作系统 (UnionTechOS / UOS) $VERSION_ID" echo "📋 系统信息:" echo " - 与 RHEL/CentOS 软件生态兼容,使用 yum/dnf 包管理器" echo " - Docker CE 将按兼容映射使用国内 CentOS 系镜像源" echo " - 支持国内镜像" fi echo "" elif [[ "$OS" == "kali" ]]; then echo "" echo "✅ 检测到 Kali Linux $VERSION_ID" echo "📋 系统信息:" echo " - Kali Linux 基于 Debian,与 Debian 完全兼容" echo " - 使用 apt 包管理器" echo " - 将使用 Debian 兼容的安装方法" echo " - 支持国内镜像" echo "" elif [[ "$OS" == "deepin" ]]; then echo "" echo "✅ 检测到深度操作系统 (Deepin) $VERSION_ID" echo "📋 系统信息:" echo " - Deepin 基于 Debian,使用 apt 包管理器" echo " - Docker CE 使用官方 linux/debian 源(Deepin 代号将映射为 Debian suite)" echo " - 支持国内镜像" echo "" fi echo ">>> [1.5/8] 检查 Docker 安装状态..." if command -v docker &> /dev/null; then echo "检测到 Docker 已安装" DOCKER_VERSION=$(docker --version | grep -oE '[0-9]+\.[0-9]+' | head -1) echo "当前 Docker 版本: $DOCKER_VERSION" # 提取主版本号进行比较 MAJOR_VERSION=$(echo $DOCKER_VERSION | cut -d. -f1) if [[ "$MAJOR_VERSION" -lt 20 ]]; then echo "警告: 当前 Docker 版本 $DOCKER_VERSION 低于 20.0" echo "建议升级到 Docker 20+ 版本以获得更好的性能和功能" read -p "是否要升级 Docker? [y/N]: " upgrade_choice if [[ "$upgrade_choice" =~ ^[Yy]$ ]]; then echo "用户选择升级 Docker,继续执行安装流程..." else echo "用户选择不升级,跳过 Docker 安装" echo ">>> [5/8] 配置轩辕镜像..." # 循环等待用户选择镜像版本 while true; do echo "请选择版本:" echo "1) 轩辕镜像免费版 (域名: docker.xuanyuan.me)" echo "2) 轩辕镜像专业版 (专属域名: *.xuanyuan.run / *.xuanyuan.dev 不含免费版域名)" echo "3) 恢复/重置镜像相关配置" read -p "请输入选择 [1/2/3]: " choice if [[ "$choice" == "1" || "$choice" == "2" ]]; then break elif [[ "$choice" == "3" ]]; then restore_docker_daemon_config exit $? else echo "❌ 无效选择,请输入 1、2 或 3" echo "" fi done mirror_list="" if [[ "$choice" == "2" ]]; then read -p "请输入您的轩辕镜像专属域名 (访问官网获取:https://xuanyuan.cloud): " custom_domain # 清理用户输入的域名,移除协议前缀 custom_domain=$(echo "$custom_domain" | sed 's|^https\?://||') # 清理用户输入的域名,移除协议前缀 custom_domain=$(echo "$custom_domain" | sed 's|^https\?://||') # 清理用户输入的域名,移除协议前缀 custom_domain=$(echo "$custom_domain" | sed 's|^https\?://||') # 专业版:*.xuanyuan.run / *.xuanyuan.dev 成对配置(不含 docker.xuanyuan.me) if [[ "$custom_domain" == *.xuanyuan.run ]]; then custom_domain_dev="${custom_domain%.xuanyuan.run}.xuanyuan.dev" mirror_list=$(cat <>> [6/8] 安装完成!" echo "🎉Docker 镜像已配置完成" echo "轩辕镜像 · 专业版 - 开发者首选的专业 Docker 镜像高效稳定拉取服务" echo "官方网站: https://xuanyuan.cloud/" # 显示当前配置的镜像源 echo "" echo "当前配置的镜像源:" if [[ "$choice" == "2" ]]; then if [[ "$custom_domain" == *.xuanyuan.run ]]; then custom_domain_dev="${custom_domain%.xuanyuan.run}.xuanyuan.dev" echo " - https://$custom_domain (优先)" echo " - https://$custom_domain_dev (备用)" elif [[ "$custom_domain" == *.xuanyuan.dev ]]; then custom_domain_run="${custom_domain%.xuanyuan.dev}.xuanyuan.run" echo " - https://$custom_domain (优先)" echo " - https://$custom_domain_run (备用)" else echo " - https://$custom_domain" fi else echo " - https://docker.xuanyuan.me" fi echo "" # 继续执行完整的流程,不在这里退出 fi else echo "Docker 版本 $DOCKER_VERSION 满足要求 (>= 20.0)" echo "跳过 Docker 安装,直接配置镜像..." echo ">>> [5/8] 配置国内镜像..." # 循环等待用户选择镜像版本 while true; do echo "请选择版本:" echo "1) 轩辕镜像免费版 (域名: docker.xuanyuan.me)" echo "2) 轩辕镜像专业版 (专属域名 *.xuanyuan.run / *.xuanyuan.dev 不含免费版域名)" echo "3) 恢复/重置镜像相关配置" read -p "请输入选择 [1/2/3]: " choice if [[ "$choice" == "1" || "$choice" == "2" ]]; then break elif [[ "$choice" == "3" ]]; then restore_docker_daemon_config exit $? else echo "❌ 无效选择,请输入 1、2 或 3" echo "" fi done mirror_list="" if [[ "$choice" == "2" ]]; then read -p "请输入您的轩辕镜像专属域名 (访问官网获取:https://xuanyuan.cloud): " custom_domain # 清理用户输入的域名,移除协议前缀 custom_domain=$(echo "$custom_domain" | sed 's|^https\?://||') # 清理用户输入的域名,移除协议前缀 custom_domain=$(echo "$custom_domain" | sed 's|^https\?://||') # 专业版:*.xuanyuan.run / *.xuanyuan.dev 成对配置(不含 docker.xuanyuan.me) if [[ "$custom_domain" == *.xuanyuan.run ]]; then custom_domain_dev="${custom_domain%.xuanyuan.run}.xuanyuan.dev" mirror_list=$(cat <>> [6/8] 安装完成!" echo "🎉Docker 镜像已配置完成" echo "轩辕镜像 · 专业版 - 开发者首选的专业 Docker 镜像高效稳定拉取服务" echo "官方网站: https://xuanyuan.cloud/" exit 0 fi else echo "未检测到 Docker,将进行全新安装" fi echo ">>> [2/8] 配置国内 Docker 源..." # 将 OS 转换为小写进行比较(支持 openEuler、openeuler、HCE 等大小写形式) OS_LOWER=$(echo "$OS" | tr '[:upper:]' '[:lower:]') if [[ "$OS_LOWER" == "openeuler" || "$OS_LOWER" == "hce" ]]; then # openEuler / Huawei Cloud EulerOS (HCE):yum/dnf + CentOS 兼容 Docker CE 源 # 注意:HCE 的 VERSION_ID 为 2.0/1.1,不能套用 openEuler 的年份式映射(否则 2.0 会误判为 CentOS 7) if [[ "$OS_LOWER" == "hce" ]]; then echo "检测到 Huawei Cloud EulerOS (HCE) $VERSION_ID" HCE_MAJOR="${VERSION_ID%%.*}" if [[ "$HCE_MAJOR" =~ ^[0-9]+$ ]] && [[ "$HCE_MAJOR" -ge 2 ]]; then # HCE 2.x:社区验证使用 CentOS 8 Docker CE 源;优先 dnf CENTOS_VERSION="8" if command -v dnf &> /dev/null; then PKG_MANAGER="dnf" else PKG_MANAGER="yum" fi echo "使用 $PKG_MANAGER 包管理器 (HCE $VERSION_ID 使用 CentOS ${CENTOS_VERSION} 兼容源)" else # HCE 1.x:仅 yum;使用 CentOS 7 兼容源 PKG_MANAGER="yum" CENTOS_VERSION="7" echo "使用 yum 包管理器 (HCE $VERSION_ID 使用 CentOS ${CENTOS_VERSION} 兼容源)" fi else echo "检测到 openEuler (欧拉操作系统) $VERSION_ID" # 判断使用 dnf 还是 yum(openEuler VERSION_ID 为年份,如 22.03) if [[ "${VERSION_ID%%.*}" -ge 22 ]]; then # openEuler 22+ 使用 dnf PKG_MANAGER="dnf" CENTOS_VERSION="9" echo "使用 dnf 包管理器 (openEuler $VERSION_ID 使用 CentOS 9 兼容源)" elif [[ "${VERSION_ID%%.*}" -ge 20 ]]; then # openEuler 20-21 使用 dnf,基于 CentOS 8 PKG_MANAGER="dnf" CENTOS_VERSION="8" echo "使用 dnf 包管理器 (openEuler $VERSION_ID 使用 CentOS 8 兼容源)" else # openEuler 旧版本使用 yum,基于 CentOS 7 PKG_MANAGER="yum" CENTOS_VERSION="7" echo "使用 yum 包管理器 (openEuler $VERSION_ID 使用 CentOS 7 兼容源)" fi fi sudo $PKG_MANAGER install -y ${PKG_MANAGER}-utils # 定义切换 Docker 镜像源的函数 switch_docker_mirror() { local mirror_index=$1 local centos_version=${CENTOS_VERSION:-9} local repo_added=false case $mirror_index in 1) echo "尝试配置阿里云 Docker 源..." sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null < /dev/null < /dev/null < /dev/null < /dev/null </dev/null || true sudo rm -rf /var/cache/dnf/* 2>/dev/null || true sudo rm -rf /var/cache/yum/* 2>/dev/null || true if sudo $PKG_MANAGER makecache; then repo_added=true echo "✅ Docker 源切换成功" return 0 else echo "❌ Docker 源切换失败" return 1 fi } # 尝试多个国内镜像源(优先华为云,因为 openEuler 是华为开发) echo "正在配置 Docker 源..." DOCKER_REPO_ADDED=false CURRENT_MIRROR_INDEX=0 # 0=华为云, 1=阿里云, 2=腾讯云, 3=中科大, 4=清华, 5=官方 # 创建Docker仓库配置文件,使用 openEuler 兼容的 CentOS 版本 echo "正在创建 Docker 仓库配置 (使用 CentOS ${CENTOS_VERSION} 兼容源)..." # 源1: 华为云镜像(openEuler 是华为开发,优先使用华为云) echo "尝试配置华为云 Docker 源..." sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null <>> [3/8] 安装 Docker CE 最新版..." # 检查是否安装了 iSulad(openEuler 的容器运行时,与 Docker 冲突) if rpm -q iSulad &>/dev/null; then echo "⚠️ 检测到系统已安装 iSulad(openEuler 容器运行时)" echo "⚠️ iSulad 与 Docker CE 存在包冲突,需要卸载 iSulad 才能安装 Docker" echo "正在卸载 iSulad..." if sudo $PKG_MANAGER remove -y iSulad 2>/dev/null; then echo "✅ iSulad 卸载成功" else echo "⚠️ iSulad 卸载失败,将使用 --allowerasing 参数处理冲突" fi fi # HCE / openEuler 自带 docker 多为 18.09(包名 docker / docker-engine),与 docker-ce 冲突;升级前先卸载 HCE_STOCK_DOCKER_PKGS=() for _pkg in docker docker-engine docker-common docker-client docker-client-common; do if rpm -q "$_pkg" &>/dev/null; then HCE_STOCK_DOCKER_PKGS+=("$_pkg") fi done if [[ ${#HCE_STOCK_DOCKER_PKGS[@]} -gt 0 ]]; then echo "⚠️ 检测到系统自带旧版 Docker 包: ${HCE_STOCK_DOCKER_PKGS[*]}" echo "⚠️ 安装 Docker CE 前将卸载这些冲突包(数据目录 /var/lib/docker 默认保留)" if sudo $PKG_MANAGER remove -y "${HCE_STOCK_DOCKER_PKGS[@]}" 2>/dev/null; then echo "✅ 旧版 Docker 包卸载成功" else echo "⚠️ 旧版 Docker 包卸载失败,将使用 --allowerasing 参数处理冲突" fi fi # 在安装 docker-ce 之前,先检查并安装 libnftables 依赖 echo ">>> [3.1/8] 检查 libnftables 依赖..." if ! rpm -q libnftables >/dev/null 2>&1; then echo "⚠️ 未检测到 libnftables,正在安装..." if sudo $PKG_MANAGER install -y libnftables 2>&1; then echo "✅ libnftables 安装成功" else echo "⚠️ libnftables 安装失败,将在安装 docker-ce 时重试" fi else echo "✅ libnftables 已安装" fi # 尝试安装 Docker,使用 --allowerasing 参数处理 runc 冲突 # containerd.io 会替代系统的 runc,需要使用 --allowerasing 允许替换 if sudo $PKG_MANAGER install -y --allowerasing docker-ce docker-ce-cli containerd.io docker-buildx-plugin; then echo "✅ Docker CE 安装成功" else echo "❌ 批量安装失败,尝试逐个安装组件(使用 --allowerasing)..." # 再次检查 libnftables(批量安装失败后) echo "再次检查 libnftables 依赖..." if ! rpm -q libnftables >/dev/null 2>&1; then echo "⚠️ 未检测到 libnftables,正在安装..." if sudo $PKG_MANAGER install -y libnftables 2>&1; then echo "✅ libnftables 安装成功" else echo "⚠️ libnftables 安装失败" fi else echo "✅ libnftables 已安装" fi # 逐个安装组件,都使用 --allowerasing 处理冲突 CONTAINERD_INSTALLED=false CONTAINERD_OUTPUT="" if sudo $PKG_MANAGER install -y --allowerasing containerd.io 2>&1; then echo "✅ containerd.io 安装成功" CONTAINERD_INSTALLED=true else CONTAINERD_OUTPUT=$(sudo $PKG_MANAGER install -y --allowerasing containerd.io 2>&1 || true) echo "❌ containerd.io 安装失败" # 检测是否是校验和错误,如果是则尝试切换镜像源 if echo "$CONTAINERD_OUTPUT" | grep -qiE "(checksum doesn't match|校验和不匹配|Cannot download|all mirrors were already tried)"; then echo "⚠️ 检测到下载失败或校验和不匹配,尝试切换 Docker 镜像源..." # 尝试切换其他镜像源(从阿里云开始,因为华为云已经失败) for mirror_idx in 1 2 3 4 5; do if switch_docker_mirror $mirror_idx; then CURRENT_MIRROR_INDEX=$mirror_idx echo " - 重新尝试安装 containerd.io..." if sudo $PKG_MANAGER install -y --allowerasing containerd.io 2>&1; then echo "✅ containerd.io 安装成功(切换镜像源后)" CONTAINERD_INSTALLED=true break else echo " ❌ 切换镜像源后仍然失败,尝试下一个镜像源..." fi fi done if [[ "$CONTAINERD_INSTALLED" == "false" ]]; then echo "❌ 所有镜像源都尝试失败,containerd.io 无法安装" fi fi fi if sudo $PKG_MANAGER install -y --allowerasing docker-ce-cli; then echo "✅ docker-ce-cli 安装成功" else echo "❌ docker-ce-cli 安装失败" fi DOCKER_CE_INSTALLED=false DOCKER_CE_OUTPUT="" # 使用临时变量捕获退出码,因为 tee 会改变退出码 DOCKER_CE_INSTALL_LOG=$(sudo $PKG_MANAGER install -y --allowerasing docker-ce 2>&1 | tee /tmp/docker-ce-install.log) DOCKER_CE_INSTALL_STATUS=${PIPESTATUS[0]} if [[ $DOCKER_CE_INSTALL_STATUS -eq 0 ]]; then # 再次验证 docker-ce 是否真的安装成功 if rpm -q docker-ce >/dev/null 2>&1; then echo "✅ docker-ce 安装成功" DOCKER_CE_INSTALLED=true else echo "⚠️ 安装命令成功但 docker-ce 包未找到,可能安装失败" DOCKER_CE_OUTPUT="$DOCKER_CE_INSTALL_LOG" echo "❌ docker-ce 安装失败" fi else DOCKER_CE_OUTPUT="$DOCKER_CE_INSTALL_LOG" echo "❌ docker-ce 安装失败" # 检测是否是 libnftables 依赖问题 if echo "$DOCKER_CE_OUTPUT" | grep -qiE "libnftables|LIBNFTABLES"; then echo "⚠️ 检测到 libnftables 依赖问题" # 先检查 libnftables 是否已安装 if rpm -q libnftables >/dev/null 2>&1; then echo "⚠️ libnftables 已安装,但版本可能不兼容,尝试升级..." sudo $PKG_MANAGER update -y libnftables 2>&1 || true else echo "正在尝试安装 libnftables 依赖..." fi # 尝试安装 libnftables(显示详细信息,不要隐藏错误) if sudo $PKG_MANAGER install -y libnftables 2>&1; then echo "✅ libnftables 安装成功,重新尝试安装 docker-ce..." if sudo $PKG_MANAGER install -y --allowerasing docker-ce 2>&1 | tee /tmp/docker-ce-install-retry.log; then echo "✅ docker-ce 安装成功(安装 libnftables 后)" DOCKER_CE_INSTALLED=true else echo "❌ docker-ce 安装仍然失败" DOCKER_CE_OUTPUT=$(cat /tmp/docker-ce-install-retry.log 2>/dev/null || echo "") # 如果仍然失败,尝试切换镜像源(不同镜像源可能有不同版本的 docker-ce) if echo "$DOCKER_CE_OUTPUT" | grep -qiE "libnftables|LIBNFTABLES"; then echo "⚠️ 当前镜像源的 docker-ce 版本可能不兼容,尝试切换镜像源..." # 尝试切换其他镜像源(从阿里云开始,因为华为云已经失败) for mirror_idx in 1 2 3 4 5; do if switch_docker_mirror $mirror_idx; then CURRENT_MIRROR_INDEX=$mirror_idx echo " - 重新尝试安装 docker-ce..." # 再次检查并安装 libnftables(某些镜像源可能提供不同版本) if ! rpm -q libnftables >/dev/null 2>&1; then echo " - 安装 libnftables..." sudo $PKG_MANAGER install -y libnftables 2>&1 || echo " ⚠️ libnftables 安装失败,继续尝试安装 docker-ce..." else echo " ✅ libnftables 已安装" fi if sudo $PKG_MANAGER install -y --allowerasing docker-ce 2>&1 | tee /tmp/docker-ce-install-mirror.log; then echo "✅ docker-ce 安装成功(切换镜像源后)" DOCKER_CE_INSTALLED=true break else echo " ❌ 切换镜像源后仍然失败,尝试下一个镜像源..." fi fi done fi fi else echo "⚠️ libnftables 安装失败,尝试切换镜像源后重试..." # 尝试切换其他镜像源 for mirror_idx in 1 2 3 4 5; do if switch_docker_mirror $mirror_idx; then CURRENT_MIRROR_INDEX=$mirror_idx echo " - 检查并安装 libnftables..." # 先检查是否已安装 if rpm -q libnftables >/dev/null 2>&1; then echo " ✅ libnftables 已安装" else # 尝试安装 libnftables(显示详细信息) if sudo $PKG_MANAGER install -y libnftables 2>&1; then echo " ✅ libnftables 安装成功" else echo " ⚠️ libnftables 安装失败,继续尝试安装 docker-ce..." fi fi # 无论 libnftables 是否安装成功,都尝试安装 docker-ce echo " - 尝试安装 docker-ce..." if sudo $PKG_MANAGER install -y --allowerasing docker-ce 2>&1 | tee /tmp/docker-ce-install-mirror.log; then echo "✅ docker-ce 安装成功(切换镜像源后)" DOCKER_CE_INSTALLED=true break else echo " ❌ docker-ce 安装仍然失败,尝试下一个镜像源..." fi fi done if [[ "$DOCKER_CE_INSTALLED" == "false" ]]; then echo "⚠️ 所有镜像源都尝试失败,将使用二进制安装方式绕过依赖问题" fi fi fi fi if sudo $PKG_MANAGER install -y --allowerasing docker-buildx-plugin; then echo "✅ docker-buildx-plugin 安装成功" else echo "❌ docker-buildx-plugin 安装失败" fi # 检查 docker.service 文件是否存在 DOCKER_SERVICE_EXISTS=false if [ -f /etc/systemd/system/docker.service ] || [ -f /usr/lib/systemd/system/docker.service ]; then DOCKER_SERVICE_EXISTS=true fi # 检查是否至少安装了核心组件 # 不仅要检查 docker 命令是否存在,还要检查 docker.service 是否存在 if ! command -v docker &> /dev/null || [ "$DOCKER_CE_INSTALLED" == "false" ] || [ "$DOCKER_SERVICE_EXISTS" == "false" ]; then if [ "$DOCKER_CE_INSTALLED" == "false" ] || [ "$DOCKER_SERVICE_EXISTS" == "false" ]; then if command -v docker &> /dev/null; then echo "⚠️ 检测到 docker 命令存在,但 docker-ce 包或 docker.service 文件缺失" echo "⚠️ 这通常是由于依赖问题导致 docker-ce 安装不完整" fi echo "❌ docker-ce 安装不完整,尝试二进制安装..." else echo "❌ 包管理器安装完全失败,尝试二进制安装..." fi # 二进制安装备选方案 echo "正在下载 Docker 二进制包..." # 尝试多个下载源 DOCKER_BINARY_DOWNLOADED=false # 源1: 华为云镜像(优先) echo "尝试从华为云镜像下载 Docker 二进制包..." if curl -fsSL https://mirrors.huaweicloud.com/docker-ce/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从华为云镜像下载成功" else echo "❌ 华为云镜像下载失败,尝试下一个源..." fi # 源2: 阿里云镜像 if [[ "$DOCKER_BINARY_DOWNLOADED" == "false" ]]; then echo "尝试从阿里云镜像下载..." if curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从阿里云镜像下载成功" else echo "❌ 阿里云镜像下载失败,尝试下一个源..." fi fi # 源3: 腾讯云镜像 if [[ "$DOCKER_BINARY_DOWNLOADED" == "false" ]]; then echo "尝试从腾讯云镜像下载..." if curl -fsSL https://mirrors.cloud.tencent.com/docker-ce/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从腾讯云镜像下载成功" else echo "❌ 腾讯云镜像下载失败,尝试下一个源..." fi fi # 源4: 官方源 if [[ "$DOCKER_BINARY_DOWNLOADED" == "false" ]]; then echo "尝试从官方源下载..." if curl -fsSL https://download.docker.com/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从官方源下载成功" else echo "❌ 官方源下载失败" fi fi if [[ "$DOCKER_BINARY_DOWNLOADED" == "true" ]]; then echo "正在解压并安装 Docker 二进制包..." sudo tar -xzf /tmp/docker.tgz -C /usr/bin --strip-components=1 sudo chmod +x /usr/bin/docker* # SELinux 友好提示 if command -v getenforce &> /dev/null && [ "$(getenforce)" != "Disabled" ]; then echo "" echo "⚠️ 检测到 SELinux 处于开启状态 ($(getenforce))" echo "⚠️ 二进制安装方式可能会遇到 SELinux 上下文问题" echo "⚠️ 如果启动失败,请尝试临时关闭 SELinux (setenforce 0) 或手动配置 SELinux 策略" echo "💡 推荐操作:尝试安装 container-selinux >= 2.74" echo "" echo "正在等待 3 秒以确认切换到二进制安装模式..." sleep 3 fi # 创建 systemd 服务文件 sudo tee /etc/systemd/system/docker.service > /dev/null < /dev/null </dev/null || true echo "✅ Docker 二进制安装成功" else echo "❌ 所有下载源都失败,无法安装 Docker" echo "请检查网络连接或手动安装 Docker" exit 1 fi fi fi # 检查 docker.service 文件是否存在 if [ ! -f /etc/systemd/system/docker.service ] && [ ! -f /usr/lib/systemd/system/docker.service ]; then echo "❌ docker.service 文件不存在,Docker 服务无法启动" echo "⚠️ 这通常是由于 docker-ce 包安装失败导致的" echo "💡 建议:" echo " 1. 检查依赖问题(如 libnftables)" echo " 2. 尝试手动安装依赖:sudo $PKG_MANAGER install -y libnftables" echo " 3. 重新运行安装脚本" echo " 4. 或使用二进制安装方式" exit 1 fi # 启动 Docker 服务 echo "正在启动 Docker 服务..." if sudo systemctl enable docker 2>/dev/null; then echo "✅ Docker 服务已设置为开机自启" else echo "⚠️ Docker 服务开机自启设置失败" fi if sudo systemctl start docker 2>/dev/null; then echo "✅ Docker 服务启动成功" else echo "⚠️ Docker 服务启动失败,尝试查看日志..." sudo systemctl status docker --no-pager -l || true echo "💡 可以尝试手动启动:sudo dockerd &" fi echo ">>> [3.5/8] 安装 Docker Compose..." # 安装最新版本的 docker-compose,使用多个备用下载源 echo "正在下载 Docker Compose..." # 尝试多个下载源 DOCKER_COMPOSE_DOWNLOADED=false # 源1: 华为云镜像(优先) echo "尝试从华为云镜像下载..." if sudo curl -L "https://mirrors.huaweicloud.com/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从华为云镜像下载成功" else echo "❌ 华为云镜像下载失败,尝试下一个源..." fi # 源2: 阿里云镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从阿里云镜像下载..." if sudo curl -L "https://mirrors.aliyun.com/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从阿里云镜像下载成功" else echo "❌ 阿里云镜像下载失败,尝试下一个源..." fi fi # 源3: 腾讯云镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从腾讯云镜像下载..." if sudo curl -L "https://mirrors.cloud.tencent.com/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从腾讯云镜像下载成功" else echo "❌ 腾讯云镜像下载失败,尝试下一个源..." fi fi # 源4: 中科大镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从中科大镜像下载..." if sudo curl -L "https://mirrors.ustc.edu.cn/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从中科大镜像下载成功" else echo "❌ 中科大镜像下载失败,尝试下一个源..." fi fi # 源5: 清华大学镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从清华大学镜像下载..." if sudo curl -L "https://mirrors.tuna.tsinghua.edu.cn/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从清华大学镜像下载成功" else echo "❌ 清华大学镜像下载失败,尝试下一个源..." fi fi # 源6: 网易镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从网易镜像下载..." if sudo curl -L "https://mirrors.163.com/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从网易镜像下载成功" else echo "❌ 网易镜像下载失败,尝试下一个源..." fi fi # 源7: 最后尝试 GitHub (如果网络允许) if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从 GitHub 下载..." if sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从 GitHub 下载成功" else echo "❌ GitHub 下载失败" fi fi # 检查是否下载成功 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "❌ 所有下载源都失败了,尝试使用包管理器安装..." # 使用包管理器作为备选方案 if sudo $PKG_MANAGER install -y docker-compose-plugin; then echo "✅ 通过包管理器安装 docker-compose-plugin 成功" DOCKER_COMPOSE_DOWNLOADED=true else echo "❌ 包管理器安装也失败了" fi fi if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "true" ]]; then # 设置执行权限 sudo chmod +x /usr/local/bin/docker-compose # 创建软链接到 PATH 目录 sudo ln -sf /usr/local/bin/docker-compose /usr/bin/docker-compose echo "✅ Docker Compose 安装完成" else echo "❌ Docker Compose 安装失败,请手动安装" echo "建议访问: https://docs.docker.com/compose/install/ 查看手动安装方法" fi elif [[ "$OS" == "opencloudos" ]]; then # OpenCloudOS 9 使用 dnf 而不是 yum sudo dnf install -y dnf-utils # 尝试多个国内镜像源 echo "正在配置 Docker 源..." DOCKER_REPO_ADDED=false # 创建Docker仓库配置文件,使用 OpenCloudOS 9 兼容的版本 echo "正在创建 Docker 仓库配置..." # 源1: 阿里云镜像 echo "尝试配置阿里云 Docker 源..." sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null <>> [3/8] 安装 Docker CE 最新版..." # 临时禁用 set -e,允许错误处理 set +e echo "正在尝试安装 Docker CE(这可能需要几分钟,请耐心等待)..." echo "如果安装过程卡住,可能是网络问题或依赖解析中,请等待..." # 尝试安装 Docker,使用超时机制(30分钟超时) INSTALL_OUTPUT="" INSTALL_STATUS=1 # 使用 timeout 命令(如果可用)或直接执行 # 注意:使用 bash -c 确保 sudo 函数在子 shell 中可用 if command -v timeout &> /dev/null; then INSTALL_OUTPUT=$(timeout 1800 bash -c "sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin" 2>&1) INSTALL_STATUS=$? if [[ $INSTALL_STATUS -eq 124 ]]; then echo "❌ 安装超时(30分钟),可能是网络问题或依赖解析失败" INSTALL_STATUS=1 fi else INSTALL_OUTPUT=$(sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin 2>&1) INSTALL_STATUS=$? fi # 重新启用 set -e set -e if [[ $INSTALL_STATUS -eq 0 ]]; then echo "✅ Docker CE 安装成功" else # 显示详细错误信息 echo "" echo "❌ Docker CE 批量安装失败" echo "错误详情:" echo "$INSTALL_OUTPUT" | tail -20 echo "" # 检查错误类型 if echo "$INSTALL_OUTPUT" | grep -qiE "(timeout|timed out|connection|网络|network)"; then echo "⚠️ 检测到可能的网络问题,请检查网络连接" fi if echo "$INSTALL_OUTPUT" | grep -qiE "(repo|repository|仓库|not found|找不到)"; then echo "⚠️ 检测到可能的仓库配置问题,请检查 Docker 源配置" fi echo "正在尝试逐个安装组件..." # 临时禁用 set -e set +e # 逐个安装组件 echo " - 正在安装 containerd.io..." CONTAINERD_OUTPUT=$(sudo dnf install -y containerd.io 2>&1) CONTAINERD_STATUS=$? if [[ $CONTAINERD_STATUS -eq 0 ]]; then echo " ✅ containerd.io 安装成功" else echo " ❌ containerd.io 安装失败" echo " 错误信息: $(echo "$CONTAINERD_OUTPUT" | tail -5)" fi echo " - 正在安装 docker-ce-cli..." DOCKER_CLI_OUTPUT=$(sudo dnf install -y docker-ce-cli 2>&1) DOCKER_CLI_STATUS=$? if [[ $DOCKER_CLI_STATUS -eq 0 ]]; then echo " ✅ docker-ce-cli 安装成功" else echo " ❌ docker-ce-cli 安装失败" echo " 错误信息: $(echo "$DOCKER_CLI_OUTPUT" | tail -5)" fi echo " - 正在安装 docker-ce..." DOCKER_CE_OUTPUT=$(sudo dnf install -y docker-ce 2>&1) DOCKER_CE_STATUS=$? if [[ $DOCKER_CE_STATUS -eq 0 ]]; then echo " ✅ docker-ce 安装成功" else echo " ❌ docker-ce 安装失败" echo " 错误信息: $(echo "$DOCKER_CE_OUTPUT" | tail -5)" fi echo " - 正在安装 docker-buildx-plugin..." BUILDX_OUTPUT=$(sudo dnf install -y docker-buildx-plugin 2>&1) BUILDX_STATUS=$? if [[ $BUILDX_STATUS -eq 0 ]]; then echo " ✅ docker-buildx-plugin 安装成功" else echo " ⚠️ docker-buildx-plugin 安装失败(可选组件,不影响核心功能)" fi # 重新启用 set -e set -e # 检查是否至少安装了核心组件 if ! command -v docker &> /dev/null; then echo "" echo "❌ 包管理器安装完全失败,尝试二进制安装..." # 二进制安装备选方案 echo "正在下载 Docker 二进制包..." # 尝试多个下载源 DOCKER_BINARY_DOWNLOADED=false # 源1: 阿里云镜像 echo "尝试从阿里云镜像下载 Docker 二进制包..." if curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从阿里云镜像下载成功" else echo "❌ 阿里云镜像下载失败,尝试下一个源..." fi # 源2: 腾讯云镜像 if [[ "$DOCKER_BINARY_DOWNLOADED" == "false" ]]; then echo "尝试从腾讯云镜像下载..." if curl -fsSL https://mirrors.cloud.tencent.com/docker-ce/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从腾讯云镜像下载成功" else echo "❌ 腾讯云镜像下载失败,尝试下一个源..." fi fi # 源3: 华为云镜像 if [[ "$DOCKER_BINARY_DOWNLOADED" == "false" ]]; then echo "尝试从华为云镜像下载..." if curl -fsSL https://mirrors.huaweicloud.com/docker-ce/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从华为云镜像下载成功" else echo "❌ 华为云镜像下载失败,尝试下一个源..." fi fi # 源4: 官方源 if [[ "$DOCKER_BINARY_DOWNLOADED" == "false" ]]; then echo "尝试从官方源下载..." if curl -fsSL https://download.docker.com/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从官方源下载成功" else echo "❌ 官方源下载失败" fi fi if [[ "$DOCKER_BINARY_DOWNLOADED" == "true" ]]; then echo "正在解压并安装 Docker 二进制包..." sudo tar -xzf /tmp/docker.tgz -C /usr/bin --strip-components=1 sudo chmod +x /usr/bin/docker* # 创建 systemd 服务文件 sudo tee /etc/systemd/system/docker.service > /dev/null < /dev/null </dev/null || true echo "✅ Docker 二进制安装成功" else echo "❌ 所有下载源都失败,无法安装 Docker" echo "请检查网络连接或手动安装 Docker" exit 1 fi fi fi sudo systemctl enable docker sudo systemctl start docker echo ">>> [3.5/8] 安装 Docker Compose..." # 安装最新版本的 docker-compose,使用多个备用下载源 echo "正在下载 Docker Compose..." # 尝试多个下载源 DOCKER_COMPOSE_DOWNLOADED=false # 源1: 阿里云镜像 echo "尝试从阿里云镜像下载..." if sudo curl -L "https://mirrors.aliyun.com/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从阿里云镜像下载成功" else echo "❌ 阿里云镜像下载失败,尝试下一个源..." fi # 源2: 腾讯云镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从腾讯云镜像下载..." if sudo curl -L "https://mirrors.cloud.tencent.com/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从腾讯云镜像下载成功" else echo "❌ 腾讯云镜像下载失败,尝试下一个源..." fi fi # 源3: 华为云镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从华为云镜像下载..." if sudo curl -L "https://mirrors.huaweicloud.com/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从华为云镜像下载成功" else echo "❌ 华为云镜像下载失败,尝试下一个源..." fi fi # 源4: 中科大镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从中科大镜像下载..." if sudo curl -L "https://mirrors.ustc.edu.cn/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从中科大镜像下载成功" else echo "❌ 中科大镜像下载失败,尝试下一个源..." fi fi # 源5: 清华大学镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从清华大学镜像下载..." if sudo curl -L "https://mirrors.tuna.tsinghua.edu.cn/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从清华大学镜像下载成功" else echo "❌ 清华大学镜像下载失败,尝试下一个源..." fi fi # 源6: 网易镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从网易镜像下载..." if sudo curl -L "https://mirrors.163.com/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从网易镜像下载成功" else echo "❌ 网易镜像下载失败,尝试下一个源..." fi fi # 源7: 最后尝试 GitHub (如果网络允许) # 源7: 最后尝试 GitHub (如果网络允许) if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从 GitHub 下载..." if sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从 GitHub 下载成功" else echo "❌ GitHub 下载失败" fi fi # 检查是否下载成功 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "❌ 所有下载源都失败了,尝试使用包管理器安装..." # 使用包管理器作为备选方案 if sudo dnf install -y docker-compose-plugin; then echo "✅ 通过包管理器安装 docker-compose-plugin 成功" DOCKER_COMPOSE_DOWNLOADED=true else echo "❌ 包管理器安装也失败了" fi fi if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "true" ]]; then # 设置执行权限 sudo chmod +x /usr/local/bin/docker-compose # 创建软链接到 PATH 目录 sudo ln -sf /usr/local/bin/docker-compose /usr/bin/docker-compose echo "✅ Docker Compose 安装完成" else echo "❌ Docker Compose 安装失败,请手动安装" echo "建议访问: https://docs.docker.com/compose/install/ 查看手动安装方法" fi elif [[ "$OS" == "anolis" ]]; then # Anolis OS (龙蜥操作系统) 支持 echo "检测到 Anolis OS (龙蜥操作系统) $VERSION_ID" # 判断使用 dnf 还是 yum if [[ "${VERSION_ID%%.*}" -ge 8 ]]; then # Anolis 8+ 使用 dnf PKG_MANAGER="dnf" CENTOS_VERSION="8" echo "使用 dnf 包管理器 (Anolis $VERSION_ID 基于 CentOS 8+)" else # Anolis 7 使用 yum PKG_MANAGER="yum" CENTOS_VERSION="7" echo "使用 yum 包管理器 (Anolis $VERSION_ID 基于 CentOS 7)" fi sudo $PKG_MANAGER install -y ${PKG_MANAGER}-utils # 尝试多个国内镜像源 echo "正在配置 Docker 源..." DOCKER_REPO_ADDED=false # 创建Docker仓库配置文件,使用 Anolis 兼容的 CentOS 版本 echo "正在创建 Docker 仓库配置 (使用 CentOS ${CENTOS_VERSION} 兼容源)..." # 源1: 阿里云镜像 echo "尝试配置阿里云 Docker 源..." sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null <>> [3/8] 安装 Docker CE 最新版..." # 尝试安装 Docker,如果失败则尝试逐个安装组件 if sudo $PKG_MANAGER install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin; then echo "✅ Docker CE 安装成功" else echo "❌ 批量安装失败,尝试逐个安装组件..." # 逐个安装组件 if sudo $PKG_MANAGER install -y containerd.io; then echo "✅ containerd.io 安装成功" else echo "❌ containerd.io 安装失败" fi if sudo $PKG_MANAGER install -y docker-ce-cli; then echo "✅ docker-ce-cli 安装成功" else echo "❌ docker-ce-cli 安装失败" fi if sudo $PKG_MANAGER install -y docker-ce; then echo "✅ docker-ce 安装成功" else echo "❌ docker-ce 安装失败" fi if sudo $PKG_MANAGER install -y docker-buildx-plugin; then echo "✅ docker-buildx-plugin 安装成功" else echo "❌ docker-buildx-plugin 安装失败" fi # 检查是否至少安装了核心组件 if ! command -v docker &> /dev/null; then echo "❌ 包管理器安装完全失败,尝试二进制安装..." # 二进制安装备选方案 echo "正在下载 Docker 二进制包..." # 尝试多个下载源 DOCKER_BINARY_DOWNLOADED=false # 源1: 阿里云镜像 echo "尝试从阿里云镜像下载 Docker 二进制包..." if curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从阿里云镜像下载成功" else echo "❌ 阿里云镜像下载失败,尝试下一个源..." fi # 源2: 腾讯云镜像 if [[ "$DOCKER_BINARY_DOWNLOADED" == "false" ]]; then echo "尝试从腾讯云镜像下载..." if curl -fsSL https://mirrors.cloud.tencent.com/docker-ce/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从腾讯云镜像下载成功" else echo "❌ 腾讯云镜像下载失败,尝试下一个源..." fi fi # 源3: 华为云镜像 if [[ "$DOCKER_BINARY_DOWNLOADED" == "false" ]]; then echo "尝试从华为云镜像下载..." if curl -fsSL https://mirrors.huaweicloud.com/docker-ce/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从华为云镜像下载成功" else echo "❌ 华为云镜像下载失败,尝试下一个源..." fi fi # 源4: 官方源 if [[ "$DOCKER_BINARY_DOWNLOADED" == "false" ]]; then echo "尝试从官方源下载..." if curl -fsSL https://download.docker.com/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从官方源下载成功" else echo "❌ 官方源下载失败" fi fi if [[ "$DOCKER_BINARY_DOWNLOADED" == "true" ]]; then echo "正在解压并安装 Docker 二进制包..." sudo tar -xzf /tmp/docker.tgz -C /usr/bin --strip-components=1 sudo chmod +x /usr/bin/docker* # 创建 systemd 服务文件 sudo tee /etc/systemd/system/docker.service > /dev/null < /dev/null </dev/null || true echo "✅ Docker 二进制安装成功" else echo "❌ 所有下载源都失败,无法安装 Docker" echo "请检查网络连接或手动安装 Docker" exit 1 fi fi fi sudo systemctl enable docker sudo systemctl start docker echo ">>> [3.5/8] 安装 Docker Compose..." # 安装最新版本的 docker-compose,使用多个备用下载源 echo "正在下载 Docker Compose..." # 尝试多个下载源 DOCKER_COMPOSE_DOWNLOADED=false # 源1: 阿里云镜像 echo "尝试从阿里云镜像下载..." if sudo curl -L "https://mirrors.aliyun.com/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从阿里云镜像下载成功" else echo "❌ 阿里云镜像下载失败,尝试下一个源..." fi # 源2: 腾讯云镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从腾讯云镜像下载..." if sudo curl -L "https://mirrors.cloud.tencent.com/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从腾讯云镜像下载成功" else echo "❌ 腾讯云镜像下载失败,尝试下一个源..." fi fi # 源3: 华为云镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从华为云镜像下载..." if sudo curl -L "https://mirrors.huaweicloud.com/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从华为云镜像下载成功" else echo "❌ 华为云镜像下载失败,尝试下一个源..." fi fi # 源4: 中科大镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从中科大镜像下载..." if sudo curl -L "https://mirrors.ustc.edu.cn/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从中科大镜像下载成功" else echo "❌ 中科大镜像下载失败,尝试下一个源..." fi fi # 源5: 清华大学镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从清华大学镜像下载..." if sudo curl -L "https://mirrors.tuna.tsinghua.edu.cn/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从清华大学镜像下载成功" else echo "❌ 清华大学镜像下载失败,尝试下一个源..." fi fi # 源6: 网易镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从网易镜像下载..." if sudo curl -L "https://mirrors.163.com/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从网易镜像下载成功" else echo "❌ 网易镜像下载失败,尝试下一个源..." fi fi # 源7: 最后尝试 GitHub (如果网络允许) if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从 GitHub 下载..." if sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从 GitHub 下载成功" else echo "❌ GitHub 下载失败" fi fi # 检查是否下载成功 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "❌ 所有下载源都失败了,尝试使用包管理器安装..." # 使用包管理器作为备选方案 if sudo $PKG_MANAGER install -y docker-compose-plugin; then echo "✅ 通过包管理器安装 docker-compose-plugin 成功" DOCKER_COMPOSE_DOWNLOADED=true else echo "❌ 包管理器安装也失败了" fi fi if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "true" ]]; then # 设置执行权限 sudo chmod +x /usr/local/bin/docker-compose # 创建软链接到 PATH 目录 sudo ln -sf /usr/local/bin/docker-compose /usr/bin/docker-compose echo "✅ Docker Compose 安装完成" else echo "❌ Docker Compose 安装失败,请手动安装" echo "建议访问: https://docs.docker.com/compose/install/ 查看手动安装方法" fi elif [[ "$OS" == "alinux" ]]; then # Alinux (Alibaba Cloud Linux) 支持 echo "检测到 Alibaba Cloud Linux (Alinux) $VERSION_ID" echo "基于 Anolis OS,阿里云深度优化的企业级操作系统" # 判断使用 dnf 还是 yum if [[ "${VERSION_ID%%.*}" -ge 3 ]]; then # Alinux 3+ 使用 dnf,基于 Anolis OS 8 PKG_MANAGER="dnf" CENTOS_VERSION="8" echo "使用 dnf 包管理器 (Alinux $VERSION_ID 基于 Anolis OS 8 / CentOS 8)" else # Alinux 2 使用 yum,基于 Anolis OS 7 PKG_MANAGER="yum" CENTOS_VERSION="7" echo "使用 yum 包管理器 (Alinux $VERSION_ID 基于 Anolis OS 7 / CentOS 7)" fi sudo $PKG_MANAGER install -y ${PKG_MANAGER}-utils # 尝试多个国内镜像源 echo "正在配置 Docker 源..." DOCKER_REPO_ADDED=false # 创建Docker仓库配置文件,使用 Alinux 兼容的 CentOS 版本 echo "正在创建 Docker 仓库配置 (使用 CentOS ${CENTOS_VERSION} 兼容源)..." # 源1: 阿里云镜像 echo "尝试配置阿里云 Docker 源..." sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null <>> [3/8] 安装 Docker CE 最新版..." # 尝试安装 Docker,如果失败则尝试逐个安装组件 if sudo $PKG_MANAGER install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin; then echo "✅ Docker CE 安装成功" else echo "❌ 批量安装失败,尝试逐个安装组件..." # 逐个安装组件 if sudo $PKG_MANAGER install -y containerd.io; then echo "✅ containerd.io 安装成功" else echo "❌ containerd.io 安装失败" fi if sudo $PKG_MANAGER install -y docker-ce-cli; then echo "✅ docker-ce-cli 安装成功" else echo "❌ docker-ce-cli 安装失败" fi if sudo $PKG_MANAGER install -y docker-ce; then echo "✅ docker-ce 安装成功" else echo "❌ docker-ce 安装失败" fi if sudo $PKG_MANAGER install -y docker-buildx-plugin; then echo "✅ docker-buildx-plugin 安装成功" else echo "❌ docker-buildx-plugin 安装失败" fi # 检查是否至少安装了核心组件 if ! command -v docker &> /dev/null; then echo "❌ 包管理器安装完全失败,尝试二进制安装..." # 二进制安装备选方案 echo "正在下载 Docker 二进制包..." # 尝试多个下载源 DOCKER_BINARY_DOWNLOADED=false # 源1: 阿里云镜像 echo "尝试从阿里云镜像下载 Docker 二进制包..." if curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从阿里云镜像下载成功" else echo "❌ 阿里云镜像下载失败,尝试下一个源..." fi # 源2: 腾讯云镜像 if [[ "$DOCKER_BINARY_DOWNLOADED" == "false" ]]; then echo "尝试从腾讯云镜像下载..." if curl -fsSL https://mirrors.cloud.tencent.com/docker-ce/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从腾讯云镜像下载成功" else echo "❌ 腾讯云镜像下载失败,尝试下一个源..." fi fi # 源3: 华为云镜像 if [[ "$DOCKER_BINARY_DOWNLOADED" == "false" ]]; then echo "尝试从华为云镜像下载..." if curl -fsSL https://mirrors.huaweicloud.com/docker-ce/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从华为云镜像下载成功" else echo "❌ 华为云镜像下载失败,尝试下一个源..." fi fi # 源4: 官方源 if [[ "$DOCKER_BINARY_DOWNLOADED" == "false" ]]; then echo "尝试从官方源下载..." if curl -fsSL https://download.docker.com/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从官方源下载成功" else echo "❌ 官方源下载失败" fi fi if [[ "$DOCKER_BINARY_DOWNLOADED" == "true" ]]; then echo "正在解压并安装 Docker 二进制包..." sudo tar -xzf /tmp/docker.tgz -C /usr/bin --strip-components=1 sudo chmod +x /usr/bin/docker* # 创建 systemd 服务文件 sudo tee /etc/systemd/system/docker.service > /dev/null < /dev/null </dev/null || true echo "✅ Docker 二进制安装成功" else echo "❌ 所有下载源都失败,无法安装 Docker" echo "请检查网络连接或手动安装 Docker" exit 1 fi fi fi sudo systemctl enable docker sudo systemctl start docker echo ">>> [3.5/8] 安装 Docker Compose..." # 安装最新版本的 docker-compose,使用多个备用下载源 echo "正在下载 Docker Compose..." # 尝试多个下载源 DOCKER_COMPOSE_DOWNLOADED=false # 源1: 阿里云镜像 echo "尝试从阿里云镜像下载..." if sudo curl -L "https://mirrors.aliyun.com/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从阿里云镜像下载成功" else echo "❌ 阿里云镜像下载失败,尝试下一个源..." fi # 源2: 腾讯云镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从腾讯云镜像下载..." if sudo curl -L "https://mirrors.cloud.tencent.com/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从腾讯云镜像下载成功" else echo "❌ 腾讯云镜像下载失败,尝试下一个源..." fi fi # 源3: 华为云镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从华为云镜像下载..." if sudo curl -L "https://mirrors.huaweicloud.com/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从华为云镜像下载成功" else echo "❌ 华为云镜像下载失败,尝试下一个源..." fi fi # 源4: 中科大镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从中科大镜像下载..." if sudo curl -L "https://mirrors.ustc.edu.cn/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从中科大镜像下载成功" else echo "❌ 中科大镜像下载失败,尝试下一个源..." fi fi # 源5: 清华大学镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从清华大学镜像下载..." if sudo curl -L "https://mirrors.tuna.tsinghua.edu.cn/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从清华大学镜像下载成功" else echo "❌ 清华大学镜像下载失败,尝试下一个源..." fi fi # 源6: 网易镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从网易镜像下载..." if sudo curl -L "https://mirrors.163.com/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从网易镜像下载成功" else echo "❌ 网易镜像下载失败,尝试下一个源..." fi fi # 源7: 最后尝试 GitHub (如果网络允许) if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从 GitHub 下载..." if sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从 GitHub 下载成功" else echo "❌ GitHub 下载失败" fi fi # 检查是否下载成功 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "❌ 所有下载源都失败了,尝试使用包管理器安装..." # 使用包管理器作为备选方案 if sudo $PKG_MANAGER install -y docker-compose-plugin; then echo "✅ 通过包管理器安装 docker-compose-plugin 成功" DOCKER_COMPOSE_DOWNLOADED=true else echo "❌ 包管理器安装也失败了" fi fi if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "true" ]]; then # 设置执行权限 sudo chmod +x /usr/local/bin/docker-compose # 创建软链接到 PATH 目录 sudo ln -sf /usr/local/bin/docker-compose /usr/bin/docker-compose echo "✅ Docker Compose 安装完成" else echo "❌ Docker Compose 安装失败,请手动安装" echo "建议访问: https://docs.docker.com/compose/install/ 查看手动安装方法" fi elif [[ "$OS" == "fedora" ]]; then # Fedora 支持 echo "检测到 Fedora $VERSION_ID" # 检查 Fedora 版本是否过期 if [[ "${VERSION_ID%%.*}" -lt 38 ]]; then echo "" echo "⚠️ 警告:Fedora $VERSION_ID 可能已结束生命周期" echo "📋 建议:" echo " - 升级到 Fedora 38+ 以获得最新的安全更新和软件包" echo " - 或考虑使用 Rocky Linux / AlmaLinux(企业级长期支持)" echo "" fi # Fedora 使用 dnf 包管理器 sudo dnf install -y dnf-plugins-core # 尝试多个国内镜像源 echo "正在配置 Docker 源..." DOCKER_REPO_ADDED=false # 创建Docker仓库配置文件,使用 Fedora 专用仓库 echo "正在创建 Docker 仓库配置..." # 源1: 阿里云镜像 echo "尝试配置阿里云 Docker 源..." sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null <>> [3/8] 安装 Docker CE 最新版..." # 尝试安装 Docker,如果失败则尝试逐个安装组件 if sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin; then echo "✅ Docker CE 安装成功" else echo "❌ 批量安装失败,尝试逐个安装组件..." # 逐个安装组件 if sudo dnf install -y containerd.io; then echo "✅ containerd.io 安装成功" else echo "❌ containerd.io 安装失败" fi if sudo dnf install -y docker-ce-cli; then echo "✅ docker-ce-cli 安装成功" else echo "❌ docker-ce-cli 安装失败" fi if sudo dnf install -y docker-ce; then echo "✅ docker-ce 安装成功" else echo "❌ docker-ce 安装失败" fi if sudo dnf install -y docker-buildx-plugin; then echo "✅ docker-buildx-plugin 安装成功" else echo "❌ docker-buildx-plugin 安装失败(可选组件)" fi if sudo dnf install -y docker-compose-plugin; then echo "✅ docker-compose-plugin 安装成功" else echo "❌ docker-compose-plugin 安装失败(可选组件)" fi # 检查是否至少安装了核心组件 if ! command -v docker &> /dev/null; then echo "❌ 包管理器安装完全失败,尝试二进制安装..." # 二进制安装备选方案 echo "正在下载 Docker 二进制包..." # 尝试多个下载源 DOCKER_BINARY_DOWNLOADED=false # 源1: 阿里云镜像 echo "尝试从阿里云镜像下载 Docker 二进制包..." if curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从阿里云镜像下载成功" else echo "❌ 阿里云镜像下载失败,尝试下一个源..." fi # 源2: 腾讯云镜像 if [[ "$DOCKER_BINARY_DOWNLOADED" == "false" ]]; then echo "尝试从腾讯云镜像下载..." if curl -fsSL https://mirrors.cloud.tencent.com/docker-ce/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从腾讯云镜像下载成功" else echo "❌ 腾讯云镜像下载失败,尝试下一个源..." fi fi # 源3: 华为云镜像 if [[ "$DOCKER_BINARY_DOWNLOADED" == "false" ]]; then echo "尝试从华为云镜像下载..." if curl -fsSL https://mirrors.huaweicloud.com/docker-ce/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从华为云镜像下载成功" else echo "❌ 华为云镜像下载失败,尝试下一个源..." fi fi # 源4: 官方源 if [[ "$DOCKER_BINARY_DOWNLOADED" == "false" ]]; then echo "尝试从官方源下载..." if curl -fsSL https://download.docker.com/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从官方源下载成功" else echo "❌ 官方源下载失败" fi fi if [[ "$DOCKER_BINARY_DOWNLOADED" == "true" ]]; then echo "正在解压并安装 Docker 二进制包..." sudo tar -xzf /tmp/docker.tgz -C /usr/bin --strip-components=1 sudo chmod +x /usr/bin/docker* # 创建 systemd 服务文件 sudo tee /etc/systemd/system/docker.service > /dev/null < /dev/null </dev/null || true echo "✅ Docker 二进制安装成功" else echo "❌ 所有下载源都失败,无法安装 Docker" echo "请检查网络连接或手动安装 Docker" exit 1 fi fi fi sudo systemctl enable docker sudo systemctl start docker echo ">>> [3.5/8] 安装 Docker Compose..." # 检查是否已通过插件安装 if command -v docker compose version &> /dev/null 2>&1; then echo "✅ Docker Compose (插件版本) 已安装" else # 安装独立版本的 docker-compose,使用多个备用下载源 echo "正在下载 Docker Compose 独立版本..." # 尝试多个下载源 DOCKER_COMPOSE_DOWNLOADED=false # 源1: 阿里云镜像 echo "尝试从阿里云镜像下载..." if sudo curl -L "https://mirrors.aliyun.com/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从阿里云镜像下载成功" else echo "❌ 阿里云镜像下载失败,尝试下一个源..." fi # 源2: 腾讯云镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从腾讯云镜像下载..." if sudo curl -L "https://mirrors.cloud.tencent.com/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从腾讯云镜像下载成功" else echo "❌ 腾讯云镜像下载失败,尝试下一个源..." fi fi # 源3: 华为云镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从华为云镜像下载..." if sudo curl -L "https://mirrors.huaweicloud.com/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从华为云镜像下载成功" else echo "❌ 华为云镜像下载失败,尝试下一个源..." fi fi # 源4: 中科大镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从中科大镜像下载..." if sudo curl -L "https://mirrors.ustc.edu.cn/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从中科大镜像下载成功" else echo "❌ 中科大镜像下载失败,尝试下一个源..." fi fi # 源5: 清华大学镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从清华大学镜像下载..." if sudo curl -L "https://mirrors.tuna.tsinghua.edu.cn/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从清华大学镜像下载成功" else echo "❌ 清华大学镜像下载失败,尝试下一个源..." fi fi # 源6: 网易镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从网易镜像下载..." if sudo curl -L "https://mirrors.163.com/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从网易镜像下载成功" else echo "❌ 网易镜像下载失败,尝试下一个源..." fi fi # 源7: 最后尝试 GitHub (如果网络允许) if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从 GitHub 下载..." if sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从 GitHub 下载成功" else echo "❌ GitHub 下载失败" fi fi if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "true" ]]; then # 设置执行权限 sudo chmod +x /usr/local/bin/docker-compose # 创建软链接到 PATH 目录 sudo ln -sf /usr/local/bin/docker-compose /usr/bin/docker-compose echo "✅ Docker Compose 独立版本安装完成" else echo "⚠️ Docker Compose 独立版本安装失败" echo "您仍可以使用 'docker compose' 命令(如果插件已安装)" fi fi elif [[ "$OS" == "rocky" ]]; then # Rocky Linux 9 使用 dnf 而不是 yum sudo dnf install -y dnf-utils # 尝试多个国内镜像源 echo "正在配置 Docker 源..." DOCKER_REPO_ADDED=false # 创建Docker仓库配置文件,使用 Rocky Linux 9 兼容的版本 echo "正在创建 Docker 仓库配置..." # 源1: 阿里云镜像 echo "尝试配置阿里云 Docker 源..." sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null <>> [3/8] 安装 Docker CE 最新版..." # 临时禁用 set -e,允许错误处理 set +e echo "正在尝试安装 Docker CE(这可能需要几分钟,请耐心等待)..." echo "如果安装过程卡住,可能是网络问题或依赖解析中,请等待..." # 尝试安装 Docker,使用超时机制(30分钟超时) INSTALL_OUTPUT="" INSTALL_STATUS=1 # 使用 timeout 命令(如果可用)或直接执行 # 注意:使用 bash -c 确保 sudo 函数在子 shell 中可用 if command -v timeout &> /dev/null; then INSTALL_OUTPUT=$(timeout 1800 bash -c "sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin" 2>&1) INSTALL_STATUS=$? if [[ $INSTALL_STATUS -eq 124 ]]; then echo "❌ 安装超时(30分钟),可能是网络问题或依赖解析失败" INSTALL_STATUS=1 fi else INSTALL_OUTPUT=$(sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin 2>&1) INSTALL_STATUS=$? fi # 重新启用 set -e set -e if [[ $INSTALL_STATUS -eq 0 ]]; then echo "✅ Docker CE 安装成功" else # 显示详细错误信息 echo "" echo "❌ Docker CE 批量安装失败" echo "错误详情:" echo "$INSTALL_OUTPUT" | tail -20 echo "" # 检查错误类型 if echo "$INSTALL_OUTPUT" | grep -qiE "(timeout|timed out|connection|网络|network)"; then echo "⚠️ 检测到可能的网络问题,请检查网络连接" fi if echo "$INSTALL_OUTPUT" | grep -qiE "(repo|repository|仓库|not found|找不到)"; then echo "⚠️ 检测到可能的仓库配置问题,请检查 Docker 源配置" fi echo "正在尝试逐个安装组件..." # 临时禁用 set -e set +e # 逐个安装组件 echo " - 正在安装 containerd.io..." CONTAINERD_OUTPUT=$(sudo dnf install -y containerd.io 2>&1) CONTAINERD_STATUS=$? if [[ $CONTAINERD_STATUS -eq 0 ]]; then echo " ✅ containerd.io 安装成功" else echo " ❌ containerd.io 安装失败" echo " 错误信息: $(echo "$CONTAINERD_OUTPUT" | tail -5)" fi echo " - 正在安装 docker-ce-cli..." DOCKER_CLI_OUTPUT=$(sudo dnf install -y docker-ce-cli 2>&1) DOCKER_CLI_STATUS=$? if [[ $DOCKER_CLI_STATUS -eq 0 ]]; then echo " ✅ docker-ce-cli 安装成功" else echo " ❌ docker-ce-cli 安装失败" echo " 错误信息: $(echo "$DOCKER_CLI_OUTPUT" | tail -5)" fi echo " - 正在安装 docker-ce..." DOCKER_CE_OUTPUT=$(sudo dnf install -y docker-ce 2>&1) DOCKER_CE_STATUS=$? if [[ $DOCKER_CE_STATUS -eq 0 ]]; then echo " ✅ docker-ce 安装成功" else echo " ❌ docker-ce 安装失败" echo " 错误信息: $(echo "$DOCKER_CE_OUTPUT" | tail -5)" fi echo " - 正在安装 docker-buildx-plugin..." BUILDX_OUTPUT=$(sudo dnf install -y docker-buildx-plugin 2>&1) BUILDX_STATUS=$? if [[ $BUILDX_STATUS -eq 0 ]]; then echo " ✅ docker-buildx-plugin 安装成功" else echo " ⚠️ docker-buildx-plugin 安装失败(可选组件,不影响核心功能)" fi # 重新启用 set -e set -e # 检查是否至少安装了核心组件 if ! command -v docker &> /dev/null; then echo "" echo "❌ 包管理器安装完全失败,尝试二进制安装..." # 二进制安装备选方案 echo "正在下载 Docker 二进制包..." # 尝试多个下载源 DOCKER_BINARY_DOWNLOADED=false # 源1: 阿里云镜像 echo "尝试从阿里云镜像下载 Docker 二进制包..." if curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从阿里云镜像下载成功" else echo "❌ 阿里云镜像下载失败,尝试下一个源..." fi # 源2: 腾讯云镜像 if [[ "$DOCKER_BINARY_DOWNLOADED" == "false" ]]; then echo "尝试从腾讯云镜像下载..." if curl -fsSL https://mirrors.cloud.tencent.com/docker-ce/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从腾讯云镜像下载成功" else echo "❌ 腾讯云镜像下载失败,尝试下一个源..." fi fi # 源3: 华为云镜像 if [[ "$DOCKER_BINARY_DOWNLOADED" == "false" ]]; then echo "尝试从华为云镜像下载..." if curl -fsSL https://mirrors.huaweicloud.com/docker-ce/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从华为云镜像下载成功" else echo "❌ 华为云镜像下载失败,尝试下一个源..." fi fi # 源4: 官方源 if [[ "$DOCKER_BINARY_DOWNLOADED" == "false" ]]; then echo "尝试从官方源下载..." if curl -fsSL https://download.docker.com/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从官方源下载成功" else echo "❌ 官方源下载失败" fi fi if [[ "$DOCKER_BINARY_DOWNLOADED" == "true" ]]; then echo "正在解压并安装 Docker 二进制包..." sudo tar -xzf /tmp/docker.tgz -C /usr/bin --strip-components=1 sudo chmod +x /usr/bin/docker* # 创建 systemd 服务文件 sudo tee /etc/systemd/system/docker.service > /dev/null < /dev/null </dev/null || true echo "✅ Docker 二进制安装成功" else echo "❌ 所有下载源都失败,无法安装 Docker" echo "请检查网络连接或手动安装 Docker" exit 1 fi fi fi sudo systemctl enable docker sudo systemctl start docker echo ">>> [3.5/8] 安装 Docker Compose..." # 安装最新版本的 docker-compose,使用多个备用下载源 echo "正在下载 Docker Compose..." # 尝试多个下载源 DOCKER_COMPOSE_DOWNLOADED=false # 源1: 阿里云镜像 echo "尝试从阿里云镜像下载..." if sudo curl -L "https://mirrors.aliyun.com/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从阿里云镜像下载成功" else echo "❌ 阿里云镜像下载失败,尝试下一个源..." fi # 源2: 腾讯云镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从腾讯云镜像下载..." if sudo curl -L "https://mirrors.cloud.tencent.com/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从腾讯云镜像下载成功" else echo "❌ 腾讯云镜像下载失败,尝试下一个源..." fi fi # 源3: 华为云镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从华为云镜像下载..." if sudo curl -L "https://mirrors.huaweicloud.com/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从华为云镜像下载成功" else echo "❌ 华为云镜像下载失败,尝试下一个源..." fi fi # 源4: 中科大镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从中科大镜像下载..." if sudo curl -L "https://mirrors.ustc.edu.cn/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从中科大镜像下载成功" else echo "❌ 中科大镜像下载失败,尝试下一个源..." fi fi # 源5: 清华大学镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从清华大学镜像下载..." if sudo curl -L "https://mirrors.tuna.tsinghua.edu.cn/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从清华大学镜像下载成功" else echo "❌ 清华大学镜像下载失败,尝试下一个源..." fi fi # 源6: 网易镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从网易镜像下载..." if sudo curl -L "https://mirrors.163.com/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从网易镜像下载成功" else echo "❌ 网易镜像下载失败,尝试下一个源..." fi fi # 源7: 最后尝试 GitHub (如果网络允许) # 源7: 最后尝试 GitHub (如果网络允许) if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从 GitHub 下载..." if sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从 GitHub 下载成功" else echo "❌ GitHub 下载失败" fi fi # 检查是否下载成功 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "❌ 所有下载源都失败了,尝试使用包管理器安装..." # 使用包管理器作为备选方案 if sudo dnf install -y docker-compose-plugin; then echo "✅ 通过包管理器安装 docker-compose-plugin 成功" DOCKER_COMPOSE_DOWNLOADED=true else echo "❌ 包管理器安装也失败了" fi fi if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "true" ]]; then # 设置执行权限 sudo chmod +x /usr/local/bin/docker-compose # 创建软链接到 PATH 目录 sudo ln -sf /usr/local/bin/docker-compose /usr/bin/docker-compose echo "✅ Docker Compose 安装完成" else echo "❌ Docker Compose 安装失败,请手动安装" echo "建议访问: https://docs.docker.com/compose/install/ 查看手动安装方法" fi elif [[ "$OS" == "kylin" || "$OS" == "uos" || "$OS" == "uniontechos" ]]; then # Kylin Linux(银河麒麟)/ 统信 UOS:RHEL 兼容系,Docker CE 使用 linux/centos/${CENTOS_VERSION} 源 KYLIN_MAJOR_VERSION="" UOS_PRESET_CENTOS="" if [[ "$OS" == "kylin" ]]; then # 规范显示版本号,避免 Vv10 if [[ "$VERSION_ID" =~ ^[Vv] ]]; then KYLIN_VERSION_DISPLAY="$VERSION_ID" else KYLIN_VERSION_DISPLAY="V$VERSION_ID" fi echo "检测到 Kylin Linux $KYLIN_VERSION_DISPLAY" echo "Kylin Linux 基于 RHEL,与 CentOS/RHEL 兼容" # 对银河麒麟版本做简单解析:V10 系列按 RHEL 8 处理 if [[ "$VERSION_ID" =~ [0-9]+ ]]; then KYLIN_MAJOR_VERSION="$(echo "$VERSION_ID" | grep -oE '[0-9]+' | head -1)" fi else echo "检测到统信 UOS $VERSION_ID(/etc/os-release ID=$OS)" echo "统信服务器版与 RHEL/CentOS 兼容;Docker CE 使用 CentOS 兼容仓库" # UOS 20.x 等与 EL8 线兼容,不得沿用「首个数字」误判为 7(VERSION_ID=20 时首段为 20 而非 10) UOS_MAJOR="${VERSION_ID%%.*}" if [[ "$UOS_MAJOR" =~ ^[0-9]+$ ]] && [[ "$UOS_MAJOR" -ge 20 ]]; then UOS_PRESET_CENTOS="8" else UOS_PRESET_CENTOS="7" fi echo "兼容映射:使用 CentOS ${UOS_PRESET_CENTOS} 的 Docker CE 源(若失败请反馈 VERSION_ID 以便调整)" fi # 优先使用 dnf,其次尝试 yum;都不存在则提示用户 if command -v dnf &> /dev/null; then PKG_MANAGER="dnf" if [[ -n "$UOS_PRESET_CENTOS" ]]; then CENTOS_VERSION="$UOS_PRESET_CENTOS" elif [[ "$KYLIN_MAJOR_VERSION" == "10" ]]; then CENTOS_VERSION="8" else CENTOS_VERSION="7" fi if [[ "$OS" == "kylin" ]]; then echo "使用 dnf 包管理器 (Kylin $KYLIN_VERSION_DISPLAY 基于 RHEL ${CENTOS_VERSION})" else echo "使用 dnf 包管理器 (UOS $VERSION_ID → CentOS ${CENTOS_VERSION} 兼容源)" fi elif command -v yum &> /dev/null; then PKG_MANAGER="yum" if [[ -n "$UOS_PRESET_CENTOS" ]]; then CENTOS_VERSION="$UOS_PRESET_CENTOS" elif [[ "$KYLIN_MAJOR_VERSION" == "10" ]]; then CENTOS_VERSION="8" else CENTOS_VERSION="7" fi if [[ "$OS" == "kylin" ]]; then echo "使用 yum 包管理器 (Kylin $KYLIN_VERSION_DISPLAY 基于 RHEL ${CENTOS_VERSION})" else echo "使用 yum 包管理器 (UOS $VERSION_ID → CentOS ${CENTOS_VERSION} 兼容源)" fi else echo "❌ 未检测到可用的 dnf 或 yum 包管理器,请先在系统中安装 dnf 或 yum 后重试。" exit 1 fi sudo $PKG_MANAGER install -y ${PKG_MANAGER}-utils # 尝试多个国内镜像源 echo "正在配置 Docker 源..." DOCKER_REPO_ADDED=false # 创建Docker仓库配置文件,使用兼容的 CentOS 版本 echo "正在创建 Docker 仓库配置 (使用 CentOS ${CENTOS_VERSION} 兼容源)..." # 源1: 阿里云镜像 echo "尝试配置阿里云 Docker 源..." sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null <>> [2.5/8] 检查 container-selinux 依赖..." # 检查 container-selinux 是否存在及版本 CONTAINER_SELINUX_INSTALLED=false if rpm -q container-selinux &>/dev/null; then INSTALLED_VERSION=$(rpm -q --qf '%{VERSION}-%{RELEASE}' container-selinux 2>/dev/null) echo "检测到已安装 container-selinux: $INSTALLED_VERSION" # 检查版本是否满足要求 (>= 2.74) # 尝试解析版本号,格式可能是 2:2.74-1 或 2.74-1 VERSION_STRING=$(echo "$INSTALLED_VERSION" | grep -oE '[0-9]+\.[0-9]+' | head -1) if [[ -n "$VERSION_STRING" ]]; then MAJOR_VERSION=$(echo "$VERSION_STRING" | cut -d. -f1) MINOR_VERSION=$(echo "$VERSION_STRING" | cut -d. -f2) if [[ "$MAJOR_VERSION" -gt 2 ]] || [[ "$MAJOR_VERSION" -eq 2 && "$MINOR_VERSION" -ge 74 ]]; then CONTAINER_SELINUX_INSTALLED=true echo "✅ container-selinux 版本满足要求" else echo "⚠️ container-selinux 版本过低 ($INSTALLED_VERSION),需要 >= 2:2.74" fi else # 如果无法解析版本,尝试安装最新版本 echo "⚠️ 无法解析 container-selinux 版本,将尝试更新" fi else echo "未检测到 container-selinux,将尝试安装..." fi # 如果 container-selinux 未安装或版本不够,尝试安装 if [[ "$CONTAINER_SELINUX_INSTALLED" == "false" ]]; then echo "正在尝试安装 container-selinux..." # 方法1: 尝试从系统源安装 if sudo $PKG_MANAGER install -y container-selinux 2>/dev/null; then echo "✅ 从系统源安装 container-selinux 成功" # 重新检查版本 INSTALLED_VERSION=$(rpm -q --qf '%{VERSION}-%{RELEASE}' container-selinux 2>/dev/null) echo "已安装版本: $INSTALLED_VERSION" VERSION_STRING=$(echo "$INSTALLED_VERSION" | grep -oE '[0-9]+\.[0-9]+' | head -1) if [[ -n "$VERSION_STRING" ]]; then MAJOR_VERSION=$(echo "$VERSION_STRING" | cut -d. -f1) MINOR_VERSION=$(echo "$VERSION_STRING" | cut -d. -f2) if [[ "$MAJOR_VERSION" -gt 2 ]] || [[ "$MAJOR_VERSION" -eq 2 && "$MINOR_VERSION" -ge 74 ]]; then CONTAINER_SELINUX_INSTALLED=true echo "✅ container-selinux 版本满足要求" else echo "⚠️ container-selinux 版本过低 ($INSTALLED_VERSION),需要 >= 2:2.74" echo "⚠️ 将尝试从其他源安装更高版本..." fi fi else echo "⚠️ 系统源中未找到 container-selinux,尝试配置 RHEL 8 extras 源..." fi # 方法2: 如果版本仍然不满足要求,尝试配置 RHEL 8 extras 源(适用于 Kylin V10) if [[ "$CONTAINER_SELINUX_INSTALLED" == "false" && "$CENTOS_VERSION" == "8" ]]; then echo "尝试配置 RHEL 8 extras 源以获取更高版本的 container-selinux..." # 尝试配置阿里云 CentOS 8 extras 源 if sudo tee /etc/yum.repos.d/rhel8-extras.repo > /dev/null </dev/null; then [rhel8-extras] name=RHEL 8 Extras - \$basearch baseurl=https://mirrors.aliyun.com/centos-vault/8.5.2111/extras/\$basearch/os/ enabled=1 gpgcheck=0 EOF if sudo $PKG_MANAGER makecache -q 2>/dev/null; then # 尝试升级到更高版本 if sudo $PKG_MANAGER upgrade -y container-selinux 2>/dev/null || sudo $PKG_MANAGER install -y container-selinux 2>/dev/null; then INSTALLED_VERSION=$(rpm -q --qf '%{VERSION}-%{RELEASE}' container-selinux 2>/dev/null) echo "已安装版本: $INSTALLED_VERSION" VERSION_STRING=$(echo "$INSTALLED_VERSION" | grep -oE '[0-9]+\.[0-9]+' | head -1) if [[ -n "$VERSION_STRING" ]]; then MAJOR_VERSION=$(echo "$VERSION_STRING" | cut -d. -f1) MINOR_VERSION=$(echo "$VERSION_STRING" | cut -d. -f2) if [[ "$MAJOR_VERSION" -gt 2 ]] || [[ "$MAJOR_VERSION" -eq 2 && "$MINOR_VERSION" -ge 74 ]]; then CONTAINER_SELINUX_INSTALLED=true echo "✅ 从 RHEL 8 extras 源安装 container-selinux 成功,版本满足要求" else echo "⚠️ RHEL 8 extras 源版本仍然不满足要求" fi fi else echo "⚠️ RHEL 8 extras 源安装失败" fi else echo "⚠️ RHEL 8 extras 源配置失败" fi sudo rm -f /etc/yum.repos.d/rhel8-extras.repo 2>/dev/null fi fi # 方法3: 如果版本仍然不满足要求,标记为需要二进制安装 if [[ "$CONTAINER_SELINUX_INSTALLED" == "false" ]]; then echo "⚠️ container-selinux 版本不满足要求(需要 >= 2:2.74)" echo "⚠️ 将使用二进制安装方式绕过依赖问题" CONTAINER_SELINUX_ERROR=true fi fi echo ">>> [3/8] 安装 Docker CE 最新版..." # 统信 UOS / 银河麒麟等自带的 docker-runc 与 Docker CE 的 containerd.io(内置 runc)冲突,需先移除再装 docker-ce if [[ "$OS" == "uos" || "$OS" == "uniontechos" || "$OS" == "kylin" ]]; then if rpm -q docker-runc &>/dev/null; then echo ">>> [2.9/8] 检测到系统包 docker-runc,与 Docker CE 依赖冲突,正在移除..." sudo $PKG_MANAGER remove -y docker-runc 2>/dev/null || true fi fi # 如果 container-selinux 版本不满足要求,直接使用二进制安装 DOCKER_INSTALL_SUCCESS=false # 如果已经检测到 container-selinux 错误,直接跳过包管理器安装 if [[ "$CONTAINER_SELINUX_ERROR" == "true" ]]; then echo "" echo "⚠️ ═══════════════════════════════════════════════════════════════════════════════" echo "⚠️ 检测到 container-selinux 版本不满足要求" echo "⚠️ ═══════════════════════════════════════════════════════════════════════════════" echo "⚠️ Docker CE 需要 container-selinux >= 2:2.74,但系统源中无法提供" echo "⚠️ 将使用二进制安装方式绕过依赖问题" echo "⚠️ ═══════════════════════════════════════════════════════════════════════════════" echo "" # 清理可能的安装残留 sudo $PKG_MANAGER remove -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin 2>/dev/null || true echo "❌ 包管理器安装失败,切换到二进制安装..." else # 临时禁用 set -e,允许错误处理 set +e echo "正在尝试安装 Docker CE(这可能需要几分钟,请耐心等待)..." echo "如果安装过程卡住,可能是网络问题或依赖解析中,请等待..." # 尝试安装 Docker,使用超时机制(30分钟超时) INSTALL_OUTPUT="" INSTALL_STATUS=1 # 使用 timeout 命令(如果可用)或直接执行 # 注意:使用 bash -c 确保 sudo 函数在子 shell 中可用 if command -v timeout &> /dev/null; then INSTALL_OUTPUT=$(timeout 1800 bash -c "sudo $PKG_MANAGER install -y --allowerasing docker-ce docker-ce-cli containerd.io docker-buildx-plugin" 2>&1) INSTALL_STATUS=$? if [[ $INSTALL_STATUS -eq 124 ]]; then echo "❌ 安装超时(30分钟),可能是网络问题或依赖解析失败" INSTALL_STATUS=1 fi else INSTALL_OUTPUT=$(sudo $PKG_MANAGER install -y --allowerasing docker-ce docker-ce-cli containerd.io docker-buildx-plugin 2>&1) INSTALL_STATUS=$? fi # 重新启用 set -e set -e if [[ $INSTALL_STATUS -eq 0 ]]; then echo "✅ Docker CE 安装成功" DOCKER_INSTALL_SUCCESS=true else # 显示详细错误信息 echo "" echo "❌ Docker CE 批量安装失败" echo "错误详情:" echo "$INSTALL_OUTPUT" | tail -20 echo "" # 检查错误输出,判断是否是 container-selinux 依赖问题 if echo "$INSTALL_OUTPUT" | grep -qi "container-selinux"; then CONTAINER_SELINUX_ERROR=true echo "❌ 检测到 container-selinux 依赖问题" fi # 检查是否是网络问题 if echo "$INSTALL_OUTPUT" | grep -qiE "(timeout|timed out|connection|网络|network)"; then echo "⚠️ 检测到可能的网络问题,请检查网络连接" fi # 检查是否是仓库问题 if echo "$INSTALL_OUTPUT" | grep -qiE "(repo|repository|仓库|not found|找不到)"; then echo "⚠️ 检测到可能的仓库配置问题,请检查 Docker 源配置" fi echo "正在尝试逐个安装组件..." # 临时禁用 set -e set +e # 逐个安装组件 echo " - 正在安装 containerd.io..." CONTAINERD_OUTPUT=$(sudo $PKG_MANAGER install -y containerd.io 2>&1) CONTAINERD_STATUS=$? if echo "$CONTAINERD_OUTPUT" | grep -qi "container-selinux"; then echo " ❌ containerd.io 安装失败(container-selinux 依赖问题)" echo " 错误信息: $(echo "$CONTAINERD_OUTPUT" | grep -i "container-selinux" | head -1)" CONTAINER_SELINUX_ERROR=true elif [[ $CONTAINERD_STATUS -eq 0 ]]; then echo " ✅ containerd.io 安装成功" else echo " ❌ containerd.io 安装失败" echo " 错误信息: $(echo "$CONTAINERD_OUTPUT" | tail -5)" # 检测下载失败或校验和不匹配,尝试清理缓存后重试 if echo "$CONTAINERD_OUTPUT" | grep -qiE "(Cannot download|all mirrors were already tried|下载失败|无法下载|checksum doesn't match|校验和不匹配)"; then echo " ⚠️ 检测到下载失败或校验和不匹配,尝试清理缓存后重试..." # 清理所有缓存,包括损坏的文件 sudo $PKG_MANAGER clean all 2>/dev/null || true sudo rm -rf /var/cache/dnf/* 2>/dev/null || true sudo rm -rf /var/cache/yum/* 2>/dev/null || true echo " - 重新尝试安装 containerd.io..." CONTAINERD_RETRY_OUTPUT=$(sudo $PKG_MANAGER install -y containerd.io 2>&1) CONTAINERD_RETRY_STATUS=$? if [[ $CONTAINERD_RETRY_STATUS -eq 0 ]]; then echo " ✅ containerd.io 重试安装成功" CONTAINERD_STATUS=0 else echo " ❌ containerd.io 重试安装仍然失败" echo " 错误信息: $(echo "$CONTAINERD_RETRY_OUTPUT" | tail -5)" # 如果还是校验和不匹配,尝试安装其他版本 if echo "$CONTAINERD_RETRY_OUTPUT" | grep -qiE "(checksum doesn't match|校验和不匹配)"; then echo " ⚠️ 检测到校验和不匹配,尝试安装其他版本的 containerd.io..." # 尝试多个可用版本(从新到旧) CONTAINERD_VERSIONS=("1.6.31-3.1.el8" "1.6.28-3.2.el8" "1.6.28-3.1.el8" "1.6.27-3.1.el8" "1.6.26-3.1.el8") CONTAINERD_INSTALLED=false for VERSION in "${CONTAINERD_VERSIONS[@]}"; do echo " - 尝试安装 containerd.io-${VERSION}..." CONTAINERD_ALT_OUTPUT=$(sudo $PKG_MANAGER install -y containerd.io-${VERSION} 2>&1) CONTAINERD_ALT_STATUS=$? if [[ $CONTAINERD_ALT_STATUS -eq 0 ]]; then echo " ✅ containerd.io-${VERSION} 安装成功" CONTAINERD_STATUS=0 CONTAINERD_INSTALLED=true break else # 检查是否是校验和不匹配,如果是则继续尝试下一个版本 if echo "$CONTAINERD_ALT_OUTPUT" | grep -qiE "(checksum doesn't match|校验和不匹配)"; then echo " ⚠️ containerd.io-${VERSION} 也存在校验和不匹配,尝试下一个版本..." continue else echo " ❌ containerd.io-${VERSION} 安装失败" # 如果不是校验和问题,可能是其他问题,继续尝试下一个版本 continue fi fi done if [[ "$CONTAINERD_INSTALLED" == "false" ]]; then echo " ❌ 所有尝试的版本都安装失败" echo " 💡 建议:手动下载并安装 containerd.io" echo " 下载地址:https://mirrors.aliyun.com/docker-ce/linux/centos/8/${DOCKER_ARCH}/stable/Packages/" echo " 或尝试其他镜像源:" echo " - 腾讯云:https://mirrors.cloud.tencent.com/docker-ce/linux/centos/8/${DOCKER_ARCH}/stable/Packages/" echo " - 华为云:https://mirrors.huaweicloud.com/docker-ce/linux/centos/8/${DOCKER_ARCH}/stable/Packages/" echo " 安装命令:sudo rpm -ivh containerd.io-*.rpm" fi else echo " ⚠️ 提示:containerd.io 是 Docker 的运行时依赖,如果无法安装,Docker daemon 可能无法启动" echo " 💡 建议:检查网络连接或尝试手动安装 containerd.io" fi fi fi fi echo " - 正在安装 docker-ce-cli..." DOCKER_CLI_OUTPUT=$(sudo $PKG_MANAGER install -y docker-ce-cli 2>&1) DOCKER_CLI_STATUS=$? if [[ $DOCKER_CLI_STATUS -eq 0 ]]; then echo " ✅ docker-ce-cli 安装成功" else echo " ❌ docker-ce-cli 安装失败" echo " 错误信息: $(echo "$DOCKER_CLI_OUTPUT" | tail -5)" fi echo " - 正在安装 docker-ce..." DOCKER_CE_OUTPUT=$(sudo $PKG_MANAGER install -y --allowerasing docker-ce 2>&1) DOCKER_CE_STATUS=$? if echo "$DOCKER_CE_OUTPUT" | grep -qi "container-selinux"; then echo " ❌ docker-ce 安装失败(container-selinux 依赖问题)" echo " 错误信息: $(echo "$DOCKER_CE_OUTPUT" | grep -i "container-selinux" | head -1)" CONTAINER_SELINUX_ERROR=true elif [[ $DOCKER_CE_STATUS -eq 0 ]]; then echo " ✅ docker-ce 安装成功" DOCKER_INSTALL_SUCCESS=true else echo " ❌ docker-ce 安装失败" echo " 错误信息: $(echo "$DOCKER_CE_OUTPUT" | tail -5)" fi echo " - 正在安装 docker-buildx-plugin..." BUILDX_OUTPUT=$(sudo $PKG_MANAGER install -y docker-buildx-plugin 2>&1) BUILDX_STATUS=$? if [[ $BUILDX_STATUS -eq 0 ]]; then echo " ✅ docker-buildx-plugin 安装成功" else echo " ⚠️ docker-buildx-plugin 安装失败(可选组件,不影响核心功能)" fi # 重新启用 set -e set -e # 检查是否至少安装了核心组件 if command -v docker &> /dev/null; then DOCKER_INSTALL_SUCCESS=true echo "" echo "✅ Docker 核心组件已安装(docker 命令可用)" # 检查安装状态并给出提示 if [[ $CONTAINERD_STATUS -ne 0 ]] || [[ $DOCKER_CE_STATUS -ne 0 ]]; then echo "" echo "⚠️ ═══════════════════════════════════════════════════════════════════════════════" echo "⚠️ 部分组件安装失败" echo "⚠️ ═══════════════════════════════════════════════════════════════════════════════" if [[ $CONTAINERD_STATUS -ne 0 ]]; then echo "⚠️ containerd.io 未安装 - Docker daemon 需要此组件才能运行" fi if [[ $DOCKER_CE_STATUS -ne 0 ]]; then echo "⚠️ docker-ce 未安装 - Docker daemon 需要此组件才能运行" fi echo "" echo "📋 当前状态:" echo " ✅ docker-ce-cli 已安装(可以使用 docker 命令)" echo " ✅ docker-buildx-plugin 已安装" if [[ $CONTAINERD_STATUS -ne 0 ]]; then echo " ❌ containerd.io 未安装" else echo " ✅ containerd.io 已安装" fi if [[ $DOCKER_CE_STATUS -ne 0 ]]; then echo " ❌ docker-ce 未安装" else echo " ✅ docker-ce 已安装" fi echo "" echo "💡 建议操作:" if [[ $CONTAINERD_STATUS -ne 0 ]]; then echo " 1. 手动安装 containerd.io:" echo " sudo $PKG_MANAGER clean all" echo " sudo $PKG_MANAGER makecache" echo " sudo $PKG_MANAGER install -y containerd.io" fi if [[ $DOCKER_CE_STATUS -ne 0 ]]; then echo " 2. 安装 containerd.io 后,再安装 docker-ce:" echo " sudo $PKG_MANAGER install -y docker-ce" fi echo " 3. 或者检查网络连接后重新运行安装脚本" echo "⚠️ ═══════════════════════════════════════════════════════════════════════════════" fi fi fi fi # 如果检测到 container-selinux 依赖问题,使用二进制安装 if [[ "$CONTAINER_SELINUX_ERROR" == "true" ]]; then echo "" echo "⚠️ ═══════════════════════════════════════════════════════════════════════════════" echo "⚠️ 检测到 container-selinux 依赖问题" echo "⚠️ ═══════════════════════════════════════════════════════════════════════════════" echo "⚠️ Docker CE 需要 container-selinux >= 2:2.74,但系统源中无法提供" echo "⚠️ 将使用二进制安装方式绕过依赖问题" echo "⚠️ ═══════════════════════════════════════════════════════════════════════════════" echo "" # 清理可能的安装残留 sudo $PKG_MANAGER remove -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin 2>/dev/null || true echo "❌ 包管理器安装失败,切换到二进制安装..." # 二进制安装备选方案 echo "正在下载 Docker 二进制包..." # 尝试多个下载源 DOCKER_BINARY_DOWNLOADED=false # 源1: 阿里云镜像 echo "尝试从阿里云镜像下载 Docker 二进制包..." if curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从阿里云镜像下载成功" else echo "❌ 阿里云镜像下载失败,尝试下一个源..." fi # 源2: 腾讯云镜像 if [[ "$DOCKER_BINARY_DOWNLOADED" == "false" ]]; then echo "尝试从腾讯云镜像下载..." if curl -fsSL https://mirrors.cloud.tencent.com/docker-ce/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从腾讯云镜像下载成功" else echo "❌ 腾讯云镜像下载失败,尝试下一个源..." fi fi # 源3: 华为云镜像 if [[ "$DOCKER_BINARY_DOWNLOADED" == "false" ]]; then echo "尝试从华为云镜像下载..." if curl -fsSL https://mirrors.huaweicloud.com/docker-ce/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从华为云镜像下载成功" else echo "❌ 华为云镜像下载失败,尝试下一个源..." fi fi # 源4: 官方源 if [[ "$DOCKER_BINARY_DOWNLOADED" == "false" ]]; then echo "尝试从官方源下载..." if curl -fsSL https://download.docker.com/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从官方源下载成功" else echo "❌ 官方源下载失败" fi fi if [[ "$DOCKER_BINARY_DOWNLOADED" == "true" ]]; then echo "正在解压并安装 Docker 二进制包..." sudo tar -xzf /tmp/docker.tgz -C /usr/bin --strip-components=1 sudo chmod +x /usr/bin/docker* # 创建 systemd 服务文件 sudo tee /etc/systemd/system/docker.service > /dev/null < /dev/null </dev/null || true # 尝试安装 containerd.io(如果可能) echo "正在尝试安装 containerd.io..." if sudo $PKG_MANAGER install -y containerd.io 2>/dev/null; then echo "✅ containerd.io 安装成功" else echo "⚠️ containerd.io 安装失败,Docker 可能需要手动安装 containerd" echo "⚠️ 如果 Docker 启动失败,请尝试手动安装 containerd.io" fi echo "✅ Docker 二进制安装成功" DOCKER_INSTALL_SUCCESS=true else echo "❌ 所有下载源都失败,无法安装 Docker" echo "请检查网络连接或手动安装 Docker" exit 1 fi fi # 检测 systemd 是否可用:PID 1 须为 systemd 且 dbus 可连通(仅有 /run/systemd 在容器/WSL 中不可靠) SYSTEMD_AVAILABLE=false if command -v systemctl &>/dev/null; then PID1_COMM_KYLIN=$(tr -d '\0' < /proc/1/comm 2>/dev/null || echo "") if [[ "$PID1_COMM_KYLIN" == "systemd" ]] && systemctl show-environment &>/dev/null; then SYSTEMD_AVAILABLE=true fi fi if [[ "$SYSTEMD_AVAILABLE" == "true" ]]; then echo "正在启动 Docker 服务..." sudo systemctl daemon-reload 2>/dev/null || true if sudo systemctl enable docker 2>/dev/null; then echo "✅ Docker 服务已启用" fi if sudo systemctl start docker 2>/dev/null; then echo "✅ Docker 服务启动成功" else echo "⚠️ systemctl 启动失败,尝试手动启动..." # 尝试手动启动 dockerd if sudo dockerd > /dev/null 2>&1 & then sleep 3 if docker info &>/dev/null; then echo "✅ Docker daemon 手动启动成功" else echo "⚠️ Docker daemon 启动失败,请手动启动: sudo dockerd &" fi fi fi else echo "⚠️ 检测到 systemd 不可用(可能是容器环境)" echo "⚠️ 将尝试手动启动 Docker daemon..." # 创建必要的目录 sudo mkdir -p /var/run/docker sudo mkdir -p /var/lib/docker # 尝试启动 dockerd if sudo dockerd > /tmp/dockerd.log 2>&1 & then DOCKERD_PID=$! sleep 3 if docker info &>/dev/null; then echo "✅ Docker daemon 手动启动成功 (PID: $DOCKERD_PID)" echo "⚠️ 注意:Docker daemon 在后台运行,退出终端前请使用 'sudo kill $DOCKERD_PID' 停止" else echo "⚠️ Docker daemon 启动可能失败,请检查日志: cat /tmp/dockerd.log" echo "⚠️ 可以尝试手动启动: sudo dockerd &" fi else echo "⚠️ 无法自动启动 Docker daemon,请手动执行: sudo dockerd &" fi fi echo ">>> [3.5/8] 安装 Docker Compose..." # 安装最新版本的 docker-compose,使用多个备用下载源 echo "正在下载 Docker Compose..." # 尝试多个下载源 DOCKER_COMPOSE_DOWNLOADED=false # 确定 Docker Compose 架构标识(使用已定义的DOCKER_ARCH变量) if [[ "$ARCH" == "x86_64" ]]; then COMPOSE_ARCH="x86_64" elif [[ "$ARCH" == "aarch64" ]] || [[ "$ARCH" == "arm64" ]]; then COMPOSE_ARCH="aarch64" else COMPOSE_ARCH="$DOCKER_ARCH" fi # 临时文件路径 COMPOSE_TMP="/tmp/docker-compose-$$" # 源1: 优先使用包管理器安装(最可靠) echo "尝试使用包管理器安装 docker-compose-plugin..." if sudo $PKG_MANAGER install -y docker-compose-plugin 2>/dev/null; then echo "✅ 通过包管理器安装 docker-compose-plugin 成功" DOCKER_COMPOSE_DOWNLOADED=true else echo "⚠️ 包管理器安装失败,尝试从国内镜像源下载..." fi # 源2: 使用国内镜像源下载(如果包管理器失败) if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then # 尝试使用 get.docker.com 的镜像(如果有) echo "尝试从国内镜像源下载 docker-compose..." # 使用固定版本 v2.24.0,从国内镜像下载 # 注意:国内镜像源可能没有最新版本,使用固定版本更可靠 COMPOSE_VERSION="2.24.0" # 尝试多个国内镜像源 # 源2.1: 阿里云镜像(如果有) if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从阿里云镜像下载 docker-compose v${COMPOSE_VERSION}..." # 注意:国内镜像源可能没有 docker-compose,这里尝试但不保证成功 if sudo curl -L "https://mirrors.aliyun.com/docker-toolbox/linux/compose/${COMPOSE_VERSION}/docker-compose-Linux-${COMPOSE_ARCH}" -o "$COMPOSE_TMP" --connect-timeout 10 --max-time 60 2>/dev/null; then FILE_SIZE=$(stat -f%z "$COMPOSE_TMP" 2>/dev/null || stat -c%s "$COMPOSE_TMP" 2>/dev/null || echo "0") if [[ "$FILE_SIZE" -gt 10485760 ]] || (file "$COMPOSE_TMP" 2>/dev/null | grep -q "ELF\|executable\|binary") || (head -c 4 "$COMPOSE_TMP" 2>/dev/null | od -An -tx1 | grep -q "7f 45 4c 46"); then sudo mv "$COMPOSE_TMP" /usr/local/bin/docker-compose DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从阿里云镜像下载成功" else if head -c 20 "$COMPOSE_TMP" 2>/dev/null | grep -q "/dev/null || true echo "✅ Docker Compose 安装完成" elif command -v docker &>/dev/null && docker compose version &>/dev/null; then echo "✅ Docker Compose Plugin 已安装(使用 'docker compose' 命令)" fi else echo "⚠️ Docker Compose 自动安装失败" echo "" echo "📋 手动安装方法:" echo " 方法1: 使用包管理器(推荐)" echo " sudo $PKG_MANAGER install -y docker-compose-plugin" echo "" echo " 方法2: 手动下载二进制文件" echo " 由于 GitHub 在国内访问受限,建议:" echo " 1. 使用代理或 VPN 访问 GitHub" echo " 2. 或从其他可靠源下载 docker-compose 二进制文件" echo "" echo " 安装后验证:" echo " docker compose version 或 docker-compose version" echo "" echo " 更多信息: https://docs.docker.com/compose/install/" fi elif [[ "$OS" == "almalinux" ]]; then # AlmaLinux (CentOS 替代品) 支持 echo "检测到 AlmaLinux $VERSION_ID" echo "AlmaLinux 是 RHEL 的 1:1 二进制兼容克隆,企业级长期支持" # AlmaLinux 使用 dnf 而不是 yum sudo dnf install -y dnf-utils # 尝试多个国内镜像源 echo "正在配置 Docker 源..." DOCKER_REPO_ADDED=false # 创建Docker仓库配置文件,使用 AlmaLinux 兼容的 CentOS 9 版本 echo "正在创建 Docker 仓库配置 (使用 CentOS 9 兼容源)..." # 源1: 阿里云镜像 echo "尝试配置阿里云 Docker 源..." sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null <>> [3/8] 安装 Docker CE 最新版..." # 临时禁用 set -e,允许错误处理 set +e echo "正在尝试安装 Docker CE(这可能需要几分钟,请耐心等待)..." echo "如果安装过程卡住,可能是网络问题或依赖解析中,请等待..." # 尝试安装 Docker,使用超时机制(30分钟超时) INSTALL_OUTPUT="" INSTALL_STATUS=1 # 使用 timeout 命令(如果可用)或直接执行 # 注意:使用 bash -c 确保 sudo 函数在子 shell 中可用 if command -v timeout &> /dev/null; then INSTALL_OUTPUT=$(timeout 1800 bash -c "sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin" 2>&1) INSTALL_STATUS=$? if [[ $INSTALL_STATUS -eq 124 ]]; then echo "❌ 安装超时(30分钟),可能是网络问题或依赖解析失败" INSTALL_STATUS=1 fi else INSTALL_OUTPUT=$(sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin 2>&1) INSTALL_STATUS=$? fi # 重新启用 set -e set -e if [[ $INSTALL_STATUS -eq 0 ]]; then echo "✅ Docker CE 安装成功" else # 显示详细错误信息 echo "" echo "❌ Docker CE 批量安装失败" echo "错误详情:" echo "$INSTALL_OUTPUT" | tail -20 echo "" # 检查错误类型 if echo "$INSTALL_OUTPUT" | grep -qiE "(timeout|timed out|connection|网络|network)"; then echo "⚠️ 检测到可能的网络问题,请检查网络连接" fi if echo "$INSTALL_OUTPUT" | grep -qiE "(repo|repository|仓库|not found|找不到)"; then echo "⚠️ 检测到可能的仓库配置问题,请检查 Docker 源配置" fi echo "正在尝试逐个安装组件..." # 临时禁用 set -e set +e # 逐个安装组件 echo " - 正在安装 containerd.io..." CONTAINERD_OUTPUT=$(sudo dnf install -y containerd.io 2>&1) CONTAINERD_STATUS=$? if [[ $CONTAINERD_STATUS -eq 0 ]]; then echo " ✅ containerd.io 安装成功" else echo " ❌ containerd.io 安装失败" echo " 错误信息: $(echo "$CONTAINERD_OUTPUT" | tail -5)" fi echo " - 正在安装 docker-ce-cli..." DOCKER_CLI_OUTPUT=$(sudo dnf install -y docker-ce-cli 2>&1) DOCKER_CLI_STATUS=$? if [[ $DOCKER_CLI_STATUS -eq 0 ]]; then echo " ✅ docker-ce-cli 安装成功" else echo " ❌ docker-ce-cli 安装失败" echo " 错误信息: $(echo "$DOCKER_CLI_OUTPUT" | tail -5)" fi echo " - 正在安装 docker-ce..." DOCKER_CE_OUTPUT=$(sudo dnf install -y docker-ce 2>&1) DOCKER_CE_STATUS=$? if [[ $DOCKER_CE_STATUS -eq 0 ]]; then echo " ✅ docker-ce 安装成功" else echo " ❌ docker-ce 安装失败" echo " 错误信息: $(echo "$DOCKER_CE_OUTPUT" | tail -5)" fi echo " - 正在安装 docker-buildx-plugin..." BUILDX_OUTPUT=$(sudo dnf install -y docker-buildx-plugin 2>&1) BUILDX_STATUS=$? if [[ $BUILDX_STATUS -eq 0 ]]; then echo " ✅ docker-buildx-plugin 安装成功" else echo " ⚠️ docker-buildx-plugin 安装失败(可选组件,不影响核心功能)" fi # 重新启用 set -e set -e # 检查是否至少安装了核心组件 if ! command -v docker &> /dev/null; then echo "" echo "❌ 包管理器安装完全失败,尝试二进制安装..." # 二进制安装备选方案 echo "正在下载 Docker 二进制包..." # 尝试多个下载源 DOCKER_BINARY_DOWNLOADED=false # 源1: 阿里云镜像 echo "尝试从阿里云镜像下载 Docker 二进制包..." if curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从阿里云镜像下载成功" else echo "❌ 阿里云镜像下载失败,尝试下一个源..." fi # 源2: 腾讯云镜像 if [[ "$DOCKER_BINARY_DOWNLOADED" == "false" ]]; then echo "尝试从腾讯云镜像下载..." if curl -fsSL https://mirrors.cloud.tencent.com/docker-ce/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从腾讯云镜像下载成功" else echo "❌ 腾讯云镜像下载失败,尝试下一个源..." fi fi # 源3: 华为云镜像 if [[ "$DOCKER_BINARY_DOWNLOADED" == "false" ]]; then echo "尝试从华为云镜像下载..." if curl -fsSL https://mirrors.huaweicloud.com/docker-ce/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从华为云镜像下载成功" else echo "❌ 华为云镜像下载失败,尝试下一个源..." fi fi # 源4: 官方源 if [[ "$DOCKER_BINARY_DOWNLOADED" == "false" ]]; then echo "尝试从官方源下载..." if curl -fsSL https://download.docker.com/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从官方源下载成功" else echo "❌ 官方源下载失败" fi fi if [[ "$DOCKER_BINARY_DOWNLOADED" == "true" ]]; then echo "正在解压并安装 Docker 二进制包..." sudo tar -xzf /tmp/docker.tgz -C /usr/bin --strip-components=1 sudo chmod +x /usr/bin/docker* # 创建 systemd 服务文件 sudo tee /etc/systemd/system/docker.service > /dev/null < /dev/null </dev/null || true echo "✅ Docker 二进制安装成功" else echo "❌ 所有下载源都失败,无法安装 Docker" echo "请检查网络连接或手动安装 Docker" exit 1 fi fi fi sudo systemctl enable docker sudo systemctl start docker echo ">>> [3.5/8] 安装 Docker Compose..." # 安装最新版本的 docker-compose,使用多个备用下载源 echo "正在下载 Docker Compose..." # 尝试多个下载源 DOCKER_COMPOSE_DOWNLOADED=false # 源1: 阿里云镜像 echo "尝试从阿里云镜像下载..." if sudo curl -L "https://mirrors.aliyun.com/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从阿里云镜像下载成功" else echo "❌ 阿里云镜像下载失败,尝试下一个源..." fi # 源2: 腾讯云镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从腾讯云镜像下载..." if sudo curl -L "https://mirrors.cloud.tencent.com/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从腾讯云镜像下载成功" else echo "❌ 腾讯云镜像下载失败,尝试下一个源..." fi fi # 源3: 华为云镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从华为云镜像下载..." if sudo curl -L "https://mirrors.huaweicloud.com/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从华为云镜像下载成功" else echo "❌ 华为云镜像下载失败,尝试下一个源..." fi fi # 源4: 中科大镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从中科大镜像下载..." if sudo curl -L "https://mirrors.ustc.edu.cn/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从中科大镜像下载成功" else echo "❌ 中科大镜像下载失败,尝试下一个源..." fi fi # 源5: 清华大学镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从清华大学镜像下载..." if sudo curl -L "https://mirrors.tuna.tsinghua.edu.cn/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从清华大学镜像下载成功" else echo "❌ 清华大学镜像下载失败,尝试下一个源..." fi fi # 源6: 网易镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从网易镜像下载..." if sudo curl -L "https://mirrors.163.com/docker-toolbox/linux/compose/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从网易镜像下载成功" else echo "❌ 网易镜像下载失败,尝试下一个源..." fi fi # 源7: 最后尝试 GitHub (如果网络允许) if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "尝试从 GitHub 下载..." if sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从 GitHub 下载成功" else echo "❌ GitHub 下载失败" fi fi # 检查是否下载成功 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "❌ 所有下载源都失败了,尝试使用包管理器安装..." # 使用包管理器作为备选方案 if sudo dnf install -y docker-compose-plugin; then echo "✅ 通过包管理器安装 docker-compose-plugin 成功" DOCKER_COMPOSE_DOWNLOADED=true else echo "❌ 包管理器安装也失败了" fi fi if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "true" ]]; then # 设置执行权限 sudo chmod +x /usr/local/bin/docker-compose # 创建软链接到 PATH 目录 sudo ln -sf /usr/local/bin/docker-compose /usr/bin/docker-compose echo "✅ Docker Compose 安装完成" else echo "❌ Docker Compose 安装失败,请手动安装" echo "建议访问: https://docs.docker.com/compose/install/ 查看手动安装方法" fi elif [[ "$OS" == "ubuntu" || "$OS" == "debian" || "$OS" == "kali" || "$OS" == "deepin" ]]; then # 检查 Debian/Ubuntu/Kali/Deepin 版本,为老版本提供兼容性支持 if [[ ("$OS" == "debian" && ("$VERSION_ID" == "9" || "$VERSION_ID" == "10")) || ("$OS" == "ubuntu" && "$VERSION_ID" == "16.04") ]]; then if [[ "$OS" == "debian" && "$VERSION_ID" == "9" ]]; then echo "⚠️ 检测到 Debian 9 (Stretch),使用兼容的安装方法..." echo "⚠️ 注意:Debian 9 已于 2020年7月停止主线支持,2022年6月停止LTS支持" echo "⚠️ 建议升级到 Debian 10 (Buster) 或更高版本" elif [[ "$OS" == "debian" && "$VERSION_ID" == "10" ]]; then echo "⚠️ 检测到 Debian 10 (Buster),使用兼容的安装方法..." echo "⚠️ 注意:Debian 10 将于 2024年6月停止主线支持,建议考虑升级到 Debian 11+" elif [[ "$OS" == "ubuntu" && "$VERSION_ID" == "16.04" ]]; then echo "⚠️ 检测到 Ubuntu 16.04 (Xenial),使用兼容的安装方法..." echo "⚠️ 注意:Ubuntu 16.04 已于 2021 年结束生命周期,将使用特殊处理..." fi # 清理损坏的软件源索引文件 echo "正在清理损坏的软件源索引文件..." sudo rm -rf /var/lib/apt/lists/* sudo rm -rf /var/lib/apt/lists/partial/* # 强制清理 apt 缓存 sudo apt-get clean sudo apt-get autoclean # 为 Debian 9/10 或 Ubuntu 16.04 配置更兼容的软件源 if [[ "$OS" == "debian" && "$VERSION_ID" == "9" ]]; then echo "正在配置 Debian 9 兼容的软件源..." # ⚠️ Debian 9 (Stretch) 生命周期结束警告 echo "" echo "⚠️ ═══════════════════════════════════════════════════════════════════════════════" echo "⚠️ 重要提醒:Debian 9 (Stretch) 生命周期已结束" echo "⚠️ ═══════════════════════════════════════════════════════════════════════════════" echo "⚠️ 📅 2020 年 7 月:停止主线支持(EOL)" echo "⚠️ 📅 2022 年 6 月:停止 LTS(长期支持)" echo "⚠️ " echo "⚠️ 之后,不再在 deb.debian.org 和 security.debian.org 提供软件包" echo "⚠️ 建议升级到至少 Debian 10 (Buster) 或更高版本" echo "⚠️ " echo "⚠️ 当前将使用归档源继续安装,但强烈建议尽快升级系统" echo "⚠️ ═══════════════════════════════════════════════════════════════════════════════" echo "" # 备份原始源列表 sudo cp /etc/apt/sources.list /etc/apt/sources.list.backup.$(date +%Y%m%d_%H%M%S) # Debian 9 已停止支持,使用归档源 echo "正在配置 Debian 9 归档源(官方源已停止支持)..." # 使用官方归档源(亲测可用) sudo tee /etc/apt/sources.list > /dev/null < /dev/null </dev/null; then echo "✅ 当前软件源可用" else echo "⚠️ 当前软件源不可用,尝试切换到备用源..." # 尝试腾讯云镜像源 DEBIAN_CODENAME="stretch" sudo tee /etc/apt/sources.list > /dev/null </dev/null; then echo "✅ 腾讯云镜像源可用" else echo "⚠️ 腾讯云镜像源也不可用,尝试华为云镜像源..." # 尝试华为云镜像源 sudo tee /etc/apt/sources.list > /dev/null </dev/null; then echo "✅ 华为云镜像源可用" else echo "⚠️ 所有国内镜像源都不可用,回退到 archive.debian.org..." # 回退到 archive.debian.org sudo tee /etc/apt/sources.list > /dev/null </dev/null; then echo "✅ 当前软件源可用" else echo "⚠️ 当前软件源不可用,尝试切换到备用源..." # 尝试腾讯云镜像源 if [[ "$OS" == "debian" && "$VERSION_ID" == "10" ]]; then DEBIAN_CODENAME="buster" else DEBIAN_CODENAME="buster" # 默认使用 buster fi sudo tee /etc/apt/sources.list > /dev/null </dev/null; then echo "✅ 腾讯云镜像源可用" else echo "⚠️ 腾讯云镜像源也不可用,尝试华为云镜像源..." # 尝试华为云镜像源 sudo tee /etc/apt/sources.list > /dev/null </dev/null; then echo "✅ 华为云镜像源可用" else echo "⚠️ 所有国内镜像源都不可用,回退到 archive.debian.org..." # 回退到 archive.debian.org sudo tee /etc/apt/sources.list > /dev/null < /dev/null < /dev/null </dev/null || true echo "✅ Docker CE 二进制安装成功" # 启动 Docker 服务 echo "正在启动 Docker 服务..." sudo systemctl daemon-reload sudo systemctl enable docker # 尝试启动 Docker 服务 if sudo systemctl start docker; then echo "✅ Docker 服务启动成功" else echo "❌ Docker 服务启动失败,正在诊断问题..." # 检查服务状态 echo "Docker 服务状态:" sudo systemctl status docker --no-pager -l # 检查日志 echo "Docker 服务日志:" sudo journalctl -u docker --no-pager -l --since "5 minutes ago" # 尝试手动启动 dockerd 进行调试 echo "尝试手动启动 dockerd 进行调试..." sudo /usr/bin/dockerd --debug --log-level=debug & DOCKERD_PID=$! sleep 5 # 检查 dockerd 是否成功启动 if sudo kill -0 $DOCKERD_PID 2>/dev/null; then echo "✅ dockerd 手动启动成功,问题可能在 systemd 配置" sudo kill $DOCKERD_PID else echo "❌ dockerd 手动启动也失败,请检查系统兼容性" fi echo "故障排除建议:" echo "1. 检查系统是否支持 Docker" echo "2. 检查是否有其他容器运行时冲突" echo "3. 检查系统资源是否充足" echo "4. 尝试重启系统后再次运行脚本" exit 1 fi # 安装 Docker Compose echo ">>> [3.5/8] 安装 Docker Compose..." echo "正在下载 Docker Compose..." # 确定 Docker Compose 架构标识 if [[ "$ARCH" == "x86_64" ]]; then COMPOSE_ARCH="x86_64" elif [[ "$ARCH" == "aarch64" ]] || [[ "$ARCH" == "arm64" ]]; then COMPOSE_ARCH="aarch64" else COMPOSE_ARCH="$DOCKER_ARCH" fi # 尝试多个下载源 DOCKER_COMPOSE_DOWNLOADED=false # 直接使用 GitHub 官方源(最可靠) echo "正在从 GitHub 官方源下载 Docker Compose..." if sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-linux-${COMPOSE_ARCH}" -o /usr/local/bin/docker-compose --connect-timeout 30 --max-time 120; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从 GitHub 官方源下载成功" else echo "❌ GitHub 官方源下载失败" echo "💡 建议检查网络连接或使用代理" fi if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "true" ]]; then sudo chmod +x /usr/local/bin/docker-compose sudo ln -sf /usr/local/bin/docker-compose /usr/bin/docker-compose echo "✅ Docker Compose 安装完成" else echo "❌ 所有 Docker Compose 下载源都失败" echo "💡 建议:可以稍后手动安装 Docker Compose" echo " 下载地址:https://github.com/docker/compose/releases" fi # 跳过后续的包管理器安装流程 echo ">>> [4/8] Docker 安装完成,跳过包管理器安装流程..." echo "✅ Docker 已通过二进制方式安装成功" echo "✅ Docker Compose 已安装" echo "✅ Docker 服务已启动" # 直接进入镜像配置 echo ">>> [5/8] 配置轩辕镜像..." # 循环等待用户选择镜像版本 while true; do echo "请选择版本:" echo "1) 轩辕镜像免费版 (域名: docker.xuanyuan.me)" echo "2) 轩辕镜像专业版 (专属域名 *.xuanyuan.run / *.xuanyuan.dev 不含免费版域名)" echo "3) 恢复/重置镜像相关配置" read -p "请输入选择 [1/2/3]: " choice if [[ "$choice" == "1" || "$choice" == "2" ]]; then break elif [[ "$choice" == "3" ]]; then restore_docker_daemon_config exit $? else echo "❌ 无效选择,请输入 1、2 或 3" echo "" fi done mirror_list="" if [[ "$choice" == "2" ]]; then read -p "请输入您的轩辕镜像专属域名 (访问官网获取:https://xuanyuan.cloud): " custom_domain # 清理用户输入的域名,移除协议前缀 custom_domain=$(echo "$custom_domain" | sed 's|^https\?://||') # 清理用户输入的域名,移除协议前缀 custom_domain=$(echo "$custom_domain" | sed 's|^https\?://||') # 专业版:*.xuanyuan.run / *.xuanyuan.dev 成对配置(不含 docker.xuanyuan.me) if [[ "$custom_domain" == *.xuanyuan.run ]]; then custom_domain_dev="${custom_domain%.xuanyuan.run}.xuanyuan.dev" mirror_list=$(cat <>> [6/8] 安装完成!" echo "🎉Docker 镜像已配置完成" echo "轩辕镜像 · 专业版 - 开发者首选的专业 Docker 镜像高效稳定拉取服务" echo "官方网站: https://xuanyuan.cloud/" # 显示当前配置的镜像源 echo "" echo "当前配置的镜像源:" if [[ "$choice" == "2" ]]; then if [[ "$custom_domain" == *.xuanyuan.run ]]; then custom_domain_dev="${custom_domain%.xuanyuan.run}.xuanyuan.dev" echo " - https://$custom_domain (优先)" echo " - https://$custom_domain_dev (备用)" elif [[ "$custom_domain" == *.xuanyuan.dev ]]; then custom_domain_run="${custom_domain%.xuanyuan.dev}.xuanyuan.run" echo " - https://$custom_domain (优先)" echo " - https://$custom_domain_run (备用)" else echo " - https://$custom_domain" fi else echo " - https://docker.xuanyuan.me" fi echo "" echo "🎉 安装和配置完成!" echo "" echo "轩辕镜像 · 专业版 - 开发者首选的专业 Docker 镜像高效稳定拉取服务" echo "官方网站: https://xuanyuan.cloud/" exit 0 else echo "❌ 所有下载源都失败,无法安装 Docker" echo "请检查网络连接或手动安装 Docker" exit 1 fi fi # 如果 curl 安装失败,尝试使用 wget 作为备用 if ! command -v curl &> /dev/null && ! command -v wget &> /dev/null; then echo "正在安装 wget 作为 curl 的备用..." apt-get install -y --allow-unauthenticated wget || true fi # 现在尝试更新过期的 GPG 密钥 echo "正在更新过期的 GPG 密钥..." if command -v dirmngr &> /dev/null; then apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 648ACFD622F3D138 || true apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 0E98404D386FA1D9 || true apt-key adv --keyserver keyserver.ubuntu.com --recv-keys AA8E81B4331F7F50 || true apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 112695A0E562B32A || true # 尝试使用不同的密钥服务器 echo "尝试使用备用密钥服务器..." apt-key adv --keyserver pgpkeys.mit.edu --recv-keys 648ACFD622F3D138 || true apt-key adv --keyserver pgpkeys.mit.edu --recv-keys 0E98404D386FA1D9 || true else echo "⚠️ dirmngr 不可用,跳过 GPG 密钥更新" fi # 更新软件包列表,允许未认证的包,移除不支持的选项 echo "正在更新软件包列表..." # Debian 9 需要忽略过期校验 if [[ "$OS" == "debian" && "$VERSION_ID" == "9" ]]; then sudo apt-get update --allow-unauthenticated -o Acquire::Check-Valid-Until=false || true else sudo apt-get update --allow-unauthenticated || true fi # 如果还是失败,尝试强制更新 if [[ "$OS" == "debian" && "$VERSION_ID" == "9" ]]; then if ! sudo apt-get update --allow-unauthenticated -o Acquire::Check-Valid-Until=false; then echo "⚠️ 软件源更新失败,尝试强制更新..." sudo apt-get update --allow-unauthenticated --fix-missing -o Acquire::Check-Valid-Until=false || true fi else if ! sudo apt-get update --allow-unauthenticated; then echo "⚠️ 软件源更新失败,尝试强制更新..." sudo apt-get update --allow-unauthenticated --fix-missing || true fi fi # 安装必要的依赖包,允许未认证的包 echo "正在安装必要的依赖包..." sudo apt-get install -y --allow-unauthenticated --fix-broken ca-certificates gnupg lsb-release apt-transport-https || true # 如果某些包安装失败,尝试逐个安装 if ! dpkg -l | grep -q "ca-certificates"; then echo "尝试单独安装 ca-certificates..." sudo apt-get install -y --allow-unauthenticated ca-certificates || true fi if ! dpkg -l | grep -q "gnupg"; then echo "尝试单独安装 gnupg..." sudo apt-get install -y --allow-unauthenticated gnupg || true fi # 添加 Docker 官方 GPG 密钥 echo "正在添加 Docker 官方 GPG 密钥..." if command -v curl &> /dev/null; then # 尝试从国内镜像下载 GPG 密钥 if sudo curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/debian/gpg | sudo apt-key add -; then echo "✅ 从阿里云镜像下载 Docker GPG 密钥成功" elif sudo curl -fsSL https://mirrors.cloud.tencent.com/docker-ce/linux/debian/gpg | sudo apt-key add -; then echo "✅ 从腾讯云镜像下载 Docker GPG 密钥成功" elif sudo curl -fsSL https://mirrors.huaweicloud.com/docker-ce/linux/debian/gpg | sudo apt-key add -; then echo "✅ 从华为云镜像下载 Docker GPG 密钥成功" else echo "❌ 所有国内镜像都无法下载 Docker GPG 密钥" fi elif command -v wget &> /dev/null; then # 尝试从国内镜像下载 GPG 密钥 if sudo wget -qO- https://mirrors.aliyun.com/docker-ce/linux/debian/gpg | sudo apt-key add -; then echo "✅ 从阿里云镜像下载 Docker GPG 密钥成功" elif sudo wget -qO- https://mirrors.cloud.tencent.com/docker-ce/linux/debian/gpg | sudo apt-key add -; then echo "✅ 从腾讯云镜像下载 Docker GPG 密钥成功" elif sudo wget -qO- https://mirrors.huaweicloud.com/docker-ce/linux/debian/gpg | sudo apt-key add -; then echo "✅ 从华为云镜像下载 Docker GPG 密钥成功" else echo "❌ 所有国内镜像都无法下载 Docker GPG 密钥" fi else echo "❌ 无法下载 Docker GPG 密钥,curl 和 wget 都不可用" fi # 添加 Docker 仓库(使用国内镜像源) echo "正在添加 Docker 仓库..." if [[ "$OS" == "debian" && "$VERSION_ID" == "9" ]]; then DEBIAN_CODENAME="stretch" elif [[ "$OS" == "debian" && "$VERSION_ID" == "10" ]]; then DEBIAN_CODENAME="buster" else DEBIAN_CODENAME="stretch" # 默认使用 stretch fi # 尝试配置国内 Docker 镜像源 echo "deb [arch=$(dpkg --print-architecture)] https://mirrors.aliyun.com/docker-ce/linux/debian ${DEBIAN_CODENAME} stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null # 再次更新,这次包含 Docker 仓库 echo "正在更新包含 Docker 仓库的软件包列表..." # Debian 9 需要忽略过期校验 if [[ "$OS" == "debian" && "$VERSION_ID" == "9" ]]; then sudo apt-get update --allow-unauthenticated -o Acquire::Check-Valid-Until=false || true else sudo apt-get update --allow-unauthenticated || true fi echo ">>> [3/8] 安装 Docker CE 兼容版本..." echo "正在安装 Docker CE..." sudo apt-get install -y --allow-unauthenticated --fix-broken docker-ce docker-ce-cli containerd.io || true # 检查 Docker 是否安装成功 if command -v docker &> /dev/null; then echo "✅ Docker CE 安装成功" else echo "❌ Docker CE 安装失败,尝试备用方法..." # 尝试从多个源下载 Docker 二进制包 echo "正在下载 Docker 二进制包..." DOCKER_BINARY_DOWNLOADED=false if command -v curl &> /dev/null; then # 源1: 阿里云镜像 echo "尝试从阿里云镜像下载 Docker 二进制包..." if sudo curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从阿里云镜像下载成功" else echo "❌ 阿里云镜像下载失败,尝试下一个源..." fi # 源2: 腾讯云镜像 if [[ "$DOCKER_BINARY_DOWNLOADED" == "false" ]]; then echo "尝试从腾讯云镜像下载 Docker 二进制包..." if sudo curl -fsSL https://mirrors.cloud.tencent.com/docker-ce/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从腾讯云镜像下载成功" else echo "❌ 腾讯云镜像下载失败,尝试下一个源..." fi fi # 源3: 华为云镜像 if [[ "$DOCKER_BINARY_DOWNLOADED" == "false" ]]; then echo "尝试从华为云镜像下载 Docker 二进制包..." if sudo curl -fsSL https://mirrors.huaweicloud.com/docker-ce/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从华为云镜像下载成功" else echo "❌ 华为云镜像下载失败" fi fi elif command -v wget &> /dev/null; then # 源1: 阿里云镜像 echo "尝试从阿里云镜像下载 Docker 二进制包..." if sudo wget -O /tmp/docker.tgz https://mirrors.aliyun.com/docker-ce/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz --timeout=60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从阿里云镜像下载成功" else echo "❌ 阿里云镜像下载失败,尝试下一个源..." fi # 源2: 腾讯云镜像 if [[ "$DOCKER_BINARY_DOWNLOADED" == "false" ]]; then echo "尝试从腾讯云镜像下载 Docker 二进制包..." if sudo wget -O /tmp/docker.tgz https://mirrors.cloud.tencent.com/docker-ce/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz --timeout=60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从腾讯云镜像下载成功" else echo "❌ 腾讯云镜像下载失败,尝试下一个源..." fi fi # 源3: 华为云镜像 if [[ "$DOCKER_BINARY_DOWNLOADED" == "false" ]]; then echo "尝试从华为云镜像下载 Docker 二进制包..." if sudo wget -O /tmp/docker.tgz https://mirrors.huaweicloud.com/docker-ce/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz --timeout=60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从华为云镜像下载成功" else echo "❌ 华为云镜像下载失败" fi fi else echo "❌ 无法下载 Docker 二进制包,curl 和 wget 都不可用" fi if [[ "$DOCKER_BINARY_DOWNLOADED" == "true" && -f /tmp/docker.tgz ]]; then echo "正在解压 Docker 二进制包..." sudo tar -xzf /tmp/docker.tgz -C /tmp sudo cp /tmp/docker/* /usr/bin/ sudo chmod +x /usr/bin/docker* echo "✅ Docker CE 二进制安装成功" else echo "❌ Docker 二进制下载失败" fi fi echo ">>> [3.5/8] 安装 Docker Compose 兼容版本..." # Debian 9 使用较老版本的 docker-compose echo "正在下载兼容的 Docker Compose..." # 确定 Docker Compose 架构标识 if [[ "$ARCH" == "x86_64" ]]; then COMPOSE_ARCH="x86_64" elif [[ "$ARCH" == "aarch64" ]] || [[ "$ARCH" == "arm64" ]]; then COMPOSE_ARCH="aarch64" else COMPOSE_ARCH="$DOCKER_ARCH" fi DOCKER_COMPOSE_DOWNLOADED=false # 尝试从多个源下载兼容版本 echo "正在尝试从多个源下载 Docker Compose 兼容版本..." # 源1: 阿里云镜像 if command -v curl &> /dev/null; then echo "尝试从阿里云镜像下载兼容版本..." if sudo curl -L "https://mirrors.aliyun.com/docker-toolbox/linux/compose/1.25.5/docker-compose-linux-${COMPOSE_ARCH}" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从阿里云镜像下载兼容版本成功" fi elif command -v wget &> /dev/null; then echo "尝试从阿里云镜像下载兼容版本..." if sudo wget -O /usr/local/bin/docker-compose "https://mirrors.aliyun.com/docker-toolbox/linux/compose/1.25.5/docker-compose-linux-${COMPOSE_ARCH}" --timeout=30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从阿里云镜像下载兼容版本成功" fi fi # 源2: 腾讯云镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then if command -v curl &> /dev/null; then echo "尝试从腾讯云镜像下载兼容版本..." if sudo curl -L "https://mirrors.cloud.tencent.com/docker-toolbox/linux/compose/1.25.5/docker-compose-linux-${COMPOSE_ARCH}" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从腾讯云镜像下载兼容版本成功" fi elif command -v wget &> /dev/null; then echo "尝试从腾讯云镜像下载兼容版本..." if sudo wget -O /usr/local/bin/docker-compose "https://mirrors.cloud.tencent.com/docker-toolbox/linux/compose/1.25.5/docker-compose-linux-${COMPOSE_ARCH}" --timeout=30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从腾讯云镜像下载兼容版本成功" fi fi fi # 源3: 华为云镜像 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then if command -v curl &> /dev/null; then echo "尝试从华为云镜像下载兼容版本..." if curl -L "https://mirrors.huaweicloud.com/docker-toolbox/linux/compose/1.25.5/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从华为云镜像下载兼容版本成功" fi elif command -v wget &> /dev/null; then echo "尝试从华为云镜像下载兼容版本..." if sudo wget -O /usr/local/bin/docker-compose "https://mirrors.huaweicloud.com/docker-toolbox/linux/compose/1.25.5/docker-compose-$(uname -s)-$(uname -m)" --timeout=30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从华为云镜像下载兼容版本成功" fi fi fi # 源4: 最后尝试 GitHub if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then if command -v curl &> /dev/null; then echo "尝试从 GitHub 下载兼容版本..." if sudo curl -L "https://github.com/docker/compose/releases/download/1.25.5/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 10 --max-time 30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从 GitHub 下载兼容版本成功" fi elif command -v wget &> /dev/null; then echo "尝试从 GitHub 下载兼容版本..." if sudo wget -O /usr/local/bin/docker-compose "https://github.com/docker/compose/releases/download/1.25.5/docker-compose-$(uname -s)-$(uname -m)" --timeout=30; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从 GitHub 下载兼容版本成功" fi fi fi if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "❌ GitHub 下载失败,尝试包管理器安装..." if sudo apt-get install -y --allow-unauthenticated docker-compose; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 通过包管理器安装 docker-compose 成功" else echo "❌ 包管理器安装也失败了" fi fi if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "true" ]]; then sudo chmod +x /usr/local/bin/docker-compose sudo ln -sf /usr/local/bin/docker-compose /usr/bin/docker-compose echo "✅ Docker Compose 兼容版本安装完成" else echo "❌ Docker Compose 安装失败" fi else # 现代版本的 Ubuntu/Debian/Kali 使用标准安装方法 sudo apt-get update # 安装必要的依赖包,添加错误处理和容错机制 echo "正在安装必要的依赖包..." if sudo apt-get install -y --fix-missing ca-certificates curl gnupg lsb-release; then echo "✅ 必要依赖包安装成功" else echo "⚠️ 批量安装失败,尝试逐个安装..." # 逐个安装依赖包 if sudo apt-get install -y --fix-missing ca-certificates; then echo "✅ ca-certificates 安装成功" else echo "⚠️ ca-certificates 安装失败,将尝试继续..." fi if sudo apt-get install -y --fix-missing curl; then echo "✅ curl 安装成功" else echo "⚠️ curl 安装失败,将尝试继续..." fi if sudo apt-get install -y --fix-missing gnupg; then echo "✅ gnupg 安装成功" else echo "⚠️ gnupg 安装失败,将尝试继续..." fi if sudo apt-get install -y --fix-missing lsb-release; then echo "✅ lsb-release 安装成功" else echo "⚠️ lsb-release 安装失败,将尝试继续..." fi # 检查关键工具是否安装成功 if ! command -v curl &> /dev/null && ! command -v wget &> /dev/null; then echo "⚠️ curl 和 wget 都未安装,某些功能可能受限..." fi if ! command -v gpg &> /dev/null; then echo "⚠️ gpg 未安装,某些功能可能受限..." fi if ! command -v lsb_release &> /dev/null; then echo "⚠️ lsb-release 未安装,将使用备用方法检测系统版本..." # 如果 lsb-release 未安装,使用 /etc/os-release 作为备用 if [[ -f /etc/os-release ]]; then DEBIAN_CODENAME_BACKUP=$(awk -F= '/^VERSION_CODENAME=/{print $2}' /etc/os-release | tr -d '"' 2>/dev/null || echo "") fi fi fi # Kali Linux 需要使用 Debian 仓库 DOCKER_OS="$OS" # 如果 lsb-release 安装成功,使用它;否则使用备用方法 if command -v lsb_release &> /dev/null; then DEBIAN_CODENAME=$(lsb_release -cs) elif [[ -n "$DEBIAN_CODENAME_BACKUP" ]]; then DEBIAN_CODENAME="$DEBIAN_CODENAME_BACKUP" echo "⚠️ 使用备用方法检测到系统代号: $DEBIAN_CODENAME" else # 最后的备用方法 DEBIAN_CODENAME=$(awk -F= '/^VERSION_CODENAME=/{print $2}' /etc/os-release | tr -d '"' 2>/dev/null || echo "bookworm") echo "⚠️ 使用 /etc/os-release 检测到系统代号: $DEBIAN_CODENAME" fi # 检测 Debian Testing/Unstable 并映射到稳定版本 if [[ "$OS" == "debian" ]]; then # 检查是否为 Debian Testing/Unstable(代号可能是 forky、trixie、sid 等) VERSION_CODENAME=$(awk -F= '/^VERSION_CODENAME=/{print $2}' /etc/os-release | tr -d '"' 2>/dev/null || echo "") # Debian Testing 的常见代号:forky(当前)、trixie(未来) # Debian Unstable 的代号:sid(固定) # Docker 官方仓库不支持 Testing/Unstable 版本,需要映射到对应的稳定版本 if [[ "$DEBIAN_CODENAME" == "forky" ]] || [[ "$VERSION_CODENAME" == "forky" ]] || \ [[ "$DEBIAN_CODENAME" == "trixie" ]] || [[ "$VERSION_CODENAME" == "trixie" ]] || \ [[ "$DEBIAN_CODENAME" == "sid" ]] || [[ "$VERSION_CODENAME" == "sid" ]] || \ [[ -n "$VERSION_CODENAME" && ("$VERSION_CODENAME" == "testing" || "$VERSION_CODENAME" == "unstable") ]]; then echo "⚠️ 检测到 Debian Testing/Unstable (codename: $DEBIAN_CODENAME)" echo "⚠️ Docker 官方仓库不支持 Testing/Unstable 版本,将使用 Debian 12 (bookworm) 仓库" DEBIAN_CODENAME="bookworm" fi fi if [[ "$OS" == "kali" ]]; then DOCKER_OS="debian" # Kali Rolling 基于 Debian Testing,使用 bookworm 作为稳定版本 # 根据 Kali 版本映射到对应的 Debian 代号 case "$DEBIAN_CODENAME" in kali-rolling|kali-dev) DEBIAN_CODENAME="bookworm" ;; *) # 其他情况默认使用 bookworm DEBIAN_CODENAME="bookworm" ;; esac echo "⚠️ Kali Linux 将使用 Debian Docker 仓库 (codename: $DEBIAN_CODENAME)" fi if [[ "$OS" == "deepin" ]]; then DOCKER_OS="debian" DEEPIN_ORIG_CODENAME="$DEBIAN_CODENAME" # Docker 无 linux/deepin;Deepin 自有代号(如 crimson、beige)需映射到 Debian stable suite case "$DEBIAN_CODENAME" in crimson|beige|nymph|martian) DEBIAN_CODENAME="bookworm" ;; apricot|eagle) DEBIAN_CODENAME="bullseye" ;; *) if [[ -n "$DEBIAN_CODENAME" ]]; then echo "⚠️ Deepin 代号 $DEBIAN_CODENAME 未在映射表,默认使用 bookworm Docker 源(若失败请反馈)" fi DEBIAN_CODENAME="bookworm" ;; esac echo "ℹ️ Deepin $VERSION_ID(${DEEPIN_ORIG_CODENAME:-unknown})→ Docker 使用 debian/$DEBIAN_CODENAME" fi # 检测 Ubuntu 版本并处理 if [[ "$OS" == "ubuntu" ]]; then VERSION_CODENAME=$(awk -F= '/^VERSION_CODENAME=/{print $2}' /etc/os-release | tr -d '"' 2>/dev/null || echo "") ORIGINAL_CODENAME="$DEBIAN_CODENAME" # Ubuntu LTS:bionic/focal/jammy/noble;较新版本先试自身,失败回退 noble case "$DEBIAN_CODENAME" in bionic|focal|jammy|noble) ;; plucky) echo "ℹ️ 检测到 Ubuntu 25.04 (Plucky Puffin)" echo "ℹ️ 将首先尝试使用 Ubuntu 25.04 仓库,如果失败将回退到 Ubuntu 24.04 LTS (noble)" ;; questing) echo "ℹ️ 检测到 Ubuntu 25.10 (Questing Quokka)" echo "ℹ️ 将首先尝试使用此版本仓库,如果失败将回退到 Ubuntu 24.04 LTS (noble)" ;; resolute) echo "ℹ️ 检测到 Ubuntu 26.04 (Resolute Raccoon)" echo "ℹ️ 将首先尝试使用此版本仓库,如果失败将回退到 Ubuntu 24.04 LTS (noble)" ;; warty|hoary|breezy|dapper|edgy|feisty|gutsy|hardy|intrepid|jaunty|karmic|lucid|maverick|natty|oneiric|precise|quantal|raring|saucy|trusty|utopic|vivid|wily|xenial|yakkety|zesty|artful|cosmic|disco|eoan|groovy|hirsute|impish|kinetic|lunar|mantic|oracular) echo "⚠️ 检测到 Ubuntu 旧版本 (codename: $DEBIAN_CODENAME)" echo "⚠️ Docker 官方仓库不支持此版本,将使用 Ubuntu 24.04 LTS (noble) 仓库" DEBIAN_CODENAME="noble" ;; "") echo "⚠️ 无法检测 Ubuntu 版本代号,将使用 Ubuntu 24.04 LTS (noble)" DEBIAN_CODENAME="noble" ;; *) echo "ℹ️ 检测到 Ubuntu 新版本 (codename: $DEBIAN_CODENAME)" echo "ℹ️ 将首先尝试使用此版本的仓库,如果失败将回退到 Ubuntu 24.04 LTS (noble)" ;; esac else ORIGINAL_CODENAME="${DEBIAN_CODENAME:-}" fi sudo install -m 0755 -d /etc/apt/keyrings # 清理可能存在的旧配置 sudo rm -f /etc/apt/keyrings/docker.gpg /etc/apt/sources.list.d/docker.list 2>/dev/null # GPG 密钥下载和验证辅助函数 download_and_verify_gpg_key() { local gpg_url=$1 local key_file="/etc/apt/keyrings/docker.gpg" local error_output="/tmp/docker_gpg_error.log" if curl -fsSL "$gpg_url" 2>"$error_output" | sudo gpg --dearmor -o "$key_file" 2>"$error_output"; then if [[ -f "$key_file" ]] && [[ $(stat -f%z "$key_file" 2>/dev/null || stat -c%s "$key_file" 2>/dev/null || echo 0) -gt 1000 ]]; then sudo chmod 644 "$key_file" 2>/dev/null || true rm -f "$error_output" 2>/dev/null return 0 else echo "⚠️ GPG 密钥文件大小异常或不存在" rm -f "$key_file" "$error_output" 2>/dev/null return 1 fi else if [[ -f "$error_output" ]]; then echo "⚠️ GPG 密钥下载/处理失败: $(cat "$error_output" 2>/dev/null | head -1)" rm -f "$error_output" 2>/dev/null fi rm -f "$key_file" 2>/dev/null return 1 fi } # 探测 URL 是否可下载:优先 HEAD,失败再用 Range GET(兼容禁用 HEAD 的环境) # 注意:不要用 `curl ... || echo 000`,否则失败时会把 "404" 与 "000" 拼成 "404000" probe_package_url_reachable() { local url=$1 local http_code http_code=$(curl -sI -o /dev/null -w "%{http_code}" --connect-timeout 10 --max-time 20 "$url" 2>/dev/null || true) [[ "$http_code" =~ ^[0-9]+$ ]] || http_code="000" if [[ "$http_code" == "200" || "$http_code" == "301" || "$http_code" == "302" || "$http_code" == "307" || "$http_code" == "308" ]]; then return 0 fi # 部分镜像对 HEAD 返回 403/405,改用只取首字节的 GET 验证文件存在 http_code=$(curl -sL -o /dev/null -w "%{http_code}" -r 0-0 --connect-timeout 10 --max-time 20 "$url" 2>/dev/null || true) [[ "$http_code" =~ ^[0-9]+$ ]] || http_code="000" if [[ "$http_code" == "200" || "$http_code" == "206" ]]; then return 0 fi printf '%s' "$http_code" return 1 } # 校验当前 apt 源中「候选版本」docker-ce / docker-ce-cli 的 pool 是否可下载 # 必须用 Candidate,避免 apt-cache show 取到旧 Filename 导致误判部分同步镜像可用 verify_docker_ce_pool_packages() { local base_url pkg candidate filename full_url probe_out base_url=$(awk '/^deb /{for(i=1;i<=NF;i++) if($i ~ /^https?:\/\//){print $i; exit}}' /etc/apt/sources.list.d/docker.list 2>/dev/null) if [[ -z "$base_url" ]]; then return 1 fi for pkg in docker-ce docker-ce-cli; do candidate=$(apt-cache policy "$pkg" 2>/dev/null | awk '/Candidate:/{print $2; exit}') if [[ -z "$candidate" || "$candidate" == "(none)" ]]; then echo "⚠️ 无法获取 ${pkg} 的候选版本" return 1 fi filename=$(apt-cache show "${pkg}=${candidate}" 2>/dev/null | awk '/^Filename:/{print $2; exit}') if [[ -z "$filename" ]]; then # 兼容部分 apt 对 =version 支持不佳:在 show 输出中匹配该 Version 块的 Filename filename=$(apt-cache show "$pkg" 2>/dev/null | awk -v ver="$candidate" ' /^Package:/ { in_pkg=0; ver_ok=0 } /^Package: / { in_pkg=1 } in_pkg && $1=="Version:" && $2==ver { ver_ok=1 } in_pkg && ver_ok && /^Filename:/ { print $2; exit } ') fi if [[ -z "$filename" ]]; then echo "⚠️ 无法从索引获取 ${pkg}=${candidate} 的 Filename" return 1 fi full_url="${base_url%/}/${filename}" if ! probe_out=$(probe_package_url_reachable "$full_url"); then echo "⚠️ 索引可用但候选软件包不可下载: ${pkg}=${candidate} (HTTP ${probe_out:-000})" echo " 镜像可能未同步完整,尝试下一个源..." return 1 fi done return 0 } # 配置单个 Docker apt 镜像;成功返回 0 try_configure_docker_apt_mirror() { local name=$1 local mirror_root=$2 local repo_base="${mirror_root}/linux/${DOCKER_OS}" local update_output="/tmp/docker_apt_update.log" echo "尝试配置${name} Docker 源..." sudo rm -f /etc/apt/keyrings/docker.gpg /etc/apt/sources.list.d/docker.list 2>/dev/null if ! download_and_verify_gpg_key "${repo_base}/gpg"; then echo "❌ ${name} Docker GPG 密钥下载失败,尝试下一个源..." return 1 fi echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] ${repo_base} \ ${DEBIAN_CODENAME} stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null if ! sudo apt-get update >"$update_output" 2>&1; then echo "❌ ${name} Docker 源配置失败" if [[ -f "$update_output" ]] && grep -q "NO_PUBKEY\|GPG error" "$update_output" 2>/dev/null; then echo " 错误详情: $(grep -i "NO_PUBKEY\|GPG error" "$update_output" | head -1)" fi rm -f "$update_output" 2>/dev/null echo " 尝试下一个源..." return 1 fi rm -f "$update_output" 2>/dev/null if ! verify_docker_ce_pool_packages; then sudo rm -f /etc/apt/keyrings/docker.gpg /etc/apt/sources.list.d/docker.list 2>/dev/null return 1 fi echo "✅ ${name} Docker 源配置成功" return 0 } DOCKER_APT_MIRROR_ENTRIES=( "阿里云|https://mirrors.aliyun.com/docker-ce" "腾讯云|https://mirrors.cloud.tencent.com/docker-ce" "华为云|https://mirrors.huaweicloud.com/docker-ce" "中科大|https://mirrors.ustc.edu.cn/docker-ce" "清华大学|https://mirrors.tuna.tsinghua.edu.cn/docker-ce" "网易|https://mirrors.163.com/docker-ce" "官方|https://download.docker.com" ) configure_docker_apt_from_mirrors() { local entry name mirror_root DOCKER_REPO_ADDED=false DOCKER_MIRROR_NAME="" for entry in "${DOCKER_APT_MIRROR_ENTRIES[@]}"; do name="${entry%%|*}" mirror_root="${entry#*|}" if try_configure_docker_apt_mirror "$name" "$mirror_root"; then DOCKER_REPO_ADDED=true DOCKER_MIRROR_NAME="$name" return 0 fi done return 1 } # 较新/未知 Ubuntu 代号在自身仓库不可用时应回退到 noble ubuntu_should_fallback_to_noble() { [[ "$OS" != "ubuntu" ]] && return 1 [[ "$DEBIAN_CODENAME" == "noble" ]] && return 1 case "${ORIGINAL_CODENAME}" in plucky|questing|resolute|oracular) return 0 ;; bionic|focal|jammy|noble|"") return 1 ;; *) # 未知新版本且仍使用自身代号 [[ "$DEBIAN_CODENAME" == "$ORIGINAL_CODENAME" ]] && return 0 return 1 ;; esac } echo "正在配置 Docker 源..." DOCKER_REPO_ADDED=false DOCKER_MIRROR_NAME="" configure_docker_apt_from_mirrors || true # 源配置失败时,对新 Ubuntu 版本回退到 noble / jammy if [[ "$DOCKER_REPO_ADDED" == "false" ]] && [[ "$OS" == "ubuntu" ]]; then if ubuntu_should_fallback_to_noble; then echo "⚠️ Ubuntu ${ORIGINAL_CODENAME} 源配置失败,回退到 Ubuntu 24.04 LTS (noble)..." DEBIAN_CODENAME="noble" configure_docker_apt_from_mirrors || true fi if [[ "$DOCKER_REPO_ADDED" == "false" ]] && [[ "$DEBIAN_CODENAME" == "noble" ]] && [[ "$ORIGINAL_CODENAME" != "noble" ]]; then echo "⚠️ Ubuntu 24.04 LTS (noble) 源配置失败,尝试回退到 Ubuntu 22.04 LTS (jammy)..." DEBIAN_CODENAME="jammy" configure_docker_apt_from_mirrors || true fi fi if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then echo "❌ 所有 Docker 源都配置失败,无法继续安装" echo "" echo "可能的原因:" echo " 1. 网络连接问题" echo " 2. 发行版代号与 Docker 仓库不匹配,或镜像暂不支持该代号" echo " 3. GPG 密钥验证失败或镜像 pool 未同步完整" if [[ "$OS" == "kali" ]]; then echo " 4. Kali 须使用 Debian Docker 源(debian/${DEBIAN_CODENAME}),勿使用 kali-rolling" fi echo "" echo "建议解决方案:" echo " 1. 检查网络连接" echo " 2. 手动添加 Docker GPG 密钥:" echo " curl -fsSL https://download.docker.com/linux/${DOCKER_OS}/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg" echo " 3. 手动配置 Docker 源:" echo " echo \"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/${DOCKER_OS} ${DEBIAN_CODENAME} stable\" | sudo tee /etc/apt/sources.list.d/docker.list" echo " 4. 更新软件包列表:" echo " sudo apt-get update" exit 1 fi install_docker_ce_packages() { sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin } echo ">>> [3/8] 安装 Docker CE 最新版(含 Compose 插件)..." DOCKER_CE_INSTALLED=false if install_docker_ce_packages; then DOCKER_CE_INSTALLED=true else echo "❌ 当前源 (${DOCKER_MIRROR_NAME:-unknown}) 安装失败,尝试切换其他镜像源重试..." for local_entry in "${DOCKER_APT_MIRROR_ENTRIES[@]}"; do name="${local_entry%%|*}" mirror_root="${local_entry#*|}" if [[ -n "$DOCKER_MIRROR_NAME" && "$name" == "$DOCKER_MIRROR_NAME" ]]; then continue fi if try_configure_docker_apt_mirror "$name" "$mirror_root"; then DOCKER_MIRROR_NAME="$name" if install_docker_ce_packages; then DOCKER_CE_INSTALLED=true break fi fi done fi # 安装仍失败且代号较新时,回退 noble 再装一轮 if [[ "$DOCKER_CE_INSTALLED" == "false" ]] && ubuntu_should_fallback_to_noble; then echo "⚠️ 使用 ${DEBIAN_CODENAME} 安装失败,回退到 Ubuntu 24.04 LTS (noble) 重试安装..." DEBIAN_CODENAME="noble" if configure_docker_apt_from_mirrors; then if install_docker_ce_packages; then DOCKER_CE_INSTALLED=true else echo "❌ noble 源安装失败,继续尝试切换镜像..." for local_entry in "${DOCKER_APT_MIRROR_ENTRIES[@]}"; do name="${local_entry%%|*}" mirror_root="${local_entry#*|}" if [[ -n "$DOCKER_MIRROR_NAME" && "$name" == "$DOCKER_MIRROR_NAME" ]]; then continue fi if try_configure_docker_apt_mirror "$name" "$mirror_root"; then DOCKER_MIRROR_NAME="$name" if install_docker_ce_packages; then DOCKER_CE_INSTALLED=true break fi fi done fi fi fi if [[ "$DOCKER_CE_INSTALLED" == "false" ]]; then echo "❌ Docker CE 安装失败,所有镜像源均无法完成安装" exit 1 fi echo ">>> [3.5/8] 配置 Docker Compose..." # 优先使用 apt 的 docker-compose-plugin;不再使用未校验的 docker-toolbox HTML 下载 DOCKER_COMPOSE_READY=false if docker compose version >/dev/null 2>&1; then DOCKER_COMPOSE_READY=true echo "✅ docker-compose-plugin 可用: $(docker compose version 2>/dev/null | head -1)" elif sudo apt-get install -y docker-compose-plugin && docker compose version >/dev/null 2>&1; then DOCKER_COMPOSE_READY=true echo "✅ 通过包管理器安装 docker-compose-plugin 成功" else echo "⚠️ docker-compose-plugin 不可用,尝试下载经校验的 Compose 二进制..." download_compose_binary_validated() { local url=$1 local dest="/usr/local/bin/docker-compose" local tmp="/tmp/docker-compose.download.$$" rm -f "$tmp" if ! curl -fsSL "$url" -o "$tmp" --connect-timeout 10 --max-time 120; then rm -f "$tmp" return 1 fi local size size=$(stat -c%s "$tmp" 2>/dev/null || stat -f%z "$tmp" 2>/dev/null || echo 0) if [[ "$size" -lt 1000000 ]]; then echo "⚠️ 下载文件过小 (${size} bytes),已丢弃" rm -f "$tmp" return 1 fi if head -c 256 "$tmp" 2>/dev/null | grep -qiE '/dev/null | od -An -tx1 | grep -qi '7f 45 4c 46'; then echo "⚠️ 下载文件不是 ELF 二进制,已丢弃" rm -f "$tmp" return 1 fi sudo mv "$tmp" "$dest" sudo chmod +x "$dest" return 0 } compose_url="https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" echo "尝试下载: $compose_url" if download_compose_binary_validated "$compose_url"; then DOCKER_COMPOSE_READY=true echo "✅ Compose 二进制下载并校验成功" fi fi if [[ "$DOCKER_COMPOSE_READY" == "true" ]]; then # 兼容旧命令 docker-compose:若已是真实二进制则保留,否则写入包装脚本 if [[ -x /usr/local/bin/docker-compose ]] && head -c 4 /usr/local/bin/docker-compose 2>/dev/null | od -An -tx1 | grep -qi '7f 45 4c 46'; then sudo ln -sf /usr/local/bin/docker-compose /usr/bin/docker-compose else # 清理可能被旧脚本写入的 HTML 伪二进制 sudo rm -f /usr/local/bin/docker-compose /usr/bin/docker-compose 2>/dev/null sudo tee /usr/local/bin/docker-compose >/dev/null <<'COMPOSE_WRAPPER' #!/bin/sh exec docker compose "$@" COMPOSE_WRAPPER sudo chmod +x /usr/local/bin/docker-compose sudo ln -sf /usr/local/bin/docker-compose /usr/bin/docker-compose fi echo "✅ Docker Compose 安装完成(docker compose / docker-compose)" else echo "❌ Docker Compose 安装失败,无法继续" echo "建议: sudo apt-get install -y docker-compose-plugin" echo "或访问: https://docs.docker.com/compose/install/" exit 1 fi fi elif [[ "$OS" == "centos" || "$OS" == "rhel" || "$OS" == "rocky" || "$OS" == "ol" ]]; then sudo yum install -y yum-utils # 尝试多个国内镜像源 echo "正在配置 Docker 源..." DOCKER_REPO_ADDED=false # 创建Docker仓库配置文件,直接使用国内镜像地址 echo "正在创建 Docker 仓库配置..." # 根据系统版本选择正确的仓库路径 # 使用数值比较以支持版本10及以上 VERSION_MAJOR="${VERSION_ID%%.*}" if [[ "$VERSION_MAJOR" -ge 10 ]]; then # CentOS Stream 10+ 使用 CentOS 9 仓库(兼容处理) CENTOS_VERSION="9" echo "检测到 CentOS/RHEL/Rocky Linux ${VERSION_ID},使用 CentOS 9 仓库(兼容模式)" elif [[ "$VERSION_MAJOR" == "9" ]]; then CENTOS_VERSION="9" echo "检测到 CentOS/RHEL/Rocky Linux 9,使用 CentOS 9 仓库" elif [[ "$VERSION_MAJOR" == "8" ]]; then CENTOS_VERSION="8" echo "检测到 CentOS/RHEL/Rocky Linux 8,使用 CentOS 8 仓库" else CENTOS_VERSION="7" echo "检测到 CentOS/RHEL/Rocky Linux 7,使用 CentOS 7 仓库" fi # 源1: 阿里云镜像 echo "尝试配置阿里云 Docker 源..." sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null <>> [3/8] 安装 Docker CE 最新版..." # 临时禁用 set -e,允许错误处理 set +e echo "正在尝试安装 Docker CE(这可能需要几分钟,请耐心等待)..." echo "如果安装过程卡住,可能是网络问题或依赖解析中,请等待..." # 尝试安装 Docker,使用超时机制(30分钟超时) INSTALL_OUTPUT="" INSTALL_STATUS=1 # 使用 timeout 命令(如果可用)或直接执行 # 注意:使用 bash -c 确保 sudo 函数在子 shell 中可用 if command -v timeout &> /dev/null; then INSTALL_OUTPUT=$(timeout 1800 bash -c "sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin --nobest" 2>&1) INSTALL_STATUS=$? if [[ $INSTALL_STATUS -eq 124 ]]; then echo "❌ 安装超时(30分钟),可能是网络问题或依赖解析失败" INSTALL_STATUS=1 fi else INSTALL_OUTPUT=$(sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin --nobest 2>&1) INSTALL_STATUS=$? fi # 重新启用 set -e set -e if [[ $INSTALL_STATUS -eq 0 ]]; then echo "✅ Docker CE 安装成功" else # 显示详细错误信息 echo "" echo "❌ Docker CE 批量安装失败" echo "错误详情:" echo "$INSTALL_OUTPUT" | tail -20 echo "" # 检查错误类型 if echo "$INSTALL_OUTPUT" | grep -qiE "(timeout|timed out|connection|网络|network)"; then echo "⚠️ 检测到可能的网络问题,请检查网络连接" fi if echo "$INSTALL_OUTPUT" | grep -qiE "(repo|repository|仓库|not found|找不到)"; then echo "⚠️ 检测到可能的仓库配置问题,请检查 Docker 源配置" fi echo "正在尝试逐个安装组件..." # 临时禁用 set -e set +e # 逐个安装组件 echo " - 正在安装 containerd.io..." CONTAINERD_OUTPUT=$(sudo yum install -y containerd.io --nobest 2>&1) CONTAINERD_STATUS=$? if [[ $CONTAINERD_STATUS -eq 0 ]]; then echo " ✅ containerd.io 安装成功" else echo " ❌ containerd.io 安装失败" echo " 错误信息: $(echo "$CONTAINERD_OUTPUT" | tail -5)" fi echo " - 正在安装 docker-ce-cli..." DOCKER_CLI_OUTPUT=$(sudo yum install -y docker-ce-cli --nobest 2>&1) DOCKER_CLI_STATUS=$? if [[ $DOCKER_CLI_STATUS -eq 0 ]]; then echo " ✅ docker-ce-cli 安装成功" else echo " ❌ docker-ce-cli 安装失败" echo " 错误信息: $(echo "$DOCKER_CLI_OUTPUT" | tail -5)" fi echo " - 正在安装 docker-ce..." DOCKER_CE_OUTPUT=$(sudo yum install -y docker-ce --nobest 2>&1) DOCKER_CE_STATUS=$? if [[ $DOCKER_CE_STATUS -eq 0 ]]; then echo " ✅ docker-ce 安装成功" else echo " ❌ docker-ce 安装失败" echo " 错误信息: $(echo "$DOCKER_CE_OUTPUT" | tail -5)" fi echo " - 正在安装 docker-buildx-plugin..." BUILDX_OUTPUT=$(sudo yum install -y docker-buildx-plugin --nobest 2>&1) BUILDX_STATUS=$? if [[ $BUILDX_STATUS -eq 0 ]]; then echo " ✅ docker-buildx-plugin 安装成功" else echo " ⚠️ docker-buildx-plugin 安装失败(可选组件,不影响核心功能)" fi # 重新启用 set -e set -e # 检查是否至少安装了核心组件 if ! command -v docker &> /dev/null; then echo "❌ 包管理器安装完全失败,尝试二进制安装..." # 二进制安装备选方案 echo "正在下载 Docker 二进制包..." # 尝试多个下载源 DOCKER_BINARY_DOWNLOADED=false # 源1: 阿里云镜像 echo "尝试从阿里云镜像下载 Docker 二进制包..." if curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从阿里云镜像下载成功" else echo "❌ 阿里云镜像下载失败,尝试下一个源..." fi # 源2: 腾讯云镜像 if [[ "$DOCKER_BINARY_DOWNLOADED" == "false" ]]; then echo "尝试从腾讯云镜像下载..." if curl -fsSL https://mirrors.cloud.tencent.com/docker-ce/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从腾讯云镜像下载成功" else echo "❌ 腾讯云镜像下载失败,尝试下一个源..." fi fi # 源3: 华为云镜像 if [[ "$DOCKER_BINARY_DOWNLOADED" == "false" ]]; then echo "尝试从华为云镜像下载..." if curl -fsSL https://mirrors.huaweicloud.com/docker-ce/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从华为云镜像下载成功" else echo "❌ 华为云镜像下载失败,尝试下一个源..." fi fi # 源4: 官方源 if [[ "$DOCKER_BINARY_DOWNLOADED" == "false" ]]; then echo "尝试从官方源下载..." if curl -fsSL https://download.docker.com/linux/static/stable/${DOCKER_ARCH}/docker-20.10.24.tgz -o /tmp/docker.tgz --connect-timeout 10 --max-time 60; then DOCKER_BINARY_DOWNLOADED=true echo "✅ 从官方源下载成功" else echo "❌ 官方源下载失败" fi fi if [[ "$DOCKER_BINARY_DOWNLOADED" == "true" ]]; then echo "正在解压并安装 Docker 二进制包..." sudo tar -xzf /tmp/docker.tgz -C /usr/bin --strip-components=1 sudo chmod +x /usr/bin/docker* # 创建 systemd 服务文件 sudo tee /etc/systemd/system/docker.service > /dev/null < /dev/null </dev/null || true echo "✅ Docker 二进制安装成功" else echo "❌ 所有下载源都失败,无法安装 Docker" echo "请检查网络连接或手动安装 Docker" exit 1 fi fi fi sudo systemctl enable docker sudo systemctl start docker echo ">>> [3.5/8] 安装 Docker Compose..." # 安装最新版本的 docker-compose,直接使用 GitHub 官方源 echo "正在下载 Docker Compose..." # 直接使用 GitHub 官方源(最可靠) echo "正在从 GitHub 官方源下载 Docker Compose..." if sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose --connect-timeout 30 --max-time 120; then DOCKER_COMPOSE_DOWNLOADED=true echo "✅ 从 GitHub 官方源下载成功" else echo "❌ GitHub 官方源下载失败" echo "💡 建议检查网络连接或使用代理" fi # 检查是否下载成功 if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "false" ]]; then echo "❌ 所有下载源都失败了,尝试使用包管理器安装..." # 使用包管理器作为备选方案 if [[ "$OS" == "ubuntu" || "$OS" == "debian" || "$OS" == "kali" || "$OS" == "deepin" ]]; then if sudo apt-get install -y docker-compose-plugin; then echo "✅ 通过包管理器安装 docker-compose-plugin 成功" DOCKER_COMPOSE_DOWNLOADED=true else echo "❌ 包管理器安装也失败了" fi elif [[ "$OS" == "centos" || "$OS" == "rhel" || "$OS" == "rocky" || "$OS" == "ol" || "$OS" == "kylin" || "$OS" == "uos" || "$OS" == "uniontechos" || "$OS_LOWER" == "hce" || "$OS_LOWER" == "openeuler" ]]; then if sudo yum install -y docker-compose-plugin; then echo "✅ 通过包管理器安装 docker-compose-plugin 成功" DOCKER_COMPOSE_DOWNLOADED=true else echo "❌ 包管理器安装也失败了" fi fi fi if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "true" ]]; then # 设置执行权限 sudo chmod +x /usr/local/bin/docker-compose # 创建软链接到 PATH 目录 sudo ln -sf /usr/local/bin/docker-compose /usr/bin/docker-compose echo "✅ Docker Compose 安装完成" else echo "❌ Docker Compose 安装失败,请手动安装" echo "建议访问: https://docs.docker.com/compose/install/ 查看手动安装方法" fi else echo "❌ 暂不支持该系统: $OS" echo "💡 若需适配本系统,请到轩辕镜像官网提交工单寻求支持:" echo " https://xuanyuan.cloud/tickets" exit 1 fi echo ">>> [5/8] 配置国内镜像..." # 循环等待用户选择镜像版本 while true; do echo "请选择版本:" echo "1) 轩辕镜像免费版 (域名: docker.xuanyuan.me)" echo "2) 轩辕镜像专业版 (专属域名 *.xuanyuan.run / *.xuanyuan.dev 不含免费版域名)" echo "3) 恢复/重置镜像相关配置" read -p "请输入选择 [1/2/3]: " choice if [[ "$choice" == "1" || "$choice" == "2" ]]; then break elif [[ "$choice" == "3" ]]; then restore_docker_daemon_config exit $? else echo "❌ 无效选择,请输入 1、2 或 3" echo "" fi done mirror_list="" if [[ "$choice" == "2" ]]; then read -p "请输入您的轩辕镜像专属域名 (访问官网获取:https://xuanyuan.cloud): " custom_domain # 清理用户输入的域名,移除协议前缀 custom_domain=$(echo "$custom_domain" | sed 's|^https\?://||') # 专业版:*.xuanyuan.run / *.xuanyuan.dev 成对配置(不含 docker.xuanyuan.me) if [[ "$custom_domain" == *.xuanyuan.run ]]; then custom_domain_dev="${custom_domain%.xuanyuan.run}.xuanyuan.dev" mirror_list=$(cat </dev/null; then PID1_COMM_SCRIPT=$(tr -d '\0' < /proc/1/comm 2>/dev/null || echo "") if [[ "$PID1_COMM_SCRIPT" == "systemd" ]] && systemctl show-environment &>/dev/null 2>&1; then SCRIPT_SYSTEMD_OK=true fi fi echo ">>> [6/8] 安装完成!" echo "🎉Docker 镜像已配置完成" echo "轩辕镜像 · 专业版 - 开发者首选的专业 Docker 镜像高效稳定拉取服务" echo "官方网站: https://xuanyuan.cloud/" echo ">>> [7/8] 验证 Docker 服务..." # 等待 Docker 服务完全启动 echo "等待 Docker 服务启动..." sleep 3 # 验证 Docker:优先 docker info(无 systemd 时 systemctl 不可用) DOCKER_VERIFIED=false if docker info &>/dev/null; then DOCKER_VERIFIED=true elif [[ "$SCRIPT_SYSTEMD_OK" == "true" ]] && systemctl is-active --quiet docker 2>/dev/null; then DOCKER_VERIFIED=true fi if [[ "$DOCKER_VERIFIED" == "true" ]]; then echo "✅ Docker 服务已成功启动" echo "✅ 镜像配置已生效" # 显示当前配置的镜像源 echo "当前配置的镜像源:" if [[ "$choice" == "2" ]]; then if [[ "$custom_domain" == *.xuanyuan.run ]]; then custom_domain_dev="${custom_domain%.xuanyuan.run}.xuanyuan.dev" echo " - https://$custom_domain (优先)" echo " - https://$custom_domain_dev (备用)" elif [[ "$custom_domain" == *.xuanyuan.dev ]]; then custom_domain_run="${custom_domain%.xuanyuan.dev}.xuanyuan.run" echo " - https://$custom_domain (优先)" echo " - https://$custom_domain_run (备用)" else echo " - https://$custom_domain" fi else echo " - https://docker.xuanyuan.me" fi echo "" echo "🎉 安装和配置完成!" echo "" # 将执行脚本的用户添加到 docker 组 echo ">>> [8/8] 配置用户权限..." # 定义函数:安全地添加用户到 docker 组 add_user_to_docker_group() { local target_user="$1" if ! groups "$target_user" | grep -q "\bdocker\b"; then echo "⚠️ 注意:将用户 $target_user 加入 docker 组意味着赋予该用户 root 级权限。" echo "⚠️ 这可能会带来安全风险。如果您不确定,请选择 'n'。" read -p "是否继续将 $target_user 添加到 docker 组?[Y/n] " confirm_add_group confirm_add_group=${confirm_add_group:-Y} if [[ "$confirm_add_group" =~ ^[Yy]$ ]]; then sudo usermod -aG docker "$target_user" 2>/dev/null || true echo "✅ 已将用户 $target_user 添加到 docker 组" echo "⚠️ 请重新登录或执行 'newgrp docker' 使权限生效" else echo "ℹ️ 已跳过用户组配置" fi else echo "✅ 用户 $target_user 已在 docker 组中" fi } if [ -n "$SUDO_USER" ]; then # 如果通过 sudo 执行 add_user_to_docker_group "$SUDO_USER" elif [ "$(id -u)" -ne 0 ]; then # 如果直接以非 root 用户执行 add_user_to_docker_group "$USER" else # 如果已经是 root 用户,提示信息 echo "ℹ️ 当前以 root 用户执行,无需添加到 docker 组" fi echo "" echo "轩辕镜像 · 专业版 - 开发者首选的专业 Docker 镜像高效稳定拉取服务" echo "官方网站: https://xuanyuan.cloud/" else echo "❌ 无法连接到 Docker daemon(可能未安装 docker-ce 或未启动)。/etc/docker/daemon.json 已写入。" echo "💡 统信等环境可先执行: sudo dnf remove -y docker-runc && sudo dnf install -y --allowerasing docker-ce" echo "💡 在物理机/虚拟机: sudo systemctl enable --now docker;无 systemd 环境可尝试: sudo dockerd &" exit 1 fi