资讯详情

内网离线安装 Docker 与 Docker Compose 全流程与避坑

📅 2026/10/28 13:36:56 | 华诺云谱 👁 阅读
内网离线安装 Docker 与 Docker Compose 全流程与避坑
简介面向内网、隔离环境及无法访问外网的服务器运维与开发人员这套资源提供可在离线条件下完成 Docker 与 Docker Compose 部署的依赖集合重点解决无外网时软件源不可用、RPM 依赖缺失、组件版本不匹配以及手工安装易出错等问题。压缩包共 22 个文件约 120.91MB其中 20 个 rpm 包覆盖容器运行时、SELinux 策略、Python 工具链等基础依赖另附 1 个安装脚本和 1 个 docker-compose 的 Linux x86_64 可执行文件便于按序安装、快速校验与版本对齐。已有 4712 人学习下载。读者可据此在 CentOS 7 类系统上完成 docker-ce 20.10.7、CLI、containerd.io 等组件的离线落地借助脚本减少逐包手工操作的重复劳动同时理解依赖闭环处理、Compose 二进制部署和内网交付思路适合批量部署、生产内网迁移或实验环境搭建等场景。1. 内网离线安装 docker 和 docker-compose卡住的通常不是命令内网离线安装 docker 和 docker-compose最容易翻车的地方不是命令记不住而是包没带全。上个月在一批隔离网段的机器上补容器环境机器连内网 yum 源都没配好我只能用移动硬盘把 rpm 拷进去。第一次只带了 docker-ce 和 docker-ce-cli 两个包yum install当场报 container-selinux 依赖缺失装到一半退出残留的 containerd 服务还起不来只能先卸干净再来一遍。这类环境在离线机房、生产车间、实验平台里非常普遍机器能通电、能连内网、就是不出公网。装不好的代价不是docker 用不了这么轻——半装状态会让 systemd 里留下失败单元后续哪怕补全了包也要先systemctl reset-failed清一遍。这套流程适合两类人一类是从没在内网装过容器、手里只有一台能出网的跳板机的开发者另一类是装过但总在依赖和配置上反复返工的人。2. 装机前把离线包凑齐版本对照与依赖清单离线安装的成败八成在进机房之前就决定了。我现在的习惯是先在跳板机上把所有东西拉全、验一遍再往内网搬。搬过去才发现少一个包来回一趟的成本比前期多花二十分钟高得多。2.1 先确认离线机的发行版和内核别照抄别人的包离线包不能跨发行版、跨大版本混用。CentOS 7 的 rpm 装不到 Ubuntu 上也装不到 Stream 9 上x86_64 的二进制塞给 ARM 机器只会报格式错误。所以第一步是登到目标机器上把身份信息记清楚。# 在离线机上执行把输出抄下来回跳板机对照 cat /etc/os-release # 只认 VERSION_ID比如 7 / 8 / 9 / 20.04 / 22.04 uname -r # 内核版本决定 overlay2 和 cgroup 能不能用 uname -m # x86_64 还是 aarch64包要对得上 systemctl --version | head -n 1 # systemd 版本老版本不支持某些 unit 指令 getenforce # SELinux 开着的话container-selinux 必须带这一步的意义在于把我以为变成确认过。我见过最典型的一次误判跳板机是 CentOS 7.9内网机是 7.6内核 3.10.0-957装完 docker 之后 overlay2 能起来但 cgroup v1 下的资源限制行为跟文档描述不一致排查了半天才发现是内核小版本差异。发行版大版本一致是底线内核小版本尽量也靠拢。还有一项容易被忽略目标机器的磁盘布局。/var/lib/docker默认在根分区容器一多根分区写满会连带系统日志一起挂掉。所以装之前先看一眼df -h和lsblk有没有单独的数据盘可以挂到/data。这个决定要在安装前做装完再迁数据目录就得多一轮停机和 rsync。提示跳板机的发行版和架构必须与目标机完全一致不要用差不多的机器凑合这是离线安装返工率最高的一项。2.2 用 yumdownloader 把依赖一次性拉全rpm 系拉包我一般用yumdownloader --resolve它会把目标包的传递依赖一起递归下载下来比手工一个个人肉找靠谱。# 在能出网、且系统版本与内网机一致的跳板机上执行 mkdir -p /opt/docker-offline cd /opt/docker-offline # yum-utils 提供 yumdownloadercreaterepo_c 用来后面做本地源 yum install -y yum-utils createrepo_c # --resolve 递归解决依赖--destdir 指定落地目录 # 明确写出组件别只写 docker-ce缺 component 会漏包 yumdownloader --resolve --destdir/opt/docker-offline \ docker-ce \ docker-ce-cli \ containerd.io \ docker-buildx-plugin \ docker-compose-plugin # 包数量低于 5 个基本可以判定没拉全 ls -1 /opt/docker-offline/*.rpm | wc -l--resolve是关键参数它让 yum 按依赖关系把 container-selinux、libcgroup、pigz 这类间接依赖一并带上。如果跳板机同时配了多个架构可以再加--archlistx86_64,noarch把无关架构过滤掉避免目录里混进 aarch64 的包。拉完之后别急着拷走先在跳板机上做一次干跑确认依赖闭合# --test 只做依赖检查和冲突检查不真正落盘 rpm -ivh --test /opt/docker-offline/*.rpm # 逐个看每个包的依赖声明确认没有指向仓库之外的包 rpm -qpR /opt/docker-offline/docker-ce-*.rpm干跑没有输出Failed dependencies才说明这套包能自洽地装下去。如果有缺失回到上一步补下载不要指望到了内网再想办法。另外还有一种做法是repotrack它会把整个仓库的依赖全下下来包数量动辄上百适合完全未知的离线环境。但多数情况下--resolve已经够用包少、搬运快、也不容易在下游机器上触发版本冲突。2.3 版本对照docker 引擎、containerd、compose 三者怎么搭版本选择这一环网上的说法很乱我的取舍标准只有两条内核支持度和后续可维护性。组件选择倾向需要注意的点docker 引擎内网长期不动选 20.10 系列内核 4.x 以上可选 23.0 及以后新版本对 iptables/nftables 有要求老内核上要先验证网络containerd.io跟着 docker-ce 的依赖版本走不自选版本不匹配会导致 dockerd 启动后立刻退出docker-compose统一用 v2Go 单二进制或 CLI 插件v1 是 Python 实现离线缺依赖且命令前缀不同buildx / compose 插件一并带上避免后续要用再补插件版命令是docker compose没有横杠经验上的结论是内核低于 4.x 的机器尽量别上最新大版本20.10 系列在老环境里更稳内核 4.x 以上、且确定不再改动基础设施的可以选 23.0 之后的版本。containerd.io 不要单独指定版本让它跟着 docker-ce 的依赖解析走手选版本是血泪经验换来的教训——依赖树一错dockerd 会以启动成功但立刻退出的方式报错日志里只有一行failed to start containerd很难往版本上想。compose 这边建议直接放弃 v1。v1 是 Python 脚本离线机上缺python3或某个 site-package 就跑不起来v2 是静态编译的单个二进制拷过去加执行权限就能用天然适合内网。包齐了、版本定了再进入实际安装。到这一步剩下的活基本是顺序问题。3. 安装 docker 引擎rpm 与 deb 两条路的执行顺序安装顺序比安装命令本身重要。我见过不少人把rpm -ivh一把梭结果依赖顺序不对装到一半失败再补包又提示已安装最后只能rpm -e --nodeps强卸留下一个半残的系统。3.1 rpm 系按依赖顺序装还是让 yum 一次解rpm 系有两条路让 yum 从本地目录解依赖或者按手工顺序逐个rpm -ivh。我优先选前者。# 把离线包传到内网机目录结构保持一致 mkdir -p /opt/docker-offline # 假设包已经拷到 /opt/docker-offline 下 # 方式一yum 从本地文件解依赖推荐 yum install -y /opt/docker-offline/*.rpm # 方式二建本地源适合包多、需要反复装的场景 createrepo_c /opt/docker-offline cat /etc/yum.repos.d/docker-offline.repo EOF [docker-offline] namedocker offline packages baseurlfile:///opt/docker-offline enabled1 gpgcheck0 EOF yum --disablerepo* --enablerepodocker-offline install -y docker-ce docker-ce-cli containerd.io方式一的优点是 yum 自己排序先把 containerd.io 卸到系统里再装 docker-ce依赖链一次走完。方式二多了一步建源但当你要在内网多台机器上重复装的时候把源配上比每台都跑一遍yum install *.rpm干净得多也便于后续补包。这里有个硬性纪律不要用rpm -ivh --nodeps绕过依赖。绕过之后 docker 是装上了但 container-selinux 缺失会导致 SELinux 开着时容器起不来报错信息指向/var/lib/docker的 context 问题跟依赖没装八竿子打不着很容易把人带偏。装完先做一次清点# 确认关键组件都在且版本是预期的那一套 rpm -qa | grep -E docker-ce|containerd.io|docker-compose-plugin | sort # 确认二进制已落地 which docker docker --versiondocker --version只验证了客户端这时候还看不出服务端能不能起别急着下结论。3.2 deb 系dpkg 与 apt 离线源的区别Debian / Ubuntu 系的机器走另一套逻辑。dpkg -i不会自动解依赖apt install -f在离线机上又必然失败因为它在找公网源。# 只看依赖和已安装状态不落盘 dpkg-deb -I /opt/docker-offline/docker-ce.deb | grep Depends # 一次性装上dpkg 会按传入顺序处理 dpkg -i /opt/docker-offline/*.deb # 检查有没有处于半配置状态的包 dpkg -l | grep -E ^i[^i] | grep -E docker|containerddpkg -l输出里第二列是状态标识ii表示正常安装并配置完成iU或iF就是半残状态这时候要先把缺的依赖补进去再dpkg --configure -a。更省事的做法同样是在离线机本地建 apt 源用dpkg-scanpackages生成Packages.gz写一个deb [trustedyes] file:///opt/docker-offline ./到sources.list.d然后apt-get install -y docker-ceapt 会把依赖关系算清楚。不管走哪条路装完后的第一件事是启动服务再看状态而不是直接跑docker ps。3.3 启动、开机自启与 docker 用户组服务启动这一步看两个输出就够判断健康与否systemctl status和docker version里有没有 Server 段。# 设开机自启并立刻启动两条动作一条命令完成 systemctl enable --now docker # 不要只看 active (running)还要看有没有 restart 记录 systemctl status docker --no-pager # 服务端信息能输出才说明 dockerd 真正跑起来了 docker version # 内核层面的确认cgroup、存储驱动、根目录 docker info | grep -iE cgroup|storage driver|docker root dirsystemctl status里如果出现Main PID后进程号不断变化、或者Active行后面跟着(Result: exit-code)说明 dockerd 在反复重启这时候别去翻容器日志先journalctl -u docker -n 100 --no-pager看启动阶段报了什么。用户组这一步很多离线环境会漏掉。docker 的命令行靠/var/run/docker.sock通信这个文件默认是root:docker、权限 660普通用户不加组就没有写权限。# docker 组一般安装时已自动创建用 -f 保证幂等 groupadd -f docker usermod -aG docker deploy # 验证组成员是否生效需要重新登录会话 id deploy | grep docker加完组必须重新登录或newgrp docker当前 shell 的组信息不会自动刷新这一点上我吃过亏明明id里已经有 docker 组新开的窗口却还报permission denied原因是复用了老的 SSH 会话。4. daemon.json 与 docker-compose配置和第二件工具一起落地引擎装起来只是能跑配置才决定它在这台机器上跑得稳不稳。默认配置有三个坑根目录在系统盘、日志无限增长、cgroup 驱动和上层编排工具不一致。这三件事都在/etc/docker/daemon.json里解决。4.1 daemon.json 里真正要改的五个参数这个文件是严格 JSON不能写注释、不能有尾逗号。写完先用python -m json.tool校验一遍再重启能省掉一次服务起不来的排查。{ data-root: /data/docker, exec-opts: [native.cgroupdriversystemd], log-driver: json-file, log-opts: { max-size: 50m, max-file: 3 }, insecure-registries: [10.0.0.10:5000], max-concurrent-downloads: 5, live-restore: true }逐项说明># 语法校验输出格式化后的 JSON 说明合法 python3 -m json.tool /etc/docker/daemon.json /dev/null echo OK # reload 只重载支持热更的配置data-root 这类不生效 systemctl reload docker # 涉及># 1. 停服务确保没有写入 systemctl stop docker # 2. 建新目录注意父目录的属主 mkdir -p /data/docker # 3. 迁移保留硬链接、扩展属性和数字属主 # overlay2 依赖硬链接去重漏了 -H 会多占一份空间 rsync -aHAX --numeric-ids /var/lib/docker/ /data/docker/ # 4. 写入或更新 daemon.json 后启动 systemctl start docker # 5. 确认根目录已切换且镜像列表还在 docker info | grep -i docker root dir docker images-aHAX四个参数缺一不可-a归档模式-H保留硬链接overlay2 的层去重靠它-A保留 ACL-X保留扩展属性。只用cp -r迁过去镜像层会被展开成实体文件占用空间翻倍。迁完先别删旧目录。保留/var/lib/docker至少一天确认容器能正常启动、数据卷能挂上再清理。这就是要留的后悔药。4.3 docker-compose 的两种离线装法独立二进制与 CLI 插件compose 的离线安装本质就是放对位置 给执行权限难点不在命令在位置和名称。第一种是独立二进制命令形式为docker-compose# 从跳板机拷入的二进制文件注意改权限 install -m 0755 /opt/docker-offline/docker-compose-linux-x86_64 /usr/local/bin/docker-compose # 验证版本和权限 docker-compose version # SELinux 开启的机器上必要时给二进制打上可执行上下文 chcon -t bin_t /usr/local/bin/docker-compose 2/dev/null || trueinstall -m 0755一步完成复制和授权比cp加chmod少一个动作也不容易漏。文件名必须是docker-compose不能保留-linux-x86_64后缀否则命令找不到。第二种是作为 docker CLI 插件安装命令形式为docker compose# 插件目录优先级用户级 系统级二选一即可 mkdir -p /usr/local/lib/docker/cli-plugins # 文件名必须叫 docker-composedocker 靠文件名识别子命令 install -m 0755 /opt/docker-offline/docker-compose-linux-x86_64 \ /usr/local/lib/docker/cli-plugins/docker-compose # 验证插件被识别 docker compose version docker info | grep -i cli-plugins两种方式可以共存但我不建议。同一台机器上既有docker-compose又有docker compose版本还不同出一份 docker-compose.yml 排查起来就是玄学问题同一条命令在不同人手里行为不一样最后发现是路径不同。选哪种如果是新装的内网环境我统一走插件方式docker compose跟docker一套版本管理升级时只换一个文件如果内网里已经有一批老脚本写死了docker-compose命令那就装独立二进制或者用软链接把docker-compose指过去。# 兼容老脚本的折中做法插件方式 软链接 ln -sf /usr/local/lib/docker/cli-plugins/docker-compose /usr/local/bin/docker-compose软链接的好处是老脚本不用改坏处是docker-compose version和docker compose version输出相同容易让人误以为是两个独立的程序。5. 离线环境的常见翻车排查五条血泪记录离线环境的排错逻辑跟联网环境不太一样网络相关的报错往往不是网络问题配置相关的报错往往不在配置文件本身。下面这五条是我在内网里反复撞上的按现象 → 原因 → 解决记下来。5.1 dockerd 起不来报错指向 daemon.json 但看不出哪里错现象systemctl start docker失败journalctl -u docker里出现unable to configure the Docker daemon with file /etc/docker/daemon.json后面跟着一行unexpected end of JSON input或类似信息但不说具体哪一行。原因daemon.json 是严格 JSON编辑器自动补的尾逗号、手写的//注释、log-opts里的键值漏引号都会导致整个文件解析失败。dockerd 读取失败后直接退出不会降级使用默认配置。解决用标准 JSON 工具校验然后把错误定位到具体字符。# 输出格式化结果说明 JSON 合法报错会带上行号和列号 python3 -m json.tool /etc/docker/daemon.json # 新版 dockerd 自带校验开关能给出更贴近配置语义的提示 dockerd --validate --config-file /etc/docker/daemon.json我的做法是改之前先cp daemon.json daemon.json.bak改完校验通过再systemctl reload。校验不过当场回滚不要带着一个坏配置去重启服务。5.2 容器里资源限制不生效上层组件报 cgroup 驱动不一致现象docker run --memory512m看着能跑但压力测试时内存照样涨过限制或者接了上层编排组件之后那边健康检查一直失败日志里出现misconfigured cgroup driver。原因dockerd 默认的 cgroup 驱动和 systemd 不一致两边各管各的资源限制写在一边监控和调度看的是另一边。解决在 daemon.json 里显式指定exec-opts: [native.cgroupdriversystemd]重启 docker用docker info确认Cgroup Driver: systemd。如果机器上已经有上层编排组件在跑改完要一起重启否则还是对不上。5.3 docker run 一直卡在拉取镜像最后超时现象docker run hello-world停在Unable to find image ... locally几分钟后报dial tcp: i/o timeout。原因容器要跑的镜像本地没有dockerd 尝试去公网仓库拉而内网根本出不去。这个问题在离线环境里 100% 复现只是安装时容易忘。解决镜像必须离线搬进来两条路。# 路径一在跳板机上导出内网机导入 docker pull nginx:1.25 docker save -o nginx-1.25.tar nginx:1.25 # 内网机上导入导入后 docker images 能看到 docker load -i nginx-1.25.tar # 路径二内网自建仓库推过去再从仓库拉 docker tag nginx:1.25 10.0.0.10:5000/library/nginx:1.25 docker push 10.0.0.10:5000/library/nginx:1.25自建仓库是更长期的方案配合insecure-registries配置使用但仓库本身的部署也是一套离线活先期用save/load过渡更实际。5.4 普通用户执行 docker 命令报 permission denied现象deploy用户执行docker ps报Got permission denied while trying to connect to the Docker daemon socket但id deploy里明明已经有 docker 组。原因Unix 组信息在会话建立时确定usermod -aG改的是账号配置不影响已经存在的登录会话。老 SSH 窗口、tmux 会话、以及某些 sudo 场景下都不会刷新组。解决退出当前会话重新登录或者临时用newgrp docker切换。验证方式是id输出里能看到 docker 组的 GID且ls -l /var/run/docker.sock的组也是 docker。如果重新登录后仍然报错检查 sock 文件权限有没有被别的东西改过systemctl status docker里重启服务会把 sock 重新创建成默认权限。5.5 装完几天后容器批量退出日志写满磁盘现象机器跑了一周容器陆续退出docker ps -a里全是Exiteddf -h显示根分区 100%。原因日志驱动用的是默认的json-file但没有配置轮转单个容器的日志文件涨到几十 GB把所在分区写满。分区满之后 dockerd 无法写入容器状态容器被 OOM 之外的原因终止。解决先清空间再补配置。# 找出占用最大的容器日志文件路径在 /var/lib/docker/containers/id/ 下 du -sh /var/lib/docker/containers/*/*-json.log | sort -rh | head -n 5 # 清理时不要 rm 正在写入的日志文件用 truncate truncate -s 0 /var/lib/docker/containers/容器ID/容器ID-json.log # 在 daemon.json 中补上轮转配置后重启 docker systemctl restart docker已经在跑的容器不会自动继承新配置最稳妥是docker compose up -d --force-recreate重建一遍或者等下次发布自然轮换。提示挂载目录写满也会表现为容器退出排查顺序是先看df -h和df -i再去看容器日志能少走一半弯路。6. 装完怎么验证从 hello-world 到一份 compose 编排跑通装完不等于装好。我判断一套离线容器环境是否真正可用走三步单容器能起来、编排文件能跑通、重启后能自恢复。三步都过了才敢交给业务方。第一步是离线版的 hello-world。它不依赖任何外部服务能跑通说明引擎、镜像、网络这条链是通的。# 跳板机导出最小验证镜像 docker pull hello-world:latest docker save -o hello-world.tar hello-world:latest # 内网机导入并运行 docker load -i hello-world.tar docker run --rm hello-world输出里能看到Hello from Docker!那段文字就说明镜像加载、容器创建、标准输出三条路都正常。如果这一步报permission denied问题在用户组报no such image问题在 load 没成功。第二步是编排文件。用一个最小化的 compose 验证docker compose或docker-compose命令、镜像引用、端口映射、重启策略是否都对。services: web: image: 10.0.0.10:5000/library/nginx:1.25 ports: - 8080:80 restart: unless-stopped logging: driver: json-file options: max-size: 50m max-file: 3这里没有写version:字段新版 compose 已经不需要它写上个老版本号反而会触发一条警告。镜像地址用内网仓库的全路径能顺便验证insecure-registries配置是否生效。# 前台看一次启动过程确认没有隐藏报错 docker compose up -d # 看容器状态和端口映射 docker compose ps # 从宿主机验证服务端口200 就是通的 curl -sI http://127.0.0.1:8080 | head -n 1 # 看日志有没有权限或配置类错误 docker compose logs --tail30第三步是重启验证。离线环境里最怕的是装完能跑重启就废所以我会直接reboot一次起来之后检查三个点。检查项命令期望结果docker 服务自启systemctl is-enabled dockerenabled数据目录未丢docker images之前的镜像还在容器自恢复docker compose ps状态 Up不是 Exited# 重启后一次性过一遍 systemctl is-active docker docker info | grep -i docker root dir docker compose -f /opt/demo/docker-compose.yml ps df -h /data最后一行df -h是我必看的。离线机器的磁盘扩容不像云端那么方便装完先确认数据盘使用率在合理范围比出事之后再处理轻松得多。这套流程我现在每次进机房都完整走一遍哪怕只是给一台机器补装 compose。装完不复验把问题留给业务方是我早期最常见的失误从那以后只要涉及容器环境我都强制把这套流程跑完再交付。希望帮到你。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑