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/enabled=1/enabled=0/g' /etc/yum.repos.d/*.repo sed -i '/\[base\]/,/^$/s/enabled=0/enabled=1/' /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_VERSION="24.0.7" DOCKER_URL="https://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_VERSION="1.7.18" CONTAINERD_URL="https://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_VERSION="1.1.12" RUNC_URL="https://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_URL="https://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-compose:Go 版 vs Python 版的决策树 根据目标环境决定:
选 Go 版(推荐) :适用于所有 glibc ≥ 2.28 的系统(CentOS 8+, Rocky 8+, Ubuntu 20.04+)。下载地址:https://github.com/docker/compose/releases
COMPOSE_VERSION="2.24.5" COMPOSE_URL="https://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-compose==1.29.2 \ docker==6.1.3 \ requests==2.31.0 \ urllib3==1.26.18 \ certifi==2023.7.22 \ pyyaml==6.0.1 \ texttable==1.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/v2(Docker 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_REGISTRIES="harbor.internal:8080" # Default ulimits DEFAULT_ULIMITS="nofile=65536:65536,nproc=65536:65536"创建/etc/systemd/system/docker.service(覆盖默认):
[Unit] Description=Docker Application Container Engine Documentation=https://docs.docker.com After=network-online.target firewalld.service containerd.service Wants=network-online.target Requires=containerd.service [Service] Type=notify EnvironmentFile=/etc/sysconfig/docker ExecStart=${DOCKERD_BINARY} \ --containerd=${CONTAINERD_BINARY} \ --data-root=${DATA_ROOT} \ --insecure-registry=${INSECURE_REGISTRIES} \ --default-ulimit=${DEFAULT_ULIMITS} \ --log-level=info ExecReload=/bin/kill -s HUP $MAINPID TimeoutSec=0 RestartSec=2 Restart=always StartLimitBurst=3 StartLimitInterval=60s LimitNOFILE=infinity LimitNPROC=infinity LimitCORE=infinity TasksMax=infinity OOMScoreAdjust=-500 [Install] WantedBy=multi-user.target逻辑说明:EnvironmentFile让所有路径和参数集中管理;--containerd显式指定 containerd 路径,避免 dockerd 自动搜索/run/containerd/containerd.sock失败;LimitNOFILE=infinity是容器高并发必需;OOMScoreAdjust=-500降低 OOM killer 优先级,防止 dockerd 被误杀。
4.4 启动与验证:用docker system info替代docker run hello-world hello-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_FS=y已启用,且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-iptables=1 # 永久生效(写入 /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 'HTTPSHandler'(Python 版) 原因 :Python 3.6 缺失ssl模块的某些符号,常见于最小化安装的 CentOS 7(@coregroup 未装python36-libs)。
解决 :
# 安装 Python SSL 依赖 yum install -y python36-libs openssl-devel # 重新编译 wheelhouse 中的 requests(需在构建机上重做) pip3 wheel --no-deps --wheel-dir /bundle/wheelhouse requests==2.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 文件,而是需要交付给安全部门审计的“软件资产”。我们用syft(Anchore 出品)生成 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-json=sbom.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 && MATRIX=rocky-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 不半夜打电话、让审计老师点头、让运维兄弟少熬一次夜的硬性底线。希望帮到你。
本文还有配套的精品资源,点击获取
版权声明:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设
2026/10/11 4:25:45
【免费下载链接】edgeone-makers-tools 项目地址: https://gitcode.com/gh_mirrors/ed/edgeone-makers-tools 点击查看 免费下载 edgeone-makers-tools 是 EdgeOne Makers 平台官方的 AI 技能包,它用一个"路由型"架构把 11 个开发能力域装进单…
李华
网站建设
2026/10/11 4:24:39
如果要我在C里挑一个最容易被低估、却又最容易让人翻车的关键字,我大概率会选static。你去看C:static这种标题,总觉得是个入门知识点,好像谁都会 ,可真要在项目里用稳了,能把人折腾到半夜去查链接错误、初始…
李华
网站建设
2026/10/11 4:24:36
awesome-design-md 深度解析:73 份品牌设计档案,两步让 AI 生成符合 DESIGN.md 的品牌 UI 【免费下载链接】awesome-design-md A collection of DESIGN.md files analysis by popular brand design systems. Drop one into your project and let coding …
李华
网站建设
2026/10/11 4:23:59
某宝搜索结果页爬虫开发某宝列表页搜索结果提取工具采集工具,开发完了人家不要了,闲置,未发布软件,交流一下1.支持关键字、销量、信用、价格排序搜索采集2.不限量、无限翻页3.导出CVS文件无缝对接上架平台4.一键采集商品全量信息5…
李华
网站建设
2026/10/11 4:23:11
接前一篇文章:软考 系统架构设计师系列知识点之杂项集萃(35) 第58题
对软件体系结构风格的研究和实践促进了对设计的复用。Garlan和Shaw对经典体系结构风格进行了分类。其中,( )属于数据流体系结构风格;( )属于虚拟机体系结构风格;而下图描述的属于( )体系结构风格…
李华
网站建设
2026/10/11 4:21:06
1. 项目定位与核心功能拆解1.1 这个蘑菇百科到底能做什么先把这个项目说清楚。所谓“蘑菇百科”,本质是一个面向科普场景的蘑菇信息检索与管理系统。它解决的实际问题很朴素:蘑菇种类太多、外观相似度又高,光靠翻图鉴或者问人,效率…
李华
编程爱好者
专注于前端开发和人工智能领域,热爱分享技术心得和编程技巧。
关于博客
这是一个专注于编程技术分享的极简博客,旨在为开发者提供高质量的技术文章和教程。