Ubuntu制作离线仓库

作者:莫名 发布时间: 2026-03-25 阅读量:24 评论数:0

一. 在线环境安装依赖

#!/bin/bash
# build-docker20-offline-repo.sh
# 一键制作 Docker 20.10.24 离线仓库(纯净版)
# 用法:./build-docker20-offline-repo.sh [focal|jammy] [阿里云镜像加速地址(可选)]

set -euo pipefail

# 配置参数
UBUNTU_VER="${1:-focal}"              # 默认 focal (20.04),可选 jammy (22.04)
DOCKER_VERSION="5:20.10.24~3-0~ubuntu-${UBUNTU_VER}"
REPO_DIR="${HOME}/docker20-${UBUNTU_VER}-repo"
OUTPUT_FILE="${HOME}/docker20-${UBUNTU_VER}-offline.tar.gz"

# 阿里云镜像加速器(用于拉取基础镜像,可选)
ALIYUN_MIRROR="${2:-}"

# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

log_info() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

log_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

# 1. 清理旧仓库(防止版本污染)
clean_old_repo() {
    log_info "清理旧仓库: ${REPO_DIR}"
    if [[ -d "${REPO_DIR}" ]]; then
        rm -rf "${REPO_DIR}"
        log_warn "已删除旧仓库目录"
    fi
    mkdir -p "${REPO_DIR}"/{pool/main,dists/stable/main/binary-amd64}
}

# 2. 配置国内 APT 源(加速下载)
setup_apt_source() {
    log_info "配置阿里云 APT 源 (${UBUNTU_VER})..."
    
    # 备份原配置
    if [[ ! -f /etc/apt/sources.list.bak ]]; then
        sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak
    fi
    
    # 添加阿里云 Docker 源(仅用于本次下载)
    curl -fsSL http://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add - 2>/dev/null || true
    sudo add-apt-repository -y "deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/ubuntu ${UBUNTU_VER} stable" 2>/dev/null || true
    sudo apt-get update
}

# 3. 下载指定版本的 Docker 及依赖(严格锁定架构和版本)
download_packages() {
    log_info "下载 Docker ${DOCKER_VERSION} (amd64 only)..."
    cd "${REPO_DIR}/pool/main"
    
    # 先清理可能存在的错误版本(高版本、i386等)
    log_warn "清理目录中可能存在的冲突包..."
    rm -f docker-ce_*28.*.deb docker-ce-cli_*28.*.deb 2>/dev/null || true
    rm -f *_i386.deb 2>/dev/null || true
    rm -f *~22.04*.deb *~24.04*.deb 2>/dev/null || true  # 删除其他 Ubuntu 版本的包
    
    # 下载核心包(严格指定版本和架构)
    log_info "下载核心组件..."
    apt-get download -y \
        docker-ce:${UBUNTU_VER}=${DOCKER_VERSION} \
        docker-ce-cli:${UBUNTU_VER}=${DOCKER_VERSION} \
		docker-compose-plugin \
        containerd.io:amd64 \
        2>/dev/null || apt-get download docker-ce=${DOCKER_VERSION} docker-ce-cli=${DOCKER_VERSION} docker-compose-plugin containerd.io
    
    # 获取依赖列表(递归但排除推荐,只保留 amd64)
    log_info "解析依赖关系..."
    local deps
    deps=$(apt-cache depends --recurse --no-recommends --no-suggests \
        --no-conflicts --no-breaks --no-replaces --no-enhances \
        docker-ce=${DOCKER_VERSION} 2>/dev/null | \
        grep "^\w" | sort -u | grep -v "^docker-ce$\|^docker-ce-cli$\|^containerd.io$" || true)
    
    # 下载依赖(强制 amd64 架构,防止下载 i386)
    log_info "下载依赖包 (共 $(echo "${deps}" | wc -l) 个)..."
    for pkg in ${deps}; do
        # 跳过虚拟包和已下载的
        if [[ "${pkg}" == "<"*">" ]]; then continue; fi
        
        # 尝试下载 amd64 版本,忽略错误(有些包可能是 all 架构或无 amd64)
        apt-get download "${pkg}:amd64" 2>/dev/null || \
        apt-get download "${pkg}:all" 2>/dev/null || \
        apt-get download "${pkg}" 2>/dev/null || \
        log_warn "跳过无法下载的包: ${pkg}"
    done
    
    # 手动补充关键依赖(确保不遗漏)
    log_info "补充关键系统依赖..."
    apt-get download -y \
        libltdl7:amd64 libseccomp2:amd64 pigz:amd64 \
        iptables:amd64 libip4tc2:amd64 libip6tc2:amd64 \
        libxtables12:amd64 libnfnetlink0:amd64 \
        libnetfilter-conntrack3:amd64 libnftnl11:amd64 \
        libmnl0:amd64 libcap2:amd64 libdevmapper1.02.1:amd64 \
        libc6:amd64 libgcc-s1:amd64 libgcrypt20:amd64 \
        liblz4-1:amd64 liblzma5:amd64 libsystemd0:amd64 \
        libselinux1:amd64 libpcre2-8-0:amd64 libmount1:amd64 \
        libblkid1:amd64 libuuid1:amd64 zlib1g:amd64 \
        adduser debconf perl-base 2>/dev/null || true
}

# 4. 清理跨版本和冲突包
clean_cross_version() {
    log_info "清理跨版本冲突包..."
    cd "${REPO_DIR}/pool/main"
    
    # 删除 i386 包
    if ls *_i386.deb 1> /dev/null 2>&1; then
        log_warn "删除 i386 架构包: $(ls *_i386.deb 2>/dev/null | wc -l) 个"
        rm -f *_i386.deb
    fi
    
    # 删除非目标 Ubuntu 版本的系统库(通过版本号特征识别)
    if [[ "${UBUNTU_VER}" == "focal" ]]; then
        # focal 是 20.04,libc 版本约 2.31,删除 2.35+(22.04+ 的版本)
        for pkg in libc6 libgcc-s1 libcrypt1; do
            if ls ${pkg}*2.3[5-9]*.deb 1> /dev/null 2>&1 || ls ${pkg}*2.4*.deb 1> /dev/null 2>&1; then
                log_warn "删除高版本 ${pkg} (22.04+ 的库)"
                rm -f ${pkg}*2.3[5-9]*.deb ${pkg}*2.4*.deb 2>/dev/null || true
            fi
        done
    fi
    
    # 再次确保没有高版本 Docker
    if ls docker-ce_*28.*.deb 1> /dev/null 2>&1; then
        log_error "发现高版本 Docker 包,正在清理..."
        rm -f docker-ce_*28.*.deb docker-ce-cli_*28.*.deb
    fi
    
    # 清理重复下载(保留最新下载的,通常是正确的 amd64 版本)
    log_info "去重处理..."
    ls -t *.deb | awk -F_ '!seen[$1]++' | while read file; do
        base=$(echo "${file}" | sed 's/_.*//')
        # 删除该包的其他版本,只保留当前文件
        for old in $(ls ${base}_*.deb 2>/dev/null | grep -v "^${file}$"); do
            if [[ "${old}" != "${file}" ]]; then
                rm -f "${old}"
                log_warn "删除重复/旧版本: ${old}"
            fi
        done
    done
}

# 5. 生成 APT 索引
generate_index() {
    log_info "生成 APT 索引..."
    cd "${REPO_DIR}"
    
    # 生成 Packages 文件
    dpkg-scanpackages pool/main /dev/null | sudo tee dists/stable/main/binary-amd64/Packages > /dev/null  # 过滤重复警告
	echo "" | sudo tee -a dists/stable/main/binary-amd64/Packages > /dev/null
    
    # 压缩
    gzip -k -f dists/stable/main/binary-amd64/Packages
    
    # 生成 Release 文件(可选,用于更规范的仓库)
    cat > Release.conf <<EOF
APT::FTPArchive::Release::Origin "Local Docker 20.10 Repo";
APT::FTPArchive::Release::Label "Docker CE 20.10.24 for ${UBUNTU_VER}";
APT::FTPArchive::Release::Suite "stable";
APT::FTPArchive::Release::Codename "stable";
APT::FTPArchive::Release::Architectures "amd64";
APT::FTPArchive::Release::Components "main";
EOF
    
    if command -v apt-ftparchive &> /dev/null; then
        apt-ftparchive release -c Release.conf dists/stable > dists/stable/Release 2>/dev/null || true
        log_info "Release 文件已生成"
    fi
    
    # 验证
    local pkg_count=$(grep -c "^Package:" dists/stable/main/binary-amd64/Packages || echo "0")
    log_info "索引生成完成,共 ${pkg_count} 个软件包"
    
    # 关键验证:确保 docker-ce 版本正确
    local docker_ver
    docker_ver=$(grep -A2 "^Package: docker-ce$" dists/stable/main/binary-amd64/Packages | grep "^Version:" | awk '{print $2}' || echo "未知")
    if [[ "${docker_ver}" == *"20.10.24"* ]]; then
        log_info "✅ 验证通过: docker-ce 版本为 ${docker_ver}"
    else
        log_error "❌ 版本错误: 发现 ${docker_ver},期望 20.10.24"
        log_error "请检查 pool/main/ 目录,手动删除 28.x 版本后重试"
        exit 1
    fi
}

# 6. 打包输出
package_repo() {
    log_info "打包离线仓库..."
    cd "${REPO_DIR}"
    
    # 创建安装说明
    cat > INSTALL_README.txt <<EOF
Docker 20.10.24 离线安装说明
============================
Ubuntu 版本: ${UBUNTU_VER}
Docker 版本: 20.10.24
架构: amd64

安装步骤:
1. 解压到离线机器: sudo tar xzvf $(basename ${OUTPUT_FILE}) -C /opt/
2. 添加本地源: echo "deb [trusted=yes] file:///opt/$(basename ${REPO_DIR}) stable main" | sudo tee /etc/apt/sources.list.d/local-docker.list
3. 更新索引: sudo apt-get update
4. 安装: sudo apt-get install -y docker-ce=${DOCKER_VERSION} docker-ce-cli=${DOCKER_VERSION} docker-compose-plugin containerd.io
5. 锁定版本: sudo apt-mark hold docker-ce docker-ce-cli containerd.io

验证: docker version
EOF
    
    # 打包
    tar czvf "${OUTPUT_FILE}" .
    
    log_info "✅ 离线仓库制作完成!"
    log_info "输出文件: ${OUTPUT_FILE}"
    log_info "大小: $(du -h ${OUTPUT_FILE} | cut -f1)"
    log_info "软件包数量: $(ls pool/main/*.deb 2>/dev/null | wc -l)"
    log_info ""
    log_info "请将该文件传输到离线环境,按 INSTALL_README.txt 说明安装"
}

# 7. 可选:配置 Docker 镜像加速(用于拉取业务镜像)
setup_docker_mirror() {
    if [[ -n "${ALIYUN_MIRROR}" ]]; then
        log_info "配置 Docker Hub 镜像加速: ${ALIYUN_MIRROR}"
        sudo mkdir -p /etc/docker
        sudo tee /etc/docker/daemon.json <<EOF
{
  "registry-mirrors": ["${ALIYUN_MIRROR}"]
}
EOF
        sudo systemctl restart docker 2>/dev/null || true
        log_info "Docker 镜像加速已配置,现在可以执行 docker pull 拉取基础镜像"
    fi
}

# 主流程
main() {
    log_info "开始制作 Docker 20.10.24 离线仓库 (Ubuntu ${UBUNTU_VER})..."
    
    # 检查依赖
    if ! command -v dpkg-scanpackages &> /dev/null; then
        log_error "缺少 dpkg-dev,正在安装..."
        sudo apt-get update && sudo apt-get install -y dpkg-dev apt-rdepends
    fi
    
    clean_old_repo
    setup_apt_source
    download_packages
    clean_cross_version
    generate_index
    package_repo
    setup_docker_mirror
    
    log_info "全部完成!"
}

# 执行
main "$@"

执行 ./install.sh

二. 离线安装

将在线的仓库压缩包上传服务器并解压
tar -xvf xxxx.tar -C /opt/docker

评论