Files
Sean 0dbebc1a45 新增一键脚本备用地址
新增一键脚本备用地址
2026-08-22 20:22:38 +08:00

7443 lines
282 KiB
Bash
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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" <<EOF
{
"registry-mirrors": $mirror_list
}
EOF
fi
if ! _validate_json_object_file "$tmp_json"; then
rm -f "$tmp_json"
echo "❌ 生成的配置不是合法 JSON 对象,已中止,未修改原文件"
return 1
fi
backup_daemon_json
sudo cp "$tmp_json" /etc/docker/daemon.json
rm -f "$tmp_json"
if _daemon_merge_tools_available; then
echo "✅ 镜像配置已写入 /etc/docker/daemon.json(已合并保留现有自定义项)"
else
echo "✅ 镜像配置已写入 /etc/docker/daemon.json(仅 registry-mirrors)"
fi
return 0
}
restart_docker_for_config() {
local SCRIPT_SYSTEMD_OK=false
if command -v systemctl &>/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 <<EOF
[
"https://$custom_domain",
"https://$custom_domain_dev"
]
EOF
)
elif [[ "$custom_domain" == *.xuanyuan.dev ]]; then
custom_domain_run="${custom_domain%.xuanyuan.dev}.xuanyuan.run"
mirror_list=$(cat <<EOF
[
"https://$custom_domain",
"https://$custom_domain_run"
]
EOF
)
else
mirror_list=$(cat <<EOF
[
"https://$custom_domain"
]
EOF
)
fi
else
mirror_list=$(cat <<EOF
[
"https://docker.xuanyuan.me"
]
EOF
)
fi
# 创建 Docker 配置目录
sudo mkdir -p /etc/docker
apply_docker_mirror_config "$mirror_list"
apply_rc=$?
if [[ $apply_rc -eq 2 ]]; then
exit 0
elif [[ $apply_rc -ne 0 ]]; then
exit 1
fi
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 "🎉 镜像配置完成!"
exit 0
elif [[ "$mode_choice" == "3" ]]; then
echo ""
echo ">>> 模式:恢复 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 <<EOF
[
"https://$custom_domain",
"https://$custom_domain_dev"
]
EOF
)
elif [[ "$custom_domain" == *.xuanyuan.dev ]]; then
custom_domain_run="${custom_domain%.xuanyuan.dev}.xuanyuan.run"
mirror_list=$(cat <<EOF
[
"https://$custom_domain",
"https://$custom_domain_run"
]
EOF
)
else
mirror_list=$(cat <<EOF
[
"https://$custom_domain"
]
EOF
)
fi
else
mirror_list=$(cat <<EOF
[
"https://docker.xuanyuan.me"
]
EOF
)
fi
sudo mkdir -p /etc/docker
apply_docker_mirror_config "$mirror_list"
apply_rc=$?
if [[ $apply_rc -eq 2 ]]; then
exit 0
elif [[ $apply_rc -ne 0 ]]; then
exit 1
fi
echo ">>> [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 <<EOF
[
"https://$custom_domain",
"https://$custom_domain_dev"
]
EOF
)
elif [[ "$custom_domain" == *.xuanyuan.dev ]]; then
custom_domain_run="${custom_domain%.xuanyuan.dev}.xuanyuan.run"
mirror_list=$(cat <<EOF
[
"https://$custom_domain",
"https://$custom_domain_run"
]
EOF
)
else
mirror_list=$(cat <<EOF
[
"https://$custom_domain"
]
EOF
)
fi
else
mirror_list=$(cat <<EOF
[
"https://docker.xuanyuan.me"
]
EOF
)
fi
sudo mkdir -p /etc/docker
apply_docker_mirror_config "$mirror_list"
apply_rc=$?
if [[ $apply_rc -eq 2 ]]; then
exit 0
elif [[ $apply_rc -ne 0 ]]; then
exit 1
fi
echo ">>> [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 <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.aliyun.com/docker-ce/linux/centos/${centos_version}/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/docker-ce/linux/centos/gpg
EOF
;;
2)
echo "尝试配置腾讯云 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.cloud.tencent.com/docker-ce/linux/centos/${centos_version}/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.cloud.tencent.com/docker-ce/linux/centos/gpg
EOF
;;
3)
echo "尝试配置中科大 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.ustc.edu.cn/docker-ce/linux/centos/${centos_version}/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.ustc.edu.cn/docker-ce/linux/centos/gpg
EOF
;;
4)
echo "尝试配置清华大学 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/${centos_version}/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/gpg
EOF
;;
5)
echo "尝试配置官方 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://download.docker.com/linux/centos/${centos_version}/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://download.docker.com/linux/centos/gpg
EOF
;;
*)
return 1
;;
esac
# 清理缓存并更新
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
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 <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.huaweicloud.com/docker-ce/linux/centos/${CENTOS_VERSION}/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.huaweicloud.com/docker-ce/linux/centos/gpg
EOF
if sudo $PKG_MANAGER makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 华为云 Docker 源配置成功"
else
echo "❌ 华为云 Docker 源配置失败,尝试下一个源..."
fi
# 源2: 阿里云镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置阿里云 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.aliyun.com/docker-ce/linux/centos/${CENTOS_VERSION}/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/docker-ce/linux/centos/gpg
EOF
if sudo $PKG_MANAGER makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 阿里云 Docker 源配置成功"
else
echo "❌ 阿里云 Docker 源配置失败,尝试下一个源..."
fi
fi
# 源3: 腾讯云镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置腾讯云 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.cloud.tencent.com/docker-ce/linux/centos/${CENTOS_VERSION}/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.cloud.tencent.com/docker-ce/linux/centos/gpg
EOF
if sudo $PKG_MANAGER makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 腾讯云 Docker 源配置成功"
else
echo "❌ 腾讯云 Docker 源配置失败,尝试下一个源..."
fi
fi
# 源4: 中科大镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置中科大 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.ustc.edu.cn/docker-ce/linux/centos/${CENTOS_VERSION}/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.ustc.edu.cn/docker-ce/linux/centos/gpg
EOF
if sudo $PKG_MANAGER makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 中科大 Docker 源配置成功"
else
echo "❌ 中科大 Docker 源配置失败,尝试下一个源..."
fi
fi
# 源5: 清华大学镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置清华大学 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/${CENTOS_VERSION}/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/gpg
EOF
if sudo $PKG_MANAGER makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 清华大学 Docker 源配置成功"
else
echo "❌ 清华大学 Docker 源配置失败,尝试下一个源..."
fi
fi
# 如果所有国内源都失败,尝试官方源
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "所有国内源都失败,尝试官方源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://download.docker.com/linux/centos/${CENTOS_VERSION}/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://download.docker.com/linux/centos/gpg
EOF
if sudo $PKG_MANAGER makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 官方 Docker 源配置成功"
else
echo "❌ 官方 Docker 源也配置失败"
fi
fi
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "❌ 所有 Docker 源都配置失败,无法继续安装"
echo "请检查网络连接或手动配置 Docker 源"
exit 1
fi
echo ">>> [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 <<EOF
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service time-set.target
Wants=network-online.target
Requires=docker.socket
[Service]
Type=notify
ExecStart=/usr/bin/dockerd -H fd://
ExecReload=/bin/kill -s HUP \$MAINPID
TimeoutStartSec=0
RestartSec=2
Restart=always
StartLimitBurst=3
StartLimitInterval=60s
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
Delegate=yes
KillMode=process
OOMScoreAdjust=-500
[Install]
WantedBy=multi-user.target
EOF
# 创建 docker.socket 文件
sudo tee /etc/systemd/system/docker.socket > /dev/null <<EOF
[Unit]
Description=Docker Socket for the API
[Socket]
ListenStream=/var/run/docker.sock
SocketMode=0660
SocketUser=root
SocketGroup=docker
[Install]
WantedBy=sockets.target
EOF
# 创建 docker 用户组
sudo groupadd docker 2>/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 <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.aliyun.com/docker-ce/linux/centos/9/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/docker-ce/linux/centos/gpg
EOF
if sudo dnf makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 阿里云 Docker 源配置成功"
else
echo "❌ 阿里云 Docker 源配置失败,尝试下一个源..."
fi
# 源2: 腾讯云镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置腾讯云 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.cloud.tencent.com/docker-ce/linux/centos/9/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.cloud.tencent.com/docker-ce/linux/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.cloud.tencent.com/docker-ce/linux/centos/gpg
EOF
if sudo dnf makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 腾讯云 Docker 源配置成功"
else
echo "❌ 腾讯云 Docker 源配置失败,尝试下一个源..."
fi
fi
# 源3: 华为云镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置华为云 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.huaweicloud.com/docker-ce/linux/centos/9/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.huaweicloud.com/docker-ce/linux/centos/gpg
EOF
if sudo dnf makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 华为云 Docker 源配置成功"
else
echo "❌ 华为云 Docker 源配置失败,尝试下一个源..."
fi
fi
# 源4: 中科大镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置中科大 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.ustc.edu.cn/docker-ce/linux/centos/9/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.ustc.edu.cn/docker-ce/linux/centos/gpg
EOF
if sudo dnf makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 中科大 Docker 源配置成功"
else
echo "❌ 中科大 Docker 源配置失败,尝试下一个源..."
fi
fi
# 源5: 清华大学镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置清华大学 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/9/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/gpg
EOF
if sudo dnf makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 清华大学 Docker 源配置成功"
else
echo "❌ 清华大学 Docker 源配置失败,尝试下一个源..."
fi
fi
# 如果所有国内源都失败,尝试官方源
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "所有国内源都失败,尝试官方源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://download.docker.com/linux/centos/9/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://download.docker.com/linux/centos/gpg
EOF
if sudo dnf makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 官方 Docker 源配置成功"
else
echo "❌ 官方 Docker 源也配置失败"
fi
fi
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "❌ 所有 Docker 源都配置失败,无法继续安装"
echo "请检查网络连接或手动配置 Docker 源"
exit 1
fi
echo ">>> [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 <<EOF
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service time-set.target
Wants=network-online.target
Requires=docker.socket
[Service]
Type=notify
ExecStart=/usr/bin/dockerd -H fd://
ExecReload=/bin/kill -s HUP \$MAINPID
TimeoutStartSec=0
RestartSec=2
Restart=always
StartLimitBurst=3
StartLimitInterval=60s
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
Delegate=yes
KillMode=process
OOMScoreAdjust=-500
[Install]
WantedBy=multi-user.target
EOF
# 创建 docker.socket 文件
sudo tee /etc/systemd/system/docker.socket > /dev/null <<EOF
[Unit]
Description=Docker Socket for the API
[Socket]
ListenStream=/var/run/docker.sock
SocketMode=0660
SocketUser=root
SocketGroup=docker
[Install]
WantedBy=sockets.target
EOF
# 创建 docker 用户组
sudo groupadd docker 2>/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 <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.aliyun.com/docker-ce/linux/centos/${CENTOS_VERSION}/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/docker-ce/linux/centos/gpg
EOF
if sudo $PKG_MANAGER makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 阿里云 Docker 源配置成功"
else
echo "❌ 阿里云 Docker 源配置失败,尝试下一个源..."
fi
# 源2: 腾讯云镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置腾讯云 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.cloud.tencent.com/docker-ce/linux/centos/${CENTOS_VERSION}/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.cloud.tencent.com/docker-ce/linux/centos/gpg
EOF
if sudo $PKG_MANAGER makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 腾讯云 Docker 源配置成功"
else
echo "❌ 腾讯云 Docker 源配置失败,尝试下一个源..."
fi
fi
# 源3: 华为云镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置华为云 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.huaweicloud.com/docker-ce/linux/centos/${CENTOS_VERSION}/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.huaweicloud.com/docker-ce/linux/centos/gpg
EOF
if sudo $PKG_MANAGER makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 华为云 Docker 源配置成功"
else
echo "❌ 华为云 Docker 源配置失败,尝试下一个源..."
fi
fi
# 源4: 中科大镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置中科大 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.ustc.edu.cn/docker-ce/linux/centos/${CENTOS_VERSION}/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.ustc.edu.cn/docker-ce/linux/centos/gpg
EOF
if sudo $PKG_MANAGER makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 中科大 Docker 源配置成功"
else
echo "❌ 中科大 Docker 源配置失败,尝试下一个源..."
fi
fi
# 源5: 清华大学镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置清华大学 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/${CENTOS_VERSION}/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/gpg
EOF
if sudo $PKG_MANAGER makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 清华大学 Docker 源配置成功"
else
echo "❌ 清华大学 Docker 源配置失败,尝试下一个源..."
fi
fi
# 如果所有国内源都失败,尝试官方源
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "所有国内源都失败,尝试官方源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://download.docker.com/linux/centos/${CENTOS_VERSION}/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://download.docker.com/linux/centos/gpg
EOF
if sudo $PKG_MANAGER makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 官方 Docker 源配置成功"
else
echo "❌ 官方 Docker 源也配置失败"
fi
fi
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "❌ 所有 Docker 源都配置失败,无法继续安装"
echo "请检查网络连接或手动配置 Docker 源"
exit 1
fi
echo ">>> [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 <<EOF
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service time-set.target
Wants=network-online.target
Requires=docker.socket
[Service]
Type=notify
ExecStart=/usr/bin/dockerd -H fd://
ExecReload=/bin/kill -s HUP \$MAINPID
TimeoutStartSec=0
RestartSec=2
Restart=always
StartLimitBurst=3
StartLimitInterval=60s
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
Delegate=yes
KillMode=process
OOMScoreAdjust=-500
[Install]
WantedBy=multi-user.target
EOF
# 创建 docker.socket 文件
sudo tee /etc/systemd/system/docker.socket > /dev/null <<EOF
[Unit]
Description=Docker Socket for the API
[Socket]
ListenStream=/var/run/docker.sock
SocketMode=0660
SocketUser=root
SocketGroup=docker
[Install]
WantedBy=sockets.target
EOF
# 创建 docker 用户组
sudo groupadd docker 2>/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 <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.aliyun.com/docker-ce/linux/centos/${CENTOS_VERSION}/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/docker-ce/linux/centos/gpg
EOF
if sudo $PKG_MANAGER makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 阿里云 Docker 源配置成功"
else
echo "❌ 阿里云 Docker 源配置失败,尝试下一个源..."
fi
# 源2: 腾讯云镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置腾讯云 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.cloud.tencent.com/docker-ce/linux/centos/${CENTOS_VERSION}/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.cloud.tencent.com/docker-ce/linux/centos/gpg
EOF
if sudo $PKG_MANAGER makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 腾讯云 Docker 源配置成功"
else
echo "❌ 腾讯云 Docker 源配置失败,尝试下一个源..."
fi
fi
# 源3: 华为云镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置华为云 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.huaweicloud.com/docker-ce/linux/centos/${CENTOS_VERSION}/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.huaweicloud.com/docker-ce/linux/centos/gpg
EOF
if sudo $PKG_MANAGER makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 华为云 Docker 源配置成功"
else
echo "❌ 华为云 Docker 源配置失败,尝试下一个源..."
fi
fi
# 源4: 中科大镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置中科大 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.ustc.edu.cn/docker-ce/linux/centos/${CENTOS_VERSION}/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.ustc.edu.cn/docker-ce/linux/centos/gpg
EOF
if sudo $PKG_MANAGER makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 中科大 Docker 源配置成功"
else
echo "❌ 中科大 Docker 源配置失败,尝试下一个源..."
fi
fi
# 源5: 清华大学镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置清华大学 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/${CENTOS_VERSION}/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/gpg
EOF
if sudo $PKG_MANAGER makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 清华大学 Docker 源配置成功"
else
echo "❌ 清华大学 Docker 源配置失败,尝试下一个源..."
fi
fi
# 如果所有国内源都失败,尝试官方源
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "所有国内源都失败,尝试官方源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://download.docker.com/linux/centos/${CENTOS_VERSION}/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://download.docker.com/linux/centos/gpg
EOF
if sudo $PKG_MANAGER makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 官方 Docker 源配置成功"
else
echo "❌ 官方 Docker 源也配置失败"
fi
fi
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "❌ 所有 Docker 源都配置失败,无法继续安装"
echo "请检查网络连接或手动配置 Docker 源"
exit 1
fi
echo ">>> [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 <<EOF
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service time-set.target
Wants=network-online.target
Requires=docker.socket
[Service]
Type=notify
ExecStart=/usr/bin/dockerd -H fd://
ExecReload=/bin/kill -s HUP \$MAINPID
TimeoutStartSec=0
RestartSec=2
Restart=always
StartLimitBurst=3
StartLimitInterval=60s
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
Delegate=yes
KillMode=process
OOMScoreAdjust=-500
[Install]
WantedBy=multi-user.target
EOF
# 创建 docker.socket 文件
sudo tee /etc/systemd/system/docker.socket > /dev/null <<EOF
[Unit]
Description=Docker Socket for the API
[Socket]
ListenStream=/var/run/docker.sock
SocketMode=0660
SocketUser=root
SocketGroup=docker
[Install]
WantedBy=sockets.target
EOF
# 创建 docker 用户组
sudo groupadd docker 2>/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 <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.aliyun.com/docker-ce/linux/fedora/\$releasever/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/docker-ce/linux/fedora/gpg
EOF
if sudo dnf makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 阿里云 Docker 源配置成功"
else
echo "❌ 阿里云 Docker 源配置失败,尝试下一个源..."
fi
# 源2: 腾讯云镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置腾讯云 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.cloud.tencent.com/docker-ce/linux/fedora/\$releasever/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.cloud.tencent.com/docker-ce/linux/fedora/gpg
EOF
if sudo dnf makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 腾讯云 Docker 源配置成功"
else
echo "❌ 腾讯云 Docker 源配置失败,尝试下一个源..."
fi
fi
# 源3: 华为云镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置华为云 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.huaweicloud.com/docker-ce/linux/fedora/\$releasever/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.huaweicloud.com/docker-ce/linux/fedora/gpg
EOF
if sudo dnf makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 华为云 Docker 源配置成功"
else
echo "❌ 华为云 Docker 源配置失败,尝试下一个源..."
fi
fi
# 源4: 中科大镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置中科大 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.ustc.edu.cn/docker-ce/linux/fedora/\$releasever/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.ustc.edu.cn/docker-ce/linux/fedora/gpg
EOF
if sudo dnf makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 中科大 Docker 源配置成功"
else
echo "❌ 中科大 Docker 源配置失败,尝试下一个源..."
fi
fi
# 源5: 清华大学镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置清华大学 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/fedora/\$releasever/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/fedora/gpg
EOF
if sudo dnf makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 清华大学 Docker 源配置成功"
else
echo "❌ 清华大学 Docker 源配置失败,尝试下一个源..."
fi
fi
# 如果所有国内源都失败,尝试官方源
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "所有国内源都失败,尝试官方源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://download.docker.com/linux/fedora/\$releasever/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://download.docker.com/linux/fedora/gpg
EOF
if sudo dnf makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 官方 Docker 源配置成功"
else
echo "❌ 官方 Docker 源也配置失败"
fi
fi
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "❌ 所有 Docker 源都配置失败,无法继续安装"
echo "请检查网络连接或手动配置 Docker 源"
exit 1
fi
echo ">>> [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 <<EOF
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service time-set.target
Wants=network-online.target
Requires=docker.socket
[Service]
Type=notify
ExecStart=/usr/bin/dockerd -H fd://
ExecReload=/bin/kill -s HUP \$MAINPID
TimeoutStartSec=0
RestartSec=2
Restart=always
StartLimitBurst=3
StartLimitInterval=60s
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
Delegate=yes
KillMode=process
OOMScoreAdjust=-500
[Install]
WantedBy=multi-user.target
EOF
# 创建 docker.socket 文件
sudo tee /etc/systemd/system/docker.socket > /dev/null <<EOF
[Unit]
Description=Docker Socket for the API
[Socket]
ListenStream=/var/run/docker.sock
SocketMode=0660
SocketUser=root
SocketGroup=docker
[Install]
WantedBy=sockets.target
EOF
# 创建 docker 用户组
sudo groupadd docker 2>/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 <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.aliyun.com/docker-ce/linux/centos/9/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/docker-ce/linux/centos/gpg
EOF
if sudo dnf makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 阿里云 Docker 源配置成功"
else
echo "❌ 阿里云 Docker 源配置失败,尝试下一个源..."
fi
# 源2: 腾讯云镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置腾讯云 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.cloud.tencent.com/docker-ce/linux/centos/9/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.cloud.tencent.com/docker-ce/linux/centos/gpg
EOF
if sudo dnf makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 腾讯云 Docker 源配置成功"
else
echo "❌ 腾讯云 Docker 源配置失败,尝试下一个源..."
fi
fi
# 源3: 华为云镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置华为云 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.huaweicloud.com/docker-ce/linux/centos/9/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.huaweicloud.com/docker-ce/linux/centos/gpg
EOF
if sudo dnf makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 华为云 Docker 源配置成功"
else
echo "❌ 华为云 Docker 源配置失败,尝试下一个源..."
fi
fi
# 源4: 中科大镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置中科大 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.ustc.edu.cn/docker-ce/linux/centos/9/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.ustc.edu.cn/docker-ce/linux/centos/gpg
EOF
if sudo dnf makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 中科大 Docker 源配置成功"
else
echo "❌ 中科大 Docker 源配置失败,尝试下一个源..."
fi
fi
# 源5: 清华大学镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置清华大学 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/9/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/gpg
EOF
if sudo dnf makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 清华大学 Docker 源配置成功"
else
echo "❌ 清华大学 Docker 源配置失败,尝试下一个源..."
fi
fi
# 如果所有国内源都失败,尝试官方源
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "所有国内源都失败,尝试官方源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://download.docker.com/linux/centos/9/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://download.docker.com/linux/centos/gpg
EOF
if sudo dnf makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 官方 Docker 源配置成功"
else
echo "❌ 官方 Docker 源也配置失败"
fi
fi
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "❌ 所有 Docker 源都配置失败,无法继续安装"
echo "请检查网络连接或手动配置 Docker 源"
exit 1
fi
echo ">>> [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 <<EOF
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service time-set.target
Wants=network-online.target
Requires=docker.socket
[Service]
Type=notify
ExecStart=/usr/bin/dockerd -H fd://
ExecReload=/bin/kill -s HUP \$MAINPID
TimeoutStartSec=0
RestartSec=2
Restart=always
StartLimitBurst=3
StartLimitInterval=60s
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
Delegate=yes
KillMode=process
OOMScoreAdjust=-500
[Install]
WantedBy=multi-user.target
EOF
# 创建 docker.socket 文件
sudo tee /etc/systemd/system/docker.socket > /dev/null <<EOF
[Unit]
Description=Docker Socket for the API
[Socket]
ListenStream=/var/run/docker.sock
SocketMode=0660
SocketUser=root
SocketGroup=docker
[Install]
WantedBy=sockets.target
EOF
# 创建 docker 用户组
sudo groupadd docker 2>/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 <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.aliyun.com/docker-ce/linux/centos/${CENTOS_VERSION}/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/docker-ce/linux/centos/gpg
EOF
if sudo $PKG_MANAGER makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 阿里云 Docker 源配置成功"
else
echo "❌ 阿里云 Docker 源配置失败,尝试下一个源..."
fi
# 源2: 腾讯云镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置腾讯云 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.cloud.tencent.com/docker-ce/linux/centos/${CENTOS_VERSION}/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.cloud.tencent.com/docker-ce/linux/centos/gpg
EOF
if sudo $PKG_MANAGER makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 腾讯云 Docker 源配置成功"
else
echo "❌ 腾讯云 Docker 源配置失败,尝试下一个源..."
fi
fi
# 源3: 华为云镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置华为云 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.huaweicloud.com/docker-ce/linux/centos/${CENTOS_VERSION}/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.huaweicloud.com/docker-ce/linux/centos/gpg
EOF
if sudo $PKG_MANAGER makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 华为云 Docker 源配置成功"
else
echo "❌ 华为云 Docker 源配置失败,尝试下一个源..."
fi
fi
# 源4: 中科大镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置中科大 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.ustc.edu.cn/docker-ce/linux/centos/${CENTOS_VERSION}/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.ustc.edu.cn/docker-ce/linux/centos/gpg
EOF
if sudo $PKG_MANAGER makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 中科大 Docker 源配置成功"
else
echo "❌ 中科大 Docker 源配置失败,尝试下一个源..."
fi
fi
# 源5: 清华大学镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置清华大学 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/${CENTOS_VERSION}/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/gpg
EOF
if sudo $PKG_MANAGER makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 清华大学 Docker 源配置成功"
else
echo "❌ 清华大学 Docker 源配置失败,尝试下一个源..."
fi
fi
# 如果所有国内源都失败,尝试官方源
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "所有国内源都失败,尝试官方源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://download.docker.com/linux/centos/${CENTOS_VERSION}/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://download.docker.com/linux/centos/gpg
EOF
if sudo $PKG_MANAGER makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 官方 Docker 源配置成功"
else
echo "❌ 官方 Docker 源也配置失败"
fi
fi
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "❌ 所有 Docker 源都配置失败,无法继续安装"
echo "请检查网络连接或手动配置 Docker 源"
exit 1
fi
echo ">>> [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 <<EOF 2>/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 <<EOF
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service time-set.target
Wants=network-online.target
Requires=docker.socket
[Service]
Type=notify
ExecStart=/usr/bin/dockerd -H fd://
ExecReload=/bin/kill -s HUP \$MAINPID
TimeoutStartSec=0
RestartSec=2
Restart=always
StartLimitBurst=3
StartLimitInterval=60s
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
Delegate=yes
KillMode=process
OOMScoreAdjust=-500
[Install]
WantedBy=multi-user.target
EOF
# 创建 docker.socket 文件
sudo tee /etc/systemd/system/docker.socket > /dev/null <<EOF
[Unit]
Description=Docker Socket for the API
[Socket]
ListenStream=/var/run/docker.sock
SocketMode=0660
SocketUser=root
SocketGroup=docker
[Install]
WantedBy=sockets.target
EOF
# 创建 docker 用户组
sudo groupadd docker 2>/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 "<!DOCTYPE\|<html"; then
echo "❌ 下载的文件是 HTML 页面,不是二进制文件"
fi
sudo rm -f "$COMPOSE_TMP"
fi
fi
fi
fi
if [[ "$DOCKER_COMPOSE_DOWNLOADED" == "true" ]]; then
# 如果安装的是独立的 docker-compose 二进制文件
if [[ -f /usr/local/bin/docker-compose ]]; then
# 设置执行权限
sudo chmod +x /usr/local/bin/docker-compose
# 创建软链接到 PATH 目录
sudo ln -sf /usr/local/bin/docker-compose /usr/bin/docker-compose 2>/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 <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.aliyun.com/docker-ce/linux/centos/9/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/docker-ce/linux/centos/gpg
EOF
if sudo dnf makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 阿里云 Docker 源配置成功"
else
echo "❌ 阿里云 Docker 源配置失败,尝试下一个源..."
fi
# 源2: 腾讯云镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置腾讯云 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.cloud.tencent.com/docker-ce/linux/centos/9/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.cloud.tencent.com/docker-ce/linux/centos/gpg
EOF
if sudo dnf makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 腾讯云 Docker 源配置成功"
else
echo "❌ 腾讯云 Docker 源配置失败,尝试下一个源..."
fi
fi
# 源3: 华为云镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置华为云 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.huaweicloud.com/docker-ce/linux/centos/9/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.huaweicloud.com/docker-ce/linux/centos/gpg
EOF
if sudo dnf makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 华为云 Docker 源配置成功"
else
echo "❌ 华为云 Docker 源配置失败,尝试下一个源..."
fi
fi
# 源4: 中科大镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置中科大 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.ustc.edu.cn/docker-ce/linux/centos/9/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.ustc.edu.cn/docker-ce/linux/centos/gpg
EOF
if sudo dnf makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 中科大 Docker 源配置成功"
else
echo "❌ 中科大 Docker 源配置失败,尝试下一个源..."
fi
fi
# 源5: 清华大学镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置清华大学 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/9/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/gpg
EOF
if sudo dnf makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 清华大学 Docker 源配置成功"
else
echo "❌ 清华大学 Docker 源配置失败,尝试下一个源..."
fi
fi
# 如果所有国内源都失败,尝试官方源
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "所有国内源都失败,尝试官方源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://download.docker.com/linux/centos/9/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://download.docker.com/linux/centos/gpg
EOF
if sudo dnf makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 官方 Docker 源配置成功"
else
echo "❌ 官方 Docker 源也配置失败"
fi
fi
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "❌ 所有 Docker 源都配置失败,无法继续安装"
echo "请检查网络连接或手动配置 Docker 源"
exit 1
fi
echo ">>> [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 <<EOF
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service time-set.target
Wants=network-online.target
Requires=docker.socket
[Service]
Type=notify
ExecStart=/usr/bin/dockerd -H fd://
ExecReload=/bin/kill -s HUP \$MAINPID
TimeoutStartSec=0
RestartSec=2
Restart=always
StartLimitBurst=3
StartLimitInterval=60s
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
Delegate=yes
KillMode=process
OOMScoreAdjust=-500
[Install]
WantedBy=multi-user.target
EOF
# 创建 docker.socket 文件
sudo tee /etc/systemd/system/docker.socket > /dev/null <<EOF
[Unit]
Description=Docker Socket for the API
[Socket]
ListenStream=/var/run/docker.sock
SocketMode=0660
SocketUser=root
SocketGroup=docker
[Install]
WantedBy=sockets.target
EOF
# 创建 docker 用户组
sudo groupadd docker 2>/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 <<EOF
# Debian 9 (Stretch) 官方归档源 - 主要源
# ⚠️ 注意:Debian 9 已停止支持,建议升级到 Debian 10+ 或更高版本
deb http://archive.debian.org/debian stretch main contrib non-free
deb http://archive.debian.org/debian-security stretch/updates main contrib non-free
# 国内归档镜像源 - 备用源(速度快)
# 阿里云归档源
# deb http://mirrors.aliyun.com/debian-archive/debian stretch main contrib non-free
# deb http://mirrors.aliyun.com/debian-archive/debian-security stretch/updates main contrib non-free
# 清华大学归档源
# deb https://mirrors.tuna.tsinghua.edu.cn/debian-archive/debian stretch main contrib non-free
# deb https://mirrors.tuna.tsinghua.edu.cn/debian-archive/debian-security stretch/updates main contrib non-free
EOF
echo "✅ Debian 9 归档源配置完成"
echo "💡 建议:安装完成后考虑升级到 Debian 10 (Buster) 或更高版本"
elif [[ "$VERSION_ID" == "10" ]]; then
echo "正在配置 Debian 10 兼容的软件源..."
# 备份原始源列表
sudo cp /etc/apt/sources.list /etc/apt/sources.list.backup.$(date +%Y%m%d_%H%M%S)
# 使用国内镜像源替代 archive.debian.org,提高下载速度
echo "正在配置国内镜像源以提高下载速度..."
# 尝试配置阿里云镜像源
sudo tee /etc/apt/sources.list > /dev/null <<EOF
# 阿里云镜像源 - 主要源
deb http://mirrors.aliyun.com/debian/ buster main contrib non-free
deb http://mirrors.aliyun.com/debian-security/ buster/updates main contrib non-free
deb http://mirrors.aliyun.com/debian/ buster-updates main contrib non-free
# 备用源 - 腾讯云镜像
# deb http://mirrors.cloud.tencent.com/debian/ buster main contrib non-free
# deb http://mirrors.cloud.tencent.com/debian-security/ buster/updates main contrib non-free
# deb http://mirrors.cloud.tencent.com/debian/ buster-updates main contrib non-free
# 备用源 - 华为云镜像
# deb http://mirrors.huaweicloud.com/debian/ buster main contrib non-free
# deb http://mirrors.huaweicloud.com/debian-security/ buster/updates main contrib non-free
# deb http://mirrors.huaweicloud.com/debian/ buster-updates main contrib non-free
# 最后备用 - archive.debian.org(如果国内源都不可用)
# deb http://archive.debian.org/debian/ buster main
# deb http://archive.debian.org/debian-security/ buster/updates main
# deb http://archive.debian.org/debian/ buster-updates main
EOF
echo "✅ Debian 10 国内镜像源配置完成"
elif [[ "$OS" == "ubuntu" && "$VERSION_ID" == "16.04" ]]; then
echo "正在配置 Ubuntu 16.04 兼容的软件源..."
echo "⚠️ Ubuntu 16.04 官方支持已结束,建议升级到 Ubuntu 20.04 LTS 或更高版本"
echo "✅ Ubuntu 16.04 软件源配置保持现状(通常已配置国内镜像源)"
fi
# 首先尝试安装基本工具
echo "正在安装基本工具..."
# 测试软件源可用性并自动切换
echo "正在测试软件源可用性..."
# Debian 9 需要忽略过期校验
if [[ "$OS" == "debian" && "$VERSION_ID" == "9" ]]; then
if sudo apt-get update --allow-unauthenticated -o Acquire::Check-Valid-Until=false 2>/dev/null; then
echo "✅ 当前软件源可用"
else
echo "⚠️ 当前软件源不可用,尝试切换到备用源..."
# 尝试腾讯云镜像源
DEBIAN_CODENAME="stretch"
sudo tee /etc/apt/sources.list > /dev/null <<EOF
# 腾讯云镜像源
deb http://mirrors.cloud.tencent.com/debian/ ${DEBIAN_CODENAME} main contrib non-free
deb http://mirrors.cloud.tencent.com/debian-security/ ${DEBIAN_CODENAME}/updates main contrib non-free
deb http://mirrors.cloud.tencent.com/debian/ ${DEBIAN_CODENAME}-updates main contrib non-free
EOF
if sudo apt-get update --allow-unauthenticated -o Acquire::Check-Valid-Until=false 2>/dev/null; then
echo "✅ 腾讯云镜像源可用"
else
echo "⚠️ 腾讯云镜像源也不可用,尝试华为云镜像源..."
# 尝试华为云镜像源
sudo tee /etc/apt/sources.list > /dev/null <<EOF
# 华为云镜像源
deb http://mirrors.huaweicloud.com/debian/ ${DEBIAN_CODENAME} main contrib non-free
deb http://mirrors.huaweicloud.com/debian-security/ ${DEBIAN_CODENAME}/updates main contrib non-free
deb http://mirrors.huaweicloud.com/debian/ ${DEBIAN_CODENAME}-updates main contrib non-free
EOF
if sudo apt-get update --allow-unauthenticated -o Acquire::Check-Valid-Until=false 2>/dev/null; then
echo "✅ 华为云镜像源可用"
else
echo "⚠️ 所有国内镜像源都不可用,回退到 archive.debian.org..."
# 回退到 archive.debian.org
sudo tee /etc/apt/sources.list > /dev/null <<EOF
# 官方归档源(速度较慢但稳定)
deb http://archive.debian.org/debian/ ${DEBIAN_CODENAME} main
deb http://archive.debian.org/debian-security/ ${DEBIAN_CODENAME}/updates main
deb http://archive.debian.org/debian/ ${DEBIAN_CODENAME}-updates main
EOF
sudo apt-get update --allow-unauthenticated -o Acquire::Check-Valid-Until=false || true
fi
fi
fi
else
if sudo apt-get update --allow-unauthenticated 2>/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 <<EOF
# 腾讯云镜像源
deb http://mirrors.cloud.tencent.com/debian/ ${DEBIAN_CODENAME} main contrib non-free
deb http://mirrors.cloud.tencent.com/debian-security/ ${DEBIAN_CODENAME}/updates main contrib non-free
deb http://mirrors.cloud.tencent.com/debian/ ${DEBIAN_CODENAME}-updates main contrib non-free
EOF
if sudo apt-get update --allow-unauthenticated 2>/dev/null; then
echo "✅ 腾讯云镜像源可用"
else
echo "⚠️ 腾讯云镜像源也不可用,尝试华为云镜像源..."
# 尝试华为云镜像源
sudo tee /etc/apt/sources.list > /dev/null <<EOF
# 华为云镜像源
deb http://mirrors.huaweicloud.com/debian/ ${DEBIAN_CODENAME} main contrib non-free
deb http://mirrors.huaweicloud.com/debian-security/ ${DEBIAN_CODENAME}/updates main contrib non-free
deb http://mirrors.huaweicloud.com/debian/ ${DEBIAN_CODENAME}-updates main contrib non-free
EOF
if sudo apt-get update --allow-unauthenticated 2>/dev/null; then
echo "✅ 华为云镜像源可用"
else
echo "⚠️ 所有国内镜像源都不可用,回退到 archive.debian.org..."
# 回退到 archive.debian.org
sudo tee /etc/apt/sources.list > /dev/null <<EOF
# 官方归档源(速度较慢但稳定)
deb http://archive.debian.org/debian/ ${DEBIAN_CODENAME} main
deb http://archive.debian.org/debian-security/ ${DEBIAN_CODENAME}/updates main
deb http://archive.debian.org/debian/ ${DEBIAN_CODENAME}-updates main
EOF
sudo apt-get update --allow-unauthenticated || true
fi
fi
fi
fi
# 尝试安装必要的依赖包
echo "正在安装必要的依赖包..."
if sudo apt-get install -y --allow-unauthenticated apt-transport-https ca-certificates gnupg lsb-release; then
echo "✅ 必要依赖包安装成功"
else
echo "⚠️ 依赖包安装失败,尝试逐个安装..."
# 逐个安装依赖包
if sudo apt-get install -y --allow-unauthenticated apt-transport-https; then
echo "✅ apt-transport-https 安装成功"
else
echo "⚠️ apt-transport-https 安装失败"
fi
if sudo apt-get install -y --allow-unauthenticated ca-certificates; then
echo "✅ ca-certificates 安装成功"
else
echo "⚠️ ca-certificates 安装失败"
fi
if sudo apt-get install -y --allow-unauthenticated gnupg; then
echo "✅ gnupg 安装成功"
else
echo "⚠️ gnupg 安装失败"
fi
if sudo apt-get install -y --allow-unauthenticated lsb-release; then
echo "✅ lsb-release 安装成功"
else
echo "⚠️ lsb-release 安装失败"
fi
fi
# 尝试安装 dirmngr 和 curl
if sudo apt-get install -y --allow-unauthenticated dirmngr; then
echo "✅ dirmngr 安装成功"
else
echo "⚠️ dirmngr 安装失败,将使用备用方法"
fi
if sudo apt-get install -y --allow-unauthenticated curl; then
echo "✅ curl 安装成功"
else
echo "⚠️ curl 安装失败,将使用备用方法"
fi
# 为 Debian 10 或 Ubuntu 16.04 跳过有问题的包安装,直接使用二进制安装
if [[ "$VERSION_ID" == "10" || ("$OS" == "ubuntu" && "$VERSION_ID" == "16.04") ]]; then
if [[ "$OS" == "debian" ]]; then
echo "⚠️ Debian 10 检测到软件源问题,跳过包管理器安装,直接使用二进制安装..."
else
echo "⚠️ Ubuntu 16.04 的 Docker 仓库缺少某些新组件,使用二进制安装..."
fi
echo "正在下载 Docker 二进制包..."
# 尝试从多个源下载 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 <<EOF
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service time-set.target
Wants=network-online.target
Requires=docker.socket
[Service]
Type=notify
ExecStart=/usr/bin/dockerd -H fd://
ExecReload=/bin/kill -s HUP \$MAINPID
TimeoutStartSec=0
RestartSec=2
Restart=always
StartLimitBurst=3
StartLimitInterval=60s
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
Delegate=yes
KillMode=process
OOMScoreAdjust=-500
[Install]
WantedBy=multi-user.target
EOF
# 创建 docker.socket 文件
sudo tee /etc/systemd/system/docker.socket > /dev/null <<EOF
[Unit]
Description=Docker Socket for the API
[Socket]
ListenStream=/var/run/docker.sock
SocketMode=0660
SocketUser=root
SocketGroup=docker
[Install]
WantedBy=sockets.target
EOF
# 创建 docker 用户组
sudo groupadd docker 2>/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 <<EOF
[
"https://$custom_domain",
"https://$custom_domain_dev"
]
EOF
)
elif [[ "$custom_domain" == *.xuanyuan.dev ]]; then
custom_domain_run="${custom_domain%.xuanyuan.dev}.xuanyuan.run"
mirror_list=$(cat <<EOF
[
"https://$custom_domain",
"https://$custom_domain_run"
]
EOF
)
else
mirror_list=$(cat <<EOF
[
"https://$custom_domain"
]
EOF
)
fi
else
mirror_list=$(cat <<EOF
[
"https://docker.xuanyuan.me"
]
EOF
)
fi
mkdir -p /etc/docker
apply_docker_mirror_config "$mirror_list"
apply_rc=$?
if [[ $apply_rc -eq 2 ]]; then
exit 0
elif [[ $apply_rc -ne 0 ]]; then
exit 1
fi
echo ">>> [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 '<html|Ali-OSM|DOCTYPE'; then
echo "⚠️ 下载内容为 HTML 页面,已丢弃"
rm -f "$tmp"
return 1
fi
# ELF 魔数:\x7fELF
if ! head -c 4 "$tmp" 2>/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 <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.aliyun.com/docker-ce/linux/centos/${CENTOS_VERSION}/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/docker-ce/linux/centos/gpg
EOF
if sudo yum makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 阿里云 Docker 源配置成功"
else
echo "❌ 阿里云 Docker 源配置失败,尝试下一个源..."
fi
# 源2: 腾讯云镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置腾讯云 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.cloud.tencent.com/docker-ce/linux/centos/${CENTOS_VERSION}/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.cloud.tencent.com/docker-ce/linux/centos/gpg
EOF
if sudo yum makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 腾讯云 Docker 源配置成功"
else
echo "❌ 腾讯云 Docker 源配置失败,尝试下一个源..."
fi
fi
# 源3: 华为云镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置华为云 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.huaweicloud.com/docker-ce/linux/centos/${CENTOS_VERSION}/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.huaweicloud.com/docker-ce/linux/centos/gpg
EOF
if sudo yum makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 华为云 Docker 源配置成功"
else
echo "❌ 华为云 Docker 源配置失败,尝试下一个源..."
fi
fi
# 源4: 中科大镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置中科大 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.ustc.edu.cn/docker-ce/linux/centos/${CENTOS_VERSION}/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.ustc.edu.cn/docker-ce/linux/centos/gpg
EOF
if sudo yum makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 中科大 Docker 源配置成功"
else
echo "❌ 中科大 Docker 源配置失败,尝试下一个源..."
fi
fi
# 源5: 清华大学镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置清华大学 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/${CENTOS_VERSION}/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/gpg
EOF
if sudo yum makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 清华大学 Docker 源配置成功"
else
echo "❌ 清华大学 Docker 源配置失败,尝试下一个源..."
fi
fi
# 源6: 网易镜像
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "尝试配置网易 Docker 源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://mirrors.163.com/docker-ce/linux/centos/${CENTOS_VERSION}/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.163.com/docker-ce/linux/centos/gpg
EOF
if sudo yum makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 网易 Docker 源配置成功"
else
echo "❌ 网易 Docker 源配置失败,尝试下一个源..."
fi
fi
# 如果所有国内源都失败,尝试官方源
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "所有国内源都失败,尝试官方源..."
sudo tee /etc/yum.repos.d/docker-ce.repo > /dev/null <<EOF
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://download.docker.com/linux/centos/${CENTOS_VERSION}/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://download.docker.com/linux/centos/gpg
EOF
if sudo yum makecache; then
DOCKER_REPO_ADDED=true
echo "✅ 官方 Docker 源配置成功"
else
echo "❌ 官方 Docker 源也配置失败"
fi
fi
if [[ "$DOCKER_REPO_ADDED" == "false" ]]; then
echo "❌ 所有 Docker 源都配置失败,无法继续安装"
echo "请检查网络连接或手动配置 Docker 源"
exit 1
fi
echo ">>> [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 <<EOF
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service time-set.target
Wants=network-online.target
Requires=docker.socket
[Service]
Type=notify
ExecStart=/usr/bin/dockerd -H fd://
ExecReload=/bin/kill -s HUP \$MAINPID
TimeoutStartSec=0
RestartSec=2
Restart=always
StartLimitBurst=3
StartLimitInterval=60s
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
Delegate=yes
KillMode=process
OOMScoreAdjust=-500
[Install]
WantedBy=multi-user.target
EOF
# 创建 docker.socket 文件
sudo tee /etc/systemd/system/docker.socket > /dev/null <<EOF
[Unit]
Description=Docker Socket for the API
[Socket]
ListenStream=/var/run/docker.sock
SocketMode=0660
SocketUser=root
SocketGroup=docker
[Install]
WantedBy=sockets.target
EOF
# 创建 docker 用户组
sudo groupadd docker 2>/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 <<EOF
[
"https://$custom_domain",
"https://$custom_domain_dev"
]
EOF
)
elif [[ "$custom_domain" == *.xuanyuan.dev ]]; then
custom_domain_run="${custom_domain%.xuanyuan.dev}.xuanyuan.run"
mirror_list=$(cat <<EOF
[
"https://$custom_domain",
"https://$custom_domain_run"
]
EOF
)
else
mirror_list=$(cat <<EOF
[
"https://$custom_domain"
]
EOF
)
fi
else
mirror_list=$(cat <<EOF
[
"https://docker.xuanyuan.me"
]
EOF
)
fi
sudo mkdir -p /etc/docker
apply_docker_mirror_config "$mirror_list"
apply_rc=$?
if [[ $apply_rc -eq 2 ]]; then
echo "已取消安装配置"
exit 0
elif [[ $apply_rc -ne 0 ]]; then
exit 1
fi
# 避免在容器/无 systemd 环境反复调用 systemctl 导致 “PID 1 / bus” 报错
SCRIPT_SYSTEMD_OK=false
if command -v systemctl &>/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