From 47daadc9bd88058c29dc9ed2ed110d7719b627e5 Mon Sep 17 00:00:00 2001 From: tangweijie <877588133@qq.com> Date: Wed, 17 Dec 2025 17:54:20 +0800 Subject: [PATCH] =?UTF-8?q?feat(docker):=20=E5=A2=9E=E5=BC=BA=20Docker=20?= =?UTF-8?q?=E5=AE=89=E8=A3=85=E8=84=9A=E6=9C=AC=EF=BC=8C=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=A4=9A=E6=BA=90=E5=88=87=E6=8D=A2=E5=92=8C=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E9=80=89=E6=8B=A9=E6=9C=80=E4=BD=B3=E6=BA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/packages/configure_packages.sh | 140 ++++++++----- scripts/packages/install_docker.sh | 276 +++++++++++++++++++++++-- 2 files changed, 351 insertions(+), 65 deletions(-) diff --git a/scripts/packages/configure_packages.sh b/scripts/packages/configure_packages.sh index 03dec22..eca9bcc 100755 --- a/scripts/packages/configure_packages.sh +++ b/scripts/packages/configure_packages.sh @@ -94,66 +94,110 @@ install_basic_tools() { log_success "基础工具安装完成" } -# 安装 Docker (从国内源) +# 安装 Docker (从国内源,支持多源切换) install_docker() { - log_info "从国内源安装 Docker..." - - # 卸载可能存在的旧版本 - apt remove -y docker docker-engine docker.io containerd runc 2>/dev/null || true - - # 更新包索引 - apt update - - # 安装必要的包 - apt install -y ca-certificates curl gnupg lsb-release - - # 添加 Docker 的官方 GPG 密钥 - mkdir -p /etc/apt/keyrings - curl -fsSL https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/debian/gpg | gpg --dearmor -o /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 - - # 更新包索引 - apt update - - # 安装 Docker 最新版本 - apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin - - # 配置 Docker 使用国内镜像 - mkdir -p /etc/docker - cat > /etc/docker/daemon.json << 'EOF' + log_info "从国内源安装 Docker (支持多源自动切换)..." + + # 获取脚本所在目录 + local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + local docker_script="$script_dir/install_docker.sh" + + # 检查是否存在独立的 Docker 安装脚本 + if [[ -f "$docker_script" ]]; then + log_info "使用 install_docker.sh 脚本安装..." + bash "$docker_script" --force + else + # 内联安装逻辑(多源支持) + log_info "使用内置安装逻辑..." + + # 定义多个 Docker 源 + local -A docker_sources=( + ["aliyun"]="https://mirrors.aliyun.com/docker-ce" + ["ustc"]="https://mirrors.ustc.edu.cn/docker-ce" + ["huawei"]="https://mirrors.huaweicloud.com/docker-ce" + ["163"]="https://mirrors.163.com/docker-ce" + ["tsinghua"]="https://mirrors.tuna.tsinghua.edu.cn/docker-ce" + ) + local source_order=("aliyun" "ustc" "huawei" "163" "tsinghua") + + # 卸载旧版本 + apt remove -y docker docker-engine docker.io containerd runc 2>/dev/null || true + 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": [ + "https://docker-proxy.syy.1msoft.cn", "https://registry.docker-cn.com", "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-opts": { "max-size": "100m", "max-file": "3" - } + }, + "storage-driver": "overlay2" } EOF - - # 启动 Docker 服务 - systemctl enable docker - systemctl start docker - - # 添加当前用户到 docker 组(如果用户存在) - if id -u "$SUDO_USER" >/dev/null 2>&1; then - usermod -aG docker "$SUDO_USER" - log_info "已将用户 $SUDO_USER 添加到 docker 组,请重新登录以生效" - fi - - # 测试 Docker 安装 - if docker --version >/dev/null 2>&1; then - log_success "Docker 安装成功,版本: $(docker --version)" - log_info "Docker 镜像加速器已配置" - else - log_error "Docker 安装失败" - exit 1 + + systemctl enable docker + systemctl start docker + + if id -u "$SUDO_USER" >/dev/null 2>&1; then + usermod -aG docker "$SUDO_USER" + log_info "已将用户 $SUDO_USER 添加到 docker 组,请重新登录以生效" + fi + + if docker --version >/dev/null 2>&1; then + log_success "Docker 安装成功,版本: $(docker --version)" + fi fi } diff --git a/scripts/packages/install_docker.sh b/scripts/packages/install_docker.sh index f5695e7..0d5dc2c 100755 --- a/scripts/packages/install_docker.sh +++ b/scripts/packages/install_docker.sh @@ -2,6 +2,7 @@ # Debian 12 Docker 安装脚本 (使用国内源) # 从国内镜像源安装 Docker CE +# 支持多源切换和自动选择最佳源 set -e @@ -29,6 +30,133 @@ log_error() { 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() { log_info "检查系统要求..." @@ -99,31 +227,86 @@ install_dependencies() { # 添加 Docker 仓库 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 + + # 移除旧的密钥和仓库配置 + rm -f /etc/apt/keyrings/docker.gpg + rm -f /etc/apt/sources.list.d/docker.list # 下载并添加 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 install_docker() { 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 - # 更新包索引 - apt update - - # 安装 Docker CE - apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin - - log_success "Docker CE 安装完成" + # 尝试安装 Docker CE + log_info "尝试从 $CURRENT_SOURCE 安装 Docker..." + + # 使用 set +e 暂时禁用错误退出 + set +e + apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin 2>&1 + 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 @@ -255,22 +438,48 @@ Docker 安装完成! 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() { cat << EOF Debian 12 Docker 安装脚本 -此脚本将从清华大学镜像源安装 Docker CE,并配置国内镜像加速器。 +此脚本支持多个国内镜像源,自动选择最佳源或手动指定源。 用法: $0 [选项] 选项: - -h, --help 显示此帮助信息 - -f, --force 强制重新安装(不检查现有安装) + -h, --help 显示此帮助信息 + -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 --force # 强制重新安装 + $0 # 自动选择最佳源安装 + $0 -s aliyun # 使用阿里云源安装 + $0 -s ustc --force # 使用中科大源强制重装 + $0 --test # 测试所有源速度 + $0 --list # 列出所有可用源 EOF } @@ -278,6 +487,8 @@ EOF # 主函数 main() { local force_install=false + local specified_source="" + local test_only=false # 解析参数 while [[ $# -gt 0 ]]; do @@ -290,6 +501,18 @@ main() { force_install=true shift ;; + -s|--source) + specified_source="$2" + shift 2 + ;; + -t|--test) + test_only=true + shift + ;; + -l|--list) + list_sources + exit 0 + ;; *) log_error "未知选项: $1" show_help @@ -304,6 +527,12 @@ main() { exit 1 fi + # 仅测试模式 + if [[ "$test_only" == true ]]; then + select_best_source + exit 0 + fi + # 检查是否已安装 if command -v docker &> /dev/null && [[ "$force_install" != true ]]; then log_warning "Docker 已经安装。如需重新安装,请使用 --force 选项。" @@ -315,6 +544,19 @@ main() { echo 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 install_dependencies add_docker_repository @@ -325,7 +567,7 @@ main() { test_installation echo - log_success "Docker 安装完成!" + log_success "Docker 安装完成!(使用源: $CURRENT_SOURCE)" } # 执行主函数