一. 在线环境安装依赖
#!/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