feat(docker): 增强 Docker 安装脚本,支持多源切换和自动选择最佳源

This commit is contained in:
tangweijie 2025-12-17 17:54:20 +08:00
parent 8d7d0b2b12
commit 47daadc9bd
2 changed files with 351 additions and 65 deletions

View File

@ -94,66 +94,110 @@ install_basic_tools() {
log_success "基础工具安装完成" log_success "基础工具安装完成"
} }
# 安装 Docker (从国内源) # 安装 Docker (从国内源,支持多源切换)
install_docker() { install_docker() {
log_info "从国内源安装 Docker..." log_info "从国内源安装 Docker (支持多源自动切换)..."
# 卸载可能存在的旧版本 # 获取脚本所在目录
apt remove -y docker docker-engine docker.io containerd runc 2>/dev/null || true local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
local docker_script="$script_dir/install_docker.sh"
# 更新包索引
apt update # 检查是否存在独立的 Docker 安装脚本
if [[ -f "$docker_script" ]]; then
# 安装必要的包 log_info "使用 install_docker.sh 脚本安装..."
apt install -y ca-certificates curl gnupg lsb-release bash "$docker_script" --force
else
# 添加 Docker 的官方 GPG 密钥 # 内联安装逻辑(多源支持)
mkdir -p /etc/apt/keyrings log_info "使用内置安装逻辑..."
curl -fsSL https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
# 定义多个 Docker 源
# 设置仓库 local -A docker_sources=(
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/debian $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null ["aliyun"]="https://mirrors.aliyun.com/docker-ce"
["ustc"]="https://mirrors.ustc.edu.cn/docker-ce"
# 更新包索引 ["huawei"]="https://mirrors.huaweicloud.com/docker-ce"
apt update ["163"]="https://mirrors.163.com/docker-ce"
["tsinghua"]="https://mirrors.tuna.tsinghua.edu.cn/docker-ce"
# 安装 Docker 最新版本 )
apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin local source_order=("aliyun" "ustc" "huawei" "163" "tsinghua")
# 配置 Docker 使用国内镜像 # 卸载旧版本
mkdir -p /etc/docker apt remove -y docker docker-engine docker.io containerd runc 2>/dev/null || true
cat > /etc/docker/daemon.json << 'EOF' apt update
apt install -y ca-certificates curl gnupg lsb-release
mkdir -p /etc/apt/keyrings
local codename=$(lsb_release -cs)
local arch=$(dpkg --print-architecture)
local installed=false
for source_name in "${source_order[@]}"; do
local source_url="${docker_sources[$source_name]}"
log_info "尝试使用 $source_name 源: $source_url"
# 测试源
if ! curl -sfL --connect-timeout 5 --max-time 10 "$source_url/linux/debian/gpg" -o /dev/null 2>/dev/null; then
log_warning "$source_name 源不可用,跳过..."
continue
fi
# 配置源
rm -f /etc/apt/keyrings/docker.gpg /etc/apt/sources.list.d/docker.list
curl -fsSL "$source_url/linux/debian/gpg" | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$arch signed-by=/etc/apt/keyrings/docker.gpg] $source_url/linux/debian $codename stable" > /etc/apt/sources.list.d/docker.list
apt update
# 尝试安装
set +e
apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin 2>&1
local result=$?
set -e
if [[ $result -eq 0 ]]; then
log_success "Docker 安装成功 (源: $source_name)"
installed=true
break
else
log_warning "$source_name 安装失败,尝试下一个源..."
fi
done
if [[ "$installed" != "true" ]]; then
log_error "Docker 安装失败,已尝试所有可用源"
exit 1
fi
# 配置 Docker
mkdir -p /etc/docker
cat > /etc/docker/daemon.json << 'EOF'
{ {
"registry-mirrors": [ "registry-mirrors": [
"https://docker-proxy.syy.1msoft.cn",
"https://registry.docker-cn.com", "https://registry.docker-cn.com",
"https://docker.mirrors.ustc.edu.cn", "https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com" "https://hub-mirror.c.163.com",
"https://mirror.baidubce.com"
], ],
"log-driver": "json-file", "log-driver": "json-file",
"log-opts": { "log-opts": {
"max-size": "100m", "max-size": "100m",
"max-file": "3" "max-file": "3"
} },
"storage-driver": "overlay2"
} }
EOF EOF
# 启动 Docker 服务 systemctl enable docker
systemctl enable docker systemctl start docker
systemctl start docker
if id -u "$SUDO_USER" >/dev/null 2>&1; then
# 添加当前用户到 docker 组(如果用户存在) usermod -aG docker "$SUDO_USER"
if id -u "$SUDO_USER" >/dev/null 2>&1; then log_info "已将用户 $SUDO_USER 添加到 docker 组,请重新登录以生效"
usermod -aG docker "$SUDO_USER" fi
log_info "已将用户 $SUDO_USER 添加到 docker 组,请重新登录以生效"
fi if docker --version >/dev/null 2>&1; then
log_success "Docker 安装成功,版本: $(docker --version)"
# 测试 Docker 安装 fi
if docker --version >/dev/null 2>&1; then
log_success "Docker 安装成功,版本: $(docker --version)"
log_info "Docker 镜像加速器已配置"
else
log_error "Docker 安装失败"
exit 1
fi fi
} }

View File

@ -2,6 +2,7 @@
# Debian 12 Docker 安装脚本 (使用国内源) # Debian 12 Docker 安装脚本 (使用国内源)
# 从国内镜像源安装 Docker CE # 从国内镜像源安装 Docker CE
# 支持多源切换和自动选择最佳源
set -e set -e
@ -29,6 +30,133 @@ log_error() {
echo -e "${RED}[ERROR]${NC} $1" echo -e "${RED}[ERROR]${NC} $1"
} }
# 定义多个 Docker 源
declare -A DOCKER_SOURCES=(
["aliyun"]="https://mirrors.aliyun.com/docker-ce"
["tsinghua"]="https://mirrors.tuna.tsinghua.edu.cn/docker-ce"
["ustc"]="https://mirrors.ustc.edu.cn/docker-ce"
["huawei"]="https://mirrors.huaweicloud.com/docker-ce"
["163"]="https://mirrors.163.com/docker-ce"
["azure"]="https://mirror.azure.cn/docker-ce"
["official"]="https://download.docker.com"
)
# 源优先级顺序
DOCKER_SOURCE_ORDER=("aliyun" "ustc" "huawei" "163" "tsinghua" "azure" "official")
# 当前使用的源
CURRENT_SOURCE=""
CURRENT_SOURCE_URL=""
# 测试单个源的连接性
test_source() {
local source_name="$1"
local source_url="${DOCKER_SOURCES[$source_name]}"
local codename=$(lsb_release -cs)
local arch=$(dpkg --print-architecture)
local test_url="${source_url}/linux/debian/dists/${codename}/stable/binary-${arch}/Packages"
# 测试连接
local start_time=$(date +%s%N)
if curl -sfL --connect-timeout 5 --max-time 15 "$test_url" -o /dev/null 2>/dev/null; then
local end_time=$(date +%s%N)
local time_diff=$(( (end_time - start_time) / 1000000 ))
echo "$time_diff"
return 0
fi
return 1
}
# 测试所有源并选择最佳
select_best_source() {
log_info "测试 Docker 源连接速度..."
local best_source=""
local best_time=999999
for source_name in "${DOCKER_SOURCE_ORDER[@]}"; do
local source_url="${DOCKER_SOURCES[$source_name]}"
printf " %-12s %-50s " "$source_name" "$source_url"
if time_ms=$(test_source "$source_name"); then
echo -e "${GREEN}${NC} ${time_ms}ms"
if (( time_ms < best_time )); then
best_time=$time_ms
best_source=$source_name
fi
else
echo -e "${RED}${NC} 连接失败"
fi
done
if [[ -n "$best_source" ]]; then
log_success "选择最佳源: $best_source (${best_time}ms)"
CURRENT_SOURCE="$best_source"
CURRENT_SOURCE_URL="${DOCKER_SOURCES[$best_source]}"
return 0
else
log_error "所有源均不可用"
return 1
fi
}
# 使用指定源
use_source() {
local source_name="$1"
if [[ -z "${DOCKER_SOURCES[$source_name]}" ]]; then
log_error "未知的源: $source_name"
log_info "可用源: ${!DOCKER_SOURCES[*]}"
return 1
fi
log_info "测试指定源: $source_name"
if test_source "$source_name" >/dev/null; then
CURRENT_SOURCE="$source_name"
CURRENT_SOURCE_URL="${DOCKER_SOURCES[$source_name]}"
log_success "使用源: $source_name ($CURRENT_SOURCE_URL)"
return 0
else
log_error "$source_name 不可用"
return 1
fi
}
# 尝试下一个源
try_next_source() {
local current="$CURRENT_SOURCE"
local found_current=false
for source_name in "${DOCKER_SOURCE_ORDER[@]}"; do
if [[ "$found_current" == "true" ]]; then
if test_source "$source_name" >/dev/null; then
CURRENT_SOURCE="$source_name"
CURRENT_SOURCE_URL="${DOCKER_SOURCES[$source_name]}"
log_info "切换到备用源: $source_name"
return 0
fi
fi
if [[ "$source_name" == "$current" ]]; then
found_current=true
fi
done
# 如果没有找到,从头开始尝试
for source_name in "${DOCKER_SOURCE_ORDER[@]}"; do
if [[ "$source_name" != "$current" ]]; then
if test_source "$source_name" >/dev/null; then
CURRENT_SOURCE="$source_name"
CURRENT_SOURCE_URL="${DOCKER_SOURCES[$source_name]}"
log_info "切换到备用源: $source_name"
return 0
fi
fi
done
return 1
}
# 检查系统要求 # 检查系统要求
check_system() { check_system() {
log_info "检查系统要求..." log_info "检查系统要求..."
@ -99,31 +227,86 @@ install_dependencies() {
# 添加 Docker 仓库 # 添加 Docker 仓库
add_docker_repository() { add_docker_repository() {
log_info "添加 Docker 仓库 (使用清华大学镜像源)..." if [[ -z "$CURRENT_SOURCE_URL" ]]; then
log_error "未选择 Docker 源"
return 1
fi
log_info "添加 Docker 仓库 (使用 $CURRENT_SOURCE 源)..."
log_info "源地址: $CURRENT_SOURCE_URL"
# 创建密钥目录 # 创建密钥目录
mkdir -p /etc/apt/keyrings mkdir -p /etc/apt/keyrings
# 移除旧的密钥和仓库配置
rm -f /etc/apt/keyrings/docker.gpg
rm -f /etc/apt/sources.list.d/docker.list
# 下载并添加 GPG 密钥 # 下载并添加 GPG 密钥
curl -fsSL https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg log_info "下载 GPG 密钥..."
if ! curl -fsSL "${CURRENT_SOURCE_URL}/linux/debian/gpg" | gpg --dearmor -o /etc/apt/keyrings/docker.gpg 2>/dev/null; then
log_warning "$CURRENT_SOURCE 下载 GPG 密钥失败,尝试官方源..."
curl -fsSL "https://download.docker.com/linux/debian/gpg" | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
fi
chmod a+r /etc/apt/keyrings/docker.gpg
# 添加仓库 # 添加仓库
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/debian $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null local arch=$(dpkg --print-architecture)
local codename=$(lsb_release -cs)
echo "deb [arch=${arch} signed-by=/etc/apt/keyrings/docker.gpg] ${CURRENT_SOURCE_URL}/linux/debian ${codename} stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
log_success "Docker 仓库添加完成" log_success "Docker 仓库添加完成 (源: $CURRENT_SOURCE)"
} }
# 安装 Docker # 安装 Docker
install_docker() { install_docker() {
log_info "安装 Docker CE..." log_info "安装 Docker CE..."
local max_retries=3
local retry_count=0
while (( retry_count < max_retries )); do
# 更新包索引
log_info "更新包索引..."
if ! apt update 2>&1; then
log_warning "apt update 失败"
fi
# 更新包索引 # 尝试安装 Docker CE
apt update log_info "尝试从 $CURRENT_SOURCE 安装 Docker..."
# 安装 Docker CE # 使用 set +e 暂时禁用错误退出
apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin set +e
apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin 2>&1
log_success "Docker CE 安装完成" local install_result=$?
set -e
if [[ $install_result -eq 0 ]]; then
log_success "Docker CE 安装完成 (源: $CURRENT_SOURCE)"
return 0
fi
retry_count=$((retry_count + 1))
log_warning "安装失败 (尝试 $retry_count/$max_retries)"
if (( retry_count < max_retries )); then
log_info "尝试切换到其他源..."
if try_next_source; then
# 重新配置仓库
add_docker_repository
else
log_error "没有更多可用的源"
break
fi
fi
done
log_error "Docker 安装失败,已尝试所有可用源"
log_info "建议手动检查网络连接或稍后重试"
exit 1
} }
# 配置 Docker # 配置 Docker
@ -255,22 +438,48 @@ Docker 安装完成!
EOF EOF
} }
# 列出可用源
list_sources() {
echo "可用的 Docker 源:"
echo "=========================================="
for source_name in "${DOCKER_SOURCE_ORDER[@]}"; do
printf " %-12s %s\n" "$source_name" "${DOCKER_SOURCES[$source_name]}"
done
echo ""
echo "默认优先级: ${DOCKER_SOURCE_ORDER[*]}"
}
# 显示帮助信息 # 显示帮助信息
show_help() { show_help() {
cat << EOF cat << EOF
Debian 12 Docker 安装脚本 Debian 12 Docker 安装脚本
此脚本将从清华大学镜像源安装 Docker CE并配置国内镜像加速器。 此脚本支持多个国内镜像源,自动选择最佳源或手动指定源
用法: $0 [选项] 用法: $0 [选项]
选项: 选项:
-h, --help 显示此帮助信息 -h, --help 显示此帮助信息
-f, --force 强制重新安装(不检查现有安装) -f, --force 强制重新安装(不检查现有安装)
-s, --source NAME 指定使用的源 (aliyun, tsinghua, ustc, huawei, 163, azure, official)
-t, --test 仅测试所有源的连接速度
-l, --list 列出所有可用源
可用源:
aliyun 阿里云镜像 (推荐)
tsinghua 清华大学镜像
ustc 中科大镜像
huawei 华为云镜像
163 网易镜像
azure 微软 Azure 镜像
official Docker 官方源
示例: 示例:
$0 # 正常安装 $0 # 自动选择最佳源安装
$0 --force # 强制重新安装 $0 -s aliyun # 使用阿里云源安装
$0 -s ustc --force # 使用中科大源强制重装
$0 --test # 测试所有源速度
$0 --list # 列出所有可用源
EOF EOF
} }
@ -278,6 +487,8 @@ EOF
# 主函数 # 主函数
main() { main() {
local force_install=false local force_install=false
local specified_source=""
local test_only=false
# 解析参数 # 解析参数
while [[ $# -gt 0 ]]; do while [[ $# -gt 0 ]]; do
@ -290,6 +501,18 @@ main() {
force_install=true force_install=true
shift shift
;; ;;
-s|--source)
specified_source="$2"
shift 2
;;
-t|--test)
test_only=true
shift
;;
-l|--list)
list_sources
exit 0
;;
*) *)
log_error "未知选项: $1" log_error "未知选项: $1"
show_help show_help
@ -304,6 +527,12 @@ main() {
exit 1 exit 1
fi fi
# 仅测试模式
if [[ "$test_only" == true ]]; then
select_best_source
exit 0
fi
# 检查是否已安装 # 检查是否已安装
if command -v docker &> /dev/null && [[ "$force_install" != true ]]; then if command -v docker &> /dev/null && [[ "$force_install" != true ]]; then
log_warning "Docker 已经安装。如需重新安装,请使用 --force 选项。" log_warning "Docker 已经安装。如需重新安装,请使用 --force 选项。"
@ -315,6 +544,19 @@ main() {
echo echo
check_system check_system
# 选择源
if [[ -n "$specified_source" ]]; then
if ! use_source "$specified_source"; then
log_warning "指定源不可用,自动选择最佳源..."
select_best_source || exit 1
fi
else
select_best_source || exit 1
fi
echo
uninstall_old_versions uninstall_old_versions
install_dependencies install_dependencies
add_docker_repository add_docker_repository
@ -325,7 +567,7 @@ main() {
test_installation test_installation
echo echo
log_success "Docker 安装完成!" log_success "Docker 安装完成!(使用源: $CURRENT_SOURCE)"
} }
# 执行主函数 # 执行主函数