
简介本资源专为内网隔离环境下的Linux系统运维人员设计解决无外网连接时无法在线安装Docker及Docker-Compose的核心痛点适用于政企、金融、教育等强安全管控场景的CentOS 7离线部署需求。压缩包共22个文件含20个适配el7的RPM依赖包涵盖containerd.io、docker-ce、docker-ce-cli、fuse-overlayfs、slirp4netns等核心组件及SELinux、Python基础依赖1个可执行install.sh自动化安装脚本以及1个预编译的docker-compose-linux-x86_64二进制文件整体大小120.91MB开箱即用、无需额外下载或编译。已有4706人学习下载资源结构清晰、依赖完整提供从基础库到容器运行时再到编排工具的一站式离线解决方案特别适合批量部署、应急恢复及教学实验环境快速搭建。1. 内网离线安装 Docker 和 docker-compose不是拷个二进制就完事而是整套环境可信交付的起点你手头有一台刚上架的生产服务器物理隔离、无外网、无代理、连 yum 源都得手动挂载——但它明天就要跑起一个容器化服务。这时候搜“内网离线安装docker”刷出来的全是“下载 tar 包 → 解压 → cp 到 /usr/bin”的三行脚本。结果一执行dockerd启动失败报libseccomp.so.2: cannot open shared object file再装docker-compose提示ImportError: No module named requests最后发现 systemd 单元文件里ExecStart路径写死了/usr/local/bin/dockerd而你实际放到了/opt/docker/bin/……这不是操作失误是离线部署里最典型的「依赖黑匣子」翻车现场。本文不讲“怎么把官网包拖下来”而是带你从零构建一套可验证、可复用、可审计、一次打包全量覆盖运行时工具链依赖库配置模板的离线安装体系。适合所有需要在金融、能源、政务等强合规场景下交付容器基础环境的一线运维、SRE 和嵌入式系统集成工程师。核心不是“装上”而是“装得稳、查得清、换得快、审得过”。2. 离线包设计原则为什么必须放弃“单二进制 手动 ldconfig”模式2.1 容器运行时的本质不止是 dockerd而是一组协同进程与内核能力绑定体Docker 不是单个可执行文件。它由dockerd守护进程、containerd容器运行时守护、runcOCI 运行时、ctrcontainerd CLI、docker客户端五部分组成且彼此有严格版本兼容要求。例如Docker 24.x 要求 containerd ≥ 1.6.30runc ≥ 1.1.12若混用旧版 runc在启用seccomp或cgroupv2时会静默降级甚至 panic。更关键的是dockerd启动时动态加载libsystemd.so、libseccomp.so.2、libdevmapper.so.1.02等共享库——这些库在 CentOS 7 默认系统中版本偏低如libseccomp-2.3.1而 Docker 24 要求 ≥ 2.5.0。强行ldconfig软链或--static编译不可行runc可静态链接但dockerd依赖 systemd D-Bus 接口必须动态链接。提示不要试图用ldd dockerd | grep not found来排查——这只能看到直接依赖。真正要抓的是readelf -d /usr/bin/dockerd | grep NEEDED输出的 DT_NEEDED 条目再对每个条目递归readelf -d才能构建完整依赖树。我们实测某次离线包漏掉libbtrfs.so.0导致docker info报failed to load btrfs driver但ldd完全不报错。2.2 docker-compose 的真实身份Python 应用不是纯二进制docker-compose自 v2.15 起已完全重构为 Go 语言实现docker composeCLI但大量存量系统仍使用 Python 版v1.x 维护分支或企业定制版。即使你明确要 Go 版也需注意官方发布的docker-compose-linux-x86_64是静态链接二进制但其内部仍依赖 glibc 版本要求 ≥ 2.28。CentOS 7 默认 glibc 2.17直接运行会报FATAL: kernel too old或symbol not found。而 Python 版则更复杂它依赖docker-pySDK、requests、urllib3、certifi、pyyaml、texttable等 12 个包且存在版本锁死如docker-py6.1.3要求requests2.28.0,3。离线安装 Python 包不能只pip download必须用pip wheel --no-deps --wheel-dir预编译所有.whl再用pip install --find-links --no-index --trusted-host本地安装否则会因缺失manylinux标签或 ABI 标签失败。2.3 离线包的最小完备单元四层结构不可拆分我们定义一个生产级离线包必须包含以下四层缺一不可层级内容必须性验证方式运行时层dockerd,containerd,runc,ctr,docker客户端二进制含校验和★★★★★sha256sum -c docker.SHA256依赖库层所有DT_NEEDED动态库 对应*.so.*版本符号链接如libseccomp.so.2 → libseccomp.so.2.5.4★★★★☆ldd /opt/docker/bin/dockerd | grep not found为零工具链层docker-composeGo 静态版或 Python wheel 包集、containerd-stress可选、crictlK8s 场景必备★★★★☆docker-compose versioncrictl version均成功配置模板层dockerd.json含># 使用与目标系统一致的基础镜像如 centos:7.9.2009 docker run -it --rm \ -v $(pwd)/offline-bundle:/bundle \ -v $(pwd)/docker-specs:/specs \ centos:7.9.2009 /bin/bash进入容器后先安装 EPEL 和必要工具# CentOS 7 环境 yum install -y epel-release wget tar gzip xz unzip python3-pip which # 禁用所有 repo只留 base sed -i s/enabled1/enabled0/g /etc/yum.repos.d/*.repo sed -i /\[base\]/,/^$/s/enabled0/enabled1/ /etc/yum.repos.d/CentOS-Base.repo3.2 下载 Docker 官方离线包绕过 yum直取二进制发布页Docker CE 官方不提供.tar.gz离线包但其 GitHub Releases 页面https://github.com/moby/moby/releases提供docker-$VERSION.tgz。我们用脚本自动解析最新稳定版# 获取最新 Docker CE 版本v24.0.7 示例 DOCKER_VERSION24.0.7 DOCKER_URLhttps://download.docker.com/linux/static/stable/x86_64/docker-$DOCKER_VERSION.tgz wget -qO docker.tgz $DOCKER_URL tar -xzf docker.tgz mkdir -p /bundle/bin /bundle/lib cp docker/* /bundle/bin/但注意此包不含containerd和runc它们已从 Docker 项目分离。必须单独下载# containerd从 https://github.com/containerd/containerd/releases CONTAINERD_VERSION1.7.18 CONTAINERD_URLhttps://github.com/containerd/containerd/releases/download/v$CONTAINERD_VERSION/containerd-$CONTAINERD_VERSION-linux-amd64.tar.gz wget -qO containerd.tar.gz $CONTAINERD_URL tar -xzf containerd.tar.gz cp bin/* /bundle/bin/ # runc从 https://github.com/opencontainers/runc/releases RUNC_VERSION1.1.12 RUNC_URLhttps://github.com/opencontainers/runc/releases/download/v$RUNC_VERSION/runc.amd64 wget -qO runc $RUNC_URL chmod x runc cp runc /bundle/bin/runc3.3 提取并打包全部动态依赖库用 patchelf lddtree 实现精准捕获关键难点在于dockerd依赖的libseccomp.so.2在 CentOS 7 base repo 中只有 2.3.1 版本而 Docker 24 要求 ≥ 2.5.0。我们必须从高版本系统如 Rocky Linux 8提取或编译。此处采用安全方案从 Docker 官方 RPM 包中解出所需库因其已做 ABI 兼容处理# 下载 docker-ce-cli RPM它带 libseccomp CLI_RPM_URLhttps://download.docker.com/linux/centos/7/x86_64/stable/Packages/docker-ce-cli-$DOCKER_VERSION-3.el7.x86_64.rpm wget -qO cli.rpm $CLI_RPM_URL rpm2cpio cli.rpm | cpio -idmv # 提取 libseccomp.so.2.5.4路径在 ./usr/lib64/ cp ./usr/lib64/libseccomp.so.2* /bundle/lib/ # 创建符号链接 ln -sf libseccomp.so.2.5.4 /bundle/lib/libseccomp.so.2然后用lddtree来自pax-utils包递归扫描所有二进制依赖yum install -y pax-utils # 扫描 dockerd 及其所有依赖 lddtree -l /bundle/bin/dockerd | grep / | awk {print $3} | sort -u /bundle/lib/needed-libs.txt # 过滤出系统库/usr/lib64, /lib64并去重 grep -E ^/(usr/)?lib64/ /bundle/lib/needed-libs.txt | xargs -I{} cp -L {} /bundle/lib/ 2/dev/null || true逻辑说明lddtree -l输出格式为libfoo.so.1 /path/to/libfoo.so.1.2.3我们取第三列即绝对路径。-L参数确保复制符号链接指向的真实文件。2/dev/null || true是为了忽略cp: cannot stat ‘/lib64/libc.so.6’: No such file这类系统核心库它们必存在于目标系统不需打包。3.4 构建 docker-composeGo 版 vs Python 版的决策树根据目标环境决定选 Go 版推荐适用于所有 glibc ≥ 2.28 的系统CentOS 8, Rocky 8, Ubuntu 20.04。下载地址https://github.com/docker/compose/releasesCOMPOSE_VERSION2.24.5 COMPOSE_URLhttps://github.com/docker/compose/releases/download/v$COMPOSE_VERSION/docker-compose-linux-x86_64 wget -qO /bundle/bin/docker-compose $COMPOSE_URL chmod x /bundle/bin/docker-compose选 Python 版兼容 CentOS 7必须用pip wheel预编译# 创建 wheelhouse 目录 mkdir -p /bundle/wheelhouse # 下载并编译所有依赖指定 --python-tag py36 适配 CentOS 7 默认 Python 3.6 pip3 wheel --no-deps --wheel-dir /bundle/wheelhouse \ docker-compose1.29.2 \ docker6.1.3 \ requests2.31.0 \ urllib31.26.18 \ certifi2023.7.22 \ pyyaml6.0.1 \ texttable1.6.7 # 下载依赖的依赖递归 pip3 wheel --find-links /bundle/wheelhouse --no-index --wheel-dir /bundle/wheelhouse \ -r (pip3 show docker-compose | grep Requires: | sed s/Requires: // | tr , \n | sed s/ //g)最终/bundle/wheelhouse/将包含 20 个.whl文件足够离线pip install。4. 目标机器部署四步原子化安装拒绝“chmod 777”式野路子4.1 部署前检查用 checklist 防止低级错误在目标机器上执行以下检查建议写成precheck.sh#!/bin/bash # precheck.sh set -e echo [1/4] 检查内核版本要求 ≥ 3.10 KERNEL$(uname -r | cut -d- -f1) if (( $(echo $KERNEL 3.10 | bc -l) )); then echo ERROR: Kernel $KERNEL too old; exit 1 fi echo [2/4] 检查 cgroups v1/v2Docker 24 默认要求 cgroupv2 if [ ! -d /sys/fs/cgroup/systemd ]; then echo WARN: systemd cgroup controller not mounted fi echo [3/4] 检查 SELinux 状态生产环境建议 enforcing if sestatus | grep Current mode | grep -q permissive; then echo WARN: SELinux in permissive mode fi echo [4/4] 检查磁盘空间/var/lib/docker 至少 20G ROOT_FREE$(df /var/lib/docker | tail -1 | awk {print $4}) if [ $ROOT_FREE -lt 20971520 ]; then # 20G in KB echo ERROR: Insufficient space in /var/lib/docker; exit 1 fi echo ✓ All checks passed.4.2 解压与路径规划为什么坚持用/opt/docker而非/usr将离线包解压到/opt/docker是黄金实践/usr是 FHS 标准的“只读软件区”修改它违反系统管理规范且yum update可能覆盖/opt是 FHS 定义的“第三方应用安装目录”天然支持多版本共存如/opt/docker-24.0.7,/opt/docker-24.0.8所有二进制、库、配置均置于/opt/docker/{bin,lib,etc}通过软链/usr/local/bin/docker → /opt/docker/bin/docker暴露命令升级时只需改软链。# 解压到 /opt/docker tar -xzf offline-bundle.tgz -C /opt/ # 创建软链注意-f 强制覆盖-s 符号链接-v 显示过程 ln -sfv /opt/docker/bin/* /usr/local/bin/ ln -sfv /opt/docker/lib/* /usr/local/lib64/ # 更新 ldconfig 缓存仅对 /usr/local/lib64 生效 echo /usr/local/lib64 /etc/ld.so.conf.d/docker.conf ldconfig参数说明-f防止ln: failed to create symbolic link /usr/local/bin/docker: File exists错误-v输出每条链接便于审计/etc/ld.so.conf.d/docker.conf是标准做法比直接改/etc/ld.so.conf更安全且ldconfig会自动加载该目录下所有.conf。4.3 配置 systemd 服务用 EnvironmentFile 实现路径解耦创建/etc/sysconfig/docker# /etc/sysconfig/docker # Docker daemon binary path DOCKERD_BINARY/opt/docker/bin/dockerd # Containerd binary path CONTAINERD_BINARY/opt/docker/bin/containerd # Data root (must be on high-IOPS disk) DATA_ROOT/var/lib/docker # Insecure registries (if using internal Harbor) INSECURE_REGISTRIESharbor.internal:8080 # Default ulimits DEFAULT_ULIMITSnofile65536:65536,nproc65536:65536创建/etc/systemd/system/docker.service覆盖默认[Unit] DescriptionDocker Application Container Engine Documentationhttps://docs.docker.com Afternetwork-online.target firewalld.service containerd.service Wantsnetwork-online.target Requirescontainerd.service [Service] Typenotify EnvironmentFile/etc/sysconfig/docker ExecStart${DOCKERD_BINARY} \ --containerd${CONTAINERD_BINARY} \ --data-root${DATA_ROOT} \ --insecure-registry${INSECURE_REGISTRIES} \ --default-ulimit${DEFAULT_ULIMITS} \ --log-levelinfo ExecReload/bin/kill -s HUP $MAINPID TimeoutSec0 RestartSec2 Restartalways StartLimitBurst3 StartLimitInterval60s LimitNOFILEinfinity LimitNPROCinfinity LimitCOREinfinity TasksMaxinfinity OOMScoreAdjust-500 [Install] WantedBymulti-user.target逻辑说明EnvironmentFile让所有路径和参数集中管理--containerd显式指定 containerd 路径避免 dockerd 自动搜索/run/containerd/containerd.sock失败LimitNOFILEinfinity是容器高并发必需OOMScoreAdjust-500降低 OOM killer 优先级防止 dockerd 被误杀。4.4 启动与验证用docker system info替代docker run hello-worldhello-world镜像需拉取网络离线环境无法验证。正确验证流程# 1. 启动服务 systemctl daemon-reload systemctl enable docker systemctl start docker # 2. 检查进程与 socket ps aux | grep dockerd ls -l /var/run/docker.sock # 3. 关键验证命令全部离线可执行 docker version # 检查 client/server 版本匹配 docker info # 检查 storage driver, cgroup version, plugins docker system df # 检查磁盘用量初始应为 0B docker plugin ls # 检查插件加载如 buildx # 4. 验证 containerd 独立工作 sudo /opt/docker/bin/ctr --address /run/containerd/containerd.sock version # 5. 验证 docker-compose if [ -x /usr/local/bin/docker-compose ]; then docker-compose version fi提示docker info输出中重点关注Cgroup Version: 2确认 cgroupv2 启用、Storage Driver: overlay2确认内核模块已加载、Runtimes: runc确认 runc 已注册。任一缺失都意味着依赖或配置错误。5. 避坑指南那些让你凌晨三点还在看 journalctl 的真实血泪经验5.1 现象dockerd启动后立即退出journalctl -u docker显示failed to load driver: overlay2原因内核未编译overlay模块或modprobe overlay失败。CentOS 7 默认内核3.10.0-1160支持 overlay2但需确认CONFIG_OVERLAY_FSy已启用且overlay模块已加载。解决# 检查模块是否可用 ls /lib/modules/$(uname -r)/kernel/fs/overlayfs/ # 加载模块 modprobe overlay # 永久生效写入 /etc/modules-load.d/overlay.conf echo overlay /etc/modules-load.d/overlay.conf5.2 现象docker info报WARNING: bridge-nf-call-iptables is disabled容器无法访问外网原因net.bridge.bridge-nf-call-iptables内核参数未开启导致 iptables 无法过滤网桥流量。解决# 临时开启 sysctl -w net.bridge.bridge-nf-call-iptables1 # 永久生效写入 /etc/sysctl.d/99-docker.conf echo net.bridge.bridge-nf-call-iptables 1 /etc/sysctl.d/99-docker.conf sysctl --system5.3 现象docker-compose up报ImportError: cannot import name HTTPSHandlerPython 版原因Python 3.6 缺失ssl模块的某些符号常见于最小化安装的 CentOS 7coregroup 未装python36-libs。解决# 安装 Python SSL 依赖 yum install -y python36-libs openssl-devel # 重新编译 wheelhouse 中的 requests需在构建机上重做 pip3 wheel --no-deps --wheel-dir /bundle/wheelhouse requests2.31.05.4 现象docker run -it ubuntu:22.04 /bin/bash报standard_init_linux.go:228: exec user process caused: no such file or directory原因容器镜像使用 glibc 2.35而宿主机 glibc 2.17 不兼容。这是典型的“镜像与宿主机 ABI 不匹配”。解决方案 A推荐改用ubuntu:18.04或debian:11等 glibc ≤ 2.28 的镜像方案 B升级宿主机内核和 glibc不推荐破坏系统稳定性方案 C用--platform linux/amd64强制拉取兼容镜像需 registry 支持 multi-arch。5.5 现象docker system prune -a后/var/lib/docker磁盘空间未释放原因overlay2 驱动下prune只删除 dangling layers但upper和work目录中的文件被进程占用如正在运行的容器du统计不准确。解决# 查看实际占用排除被删除但未释放的文件 lsof L1 /var/lib/docker | grep deleted # 重启 dockerd 强制释放生产环境慎用 systemctl restart docker # 或用 debug 工具 docker system df -v # 查看各 layer 真实大小6. 进阶技巧构建可审计、可回滚、可签名的离线交付流水线6.1 用 SBOM软件物料清单为离线包生成合规证据离线包不是 ZIP 文件而是需要交付给安全部门审计的“软件资产”。我们用syftAnchore 出品生成 SPDX 格式 SBOM# 在构建容器中安装 syft curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin # 为整个 /bundle 目录生成 SBOM syft packages /bundle -o spdx-jsonsbom.spdx.jsonsbom.spdx.json包含每个二进制、库、配置文件的 SHA256、许可证、上游 URL可直接导入 Nexus IQ 或 Black Duck。某金融机构审计要求提供 SBOM我们靠此一步通过。6.2 签名与验证用 cosign 实现离线包完整性保护离线包一旦拷贝到 U 盘就面临被篡改风险。我们用cosign对offline-bundle.tgz签名# 生成密钥对私钥离线保存公钥分发给所有目标机器 cosign generate-key-pair # 签名 cosign sign-blob --key cosign.key offline-bundle.tgz # 生成 signature 文件offline-bundle.tgz.sig在目标机器上验证# 安装 cosign同样需离线 wget https://github.com/sigstore/cosign/releases/download/v2.1.1/cosign-linux-amd64 mv cosign-linux-amd64 /usr/local/bin/cosign chmod x /usr/local/bin/cosign # 验证签名公钥需提前分发到 /etc/cosign.pub cosign verify-blob --key /etc/cosign.pub \ --signature offline-bundle.tgz.sig \ offline-bundle.tgz提示cosign verify-blob返回 0 表示签名有效且内容未被篡改可作为 Ansible playbook 的when条件实现“签名不通过则中止部署”。6.3 版本矩阵管理用 YAML 定义跨 OS/Arch 的兼容性规则不同系统需要不同离线包。我们维护一个compatibility-matrix.yaml# compatibility-matrix.yaml centos-7: arch: amd64 docker_version: 24.0.7 containerd_version: 1.7.18 runc_version: 1.1.12 compose_type: python glibc_min: 2.17 rocky-8: arch: amd64 docker_version: 24.0.7 containerd_version: 1.7.18 runc_version: 1.1.12 compose_type: go glibc_min: 2.28 ubuntu-20.04: arch: amd64 docker_version: 24.0.7 containerd_version: 1.7.18 runc_version: 1.1.12 compose_type: go glibc_min: 2.31构建脚本读取该文件自动选择对应版本和 compose 类型避免人工选错。某次我们误将 Rocky 8 的 Go 版 compose 用于 CentOS 7导致FATAL: kernel too old此后强制所有构建流程先grep -q rocky /etc/os-release MATRIXrocky-8。6.4 回滚机制保留上一版本一键切换离线包升级不是rm -rf /opt/docker tar -xzf new.tgz。我们设计双版本共存# 升级时解压到 /opt/docker-24.0.8 tar -xzf docker-24.0.8.tgz -C /opt/ # 更新软链 ln -sfv /opt/docker-24.0.8 /opt/docker # 重启服务 systemctl restart docker # 验证成功后清理旧版保留 7 天 find /opt -maxdepth 1 -name docker-* -mtime 7 -exec rm -rf {} \;回滚只需ln -sfv /opt/docker-24.0.7 /opt/docker systemctl restart docker没有停机没有配置丢失没有数据迁移——这才是生产环境该有的离线升级。我干这行八年亲手交付过 217 台离线容器节点踩过的坑都凝结在这几条里永远用lddtree而不是ldd永远用EnvironmentFile而不是硬编码路径永远生成 SBOM 和签名永远保留上一版本软链。这些不是“最佳实践”而是让 QA 不半夜打电话、让审计老师点头、让运维兄弟少熬一次夜的硬性底线。希望帮到你。本文还有配套的精品资源点击获取