Linux 离线安装 Docker 25.0.4 详细教程:静态二进制与 RPM/DEB 离线包全方案
内网机房、等保环境、涉密网络、没有外网的服务器——这些场景下 Docker 没法用 yum install / apt install 在线装,只能先在联网机器上把安装包下载好,再传到目标机上离线安装。本文以 Docker 25.0.4 为例,把静态二进制、RPM、DEB 三种离线安装方法从头到尾讲清楚,包含 systemd 服务配置、daemon.json、离线镜像导入和常见报错排查,照着做就能装起来。
1. 版本与环境要求
Docker 25.0.4 是 25.0.x 系列的一个补丁版本(2024 年 3 月发布),修复了 25.0.3 之前版本的一些问题,核心组件版本与 25.0.0 保持一致,适合作为内网环境的固定版本长期使用。先确认目标机满足以下条件:
| 项目 | 要求 |
|---|---|
| CPU 架构 | 64 位 x86_64 或 aarch64(本文以 x86_64 为主,aarch64 步骤相同,只换包) |
| 内核版本 | 3.10 以上;overlay2 存储驱动建议 4.0 以上内核 |
| 操作系统 | RHEL / CentOS / Rocky / Ubuntu / Debian 等主流发行版均可(静态二进制方式不挑发行版) |
| 磁盘空间 | /var/lib/docker 所在分区建议预留 20GB 以上(镜像和容器都存在这里) |
| 权限 | root 用户操作 |
| 依赖 | iptables(二进制方式需手动确认)、systemd(用 systemctl 管理服务) |
# 先在目标机上确认内核和架构
uname -m
uname -r
cat /etc/os-release
df -h /var/lib/docker 2>/dev/null || df -h /
2. 三种离线安装方案对比
| 方案 | 适用系统 | 优点 | 缺点 |
|---|---|---|---|
| 静态二进制包 | 所有 Linux 发行版 | 一个 tgz 搞定,不挑发行版和版本,最通用 | 需手动写 systemd 服务文件;不装 compose/buildx 插件;依赖(iptables)要自己确认 |
| RPM 离线包 | RHEL / CentOS / Rocky / openEuler | yum/dnf 管理,服务文件自带,含 compose、buildx 插件 | 要提前把依赖包也下载全;不同大版本(7/8/9)包不通用 |
| DEB 离线包 | Ubuntu / Debian | dpkg 管理,服务文件自带,含 compose、buildx 插件 | 要提前把依赖包也下载全;版本号里带发行版代号,下载时别拿错 |
不知道选哪个就选静态二进制,一个包、一个方法,什么发行版都能用。下面三种方法都会讲,任选其一即可,不要三种都装。
3. 准备工作:在联网机上下载离线包
找一台能联网的机器(自己的电脑、跳板机都行),下载对应架构的静态二进制包:
# x86_64(绝大多数服务器)
curl -O https://download.docker.com/linux/static/stable/x86_64/docker-25.0.4.tgz
# aarch64(ARM 服务器,如鲲鹏、飞腾、树莓派 4)
curl -O https://download.docker.com/linux/static/stable/aarch64/docker-25.0.4.tgz
# 校验完整性(本文实测值)
sha256sum docker-25.0.4.tgz
# 正确输出:23db817b99aac6d5d7fcb1f706e50b5a412d78a9438975d6b4a54c58dc409bfb
包不大,实测 71,586,529 字节(约 68.3 MiB)。解开后是 8 个文件,作用如下:
| 文件 | 大小 | 作用 |
|---|---|---|
| dockerd | 67.8 MB | Docker 守护进程本体 |
| docker | 35.7 MB | docker 命令行客户端 |
| containerd | 39.1 MB | 容器运行时(真正管容器生命周期) |
| containerd-shim-runc-v2 | 12.4 MB | containerd 与 runc 之间的垫片 |
| runc | 15.3 MB | 按 OCI 规范创建容器的底层工具 |
| ctr | 19.2 MB | containerd 的调试命令行 |
| docker-proxy | 2.0 MB | 容器端口映射的代理进程 |
| docker-init | 0.7 MB | 容器的 init 进程(tini,回收僵尸进程) |
下载完把包传到目标机上,scp、U盘、内网文件服务器都行:
scp docker-25.0.4.tgz root@目标机IP:/root/
# 如果目标机只能通过跳板机访问,加 -J 跳板机
scp -J 跳板机用户@跳板机IP docker-25.0.4.tgz root@目标机IP:/root/
4. 方法一:静态二进制安装(推荐)
4.1 解压并复制二进制文件
cd /root
tar -xzvf docker-25.0.4.tgz
cp docker/* /usr/bin/
chmod +x /usr/bin/docker*
docker --version
dockerd --version
# 输出应为:Docker version 25.0.4, build 1a74b9f
# Docker version 25.0.4, build f9aab9f
4.2 创建 docker 用户组
docker 组的作用是让普通用户不用 sudo 就能用 docker 命令(只有组内用户能访问 /run/docker.sock):
groupadd docker
# 把需要用 docker 的普通用户加进组(root 不需要)
usermod -aG docker yourname
# 注意:已登录的用户要重新登录或执行 newgrp docker,组身份才生效
4.3 编写 systemd 服务文件
静态二进制包不带 systemd 文件,这是它和 RPM/DEB 安装最大的区别,需要手动写三个文件。先写 containerd 的:
cat > /etc/systemd/system/containerd.service <<'EOF'
[Unit]
Description=containerd container runtime
Documentation=https://containerd.io
After=network.target local-fs.target
[Service]
ExecStartPre=-/sbin/modprobe overlay
ExecStart=/usr/bin/containerd
Type=notify
Delegate=yes
KillMode=process
Restart=always
RestartSec=5
LimitNPROC=infinity
LimitCORE=infinity
LimitNOFILE=infinity
TasksMax=infinity
OOMScoreAdjust=-999
[Install]
WantedBy=multi-user.target
EOF
再写 docker 的 socket 文件(dockerd 通过这个 socket 接受 API 请求):
cat > /etc/systemd/system/docker.socket <<'EOF'
[Unit]
Description=Docker Socket for the API
[Socket]
ListenStream=/run/docker.sock
SocketMode=0660
SocketUser=root
SocketGroup=docker
[Install]
WantedBy=sockets.target
EOF
最后写 docker 服务文件:
cat > /etc/systemd/system/docker.service <<'EOF'
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target docker.socket firewalld.service containerd.service time-set.target
Wants=network-online.target containerd.service
Requires=docker.socket
[Service]
Type=notify
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutStartSec=0
RestartSec=2
Restart=always
StartLimitBurst=3
StartLimitInterval=60s
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
Delegate=yes
KillMode=process
OOMScoreAdjust=-500
[Install]
WantedBy=multi-user.target
EOF
# 关键点:-H fd:// 表示 dockerd 从 systemd 传过来的 socket 启动,
# 必须和上面 docker.socket 里的 ListenStream 保持一致
4.4 写 daemon.json 配置文件
/etc/docker/daemon.json 是 dockerd 的主配置文件。离线环境最常用的是改数据目录和日志策略;镜像加速地址在纯离线环境用不上,如果内网有 Harbor 或代理仓库再配 registry-mirrors:
mkdir -p /etc/docker
cat > /etc/docker/daemon.json <<'EOF'
{
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "3"
},
"storage-driver": "overlay2",
"exec-opts": ["native.cgroupdriver=systemd"]
}
EOF
# 检查 JSON 格式有没有写错(写错会导致 dockerd 起不来)
python3 -m json.tool /etc/docker/daemon.json > /dev/null && echo "JSON OK"
如果你的数据盘不在根分区,建议把数据目录也改过去,避免根分区被镜像塞满:
# 在 daemon.json 里加一行(注意上一行末尾加逗号)
# "data-root": "/data/docker"
mkdir -p /data/docker
4.5 启动服务并设置开机自启
systemctl daemon-reload
systemctl enable --now containerd
systemctl enable --now docker
systemctl status docker --no-pager
systemctl status containerd --no-pager
4.6 验证安装
docker version
# Client 和 Server 都显示 25.0.4 才算成功
# Client: Version 25.0.4 / Server: Version 25.0.4
docker info | grep -E 'Server Version|Storage Driver|Cgroup Driver|Cgroup Version|Operating System'
# Server Version: 25.0.4
# Storage Driver: overlay2
# Cgroup Driver: systemd
# Cgroup Version: 2
到这里 Docker 本体已经装好了。注意:docker run hello-world 这一步在离线机上会失败,因为它要联网拉镜像——验证容器能不能跑要用第 8 节的离线导入方法。
5. 方法二:RPM 离线安装(RHEL / CentOS / Rocky)
如果目标机是 RHEL 系,用 RPM 包安装更省事:服务文件、docker 组、依赖关系都由包管理器处理。关键是在联网机上把依赖一起下载全,否则目标机上装到一半会报缺包。
5.1 在联网机上下载 RPM 包
找一台和目标机同发行版、同大版本的联网机(比如目标机是 Rocky 9,就用 Rocky 9 的联网机),先配好 Docker 官方 yum 源,再用 dnf download --resolve 把包和依赖一次性下全:
# 1. 配 Docker 官方源(RHEL 9 / Rocky 9 / AlmaLinux 9 示例,8 换成 8,7 换成 7)
dnf install -y yum-utils
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# 2. 下载指定版本及全部依赖到 ./docker-rpms 目录
mkdir -p ~/docker-rpms && cd ~/docker-rpms
dnf download --resolve --destdir=. \
docker-ce-25.0.4 \
docker-ce-cli-25.0.4 \
containerd.io \
docker-buildx-plugin \
docker-compose-plugin
# 3. 确认下载结果(正常应有 10 个左右的 rpm,含 iptables、libseccomp 等依赖)
ls -la
# docker-ce-25.0.4-1.el9.x86_64.rpm
# docker-ce-cli-25.0.4-1.el9.x86_64.rpm
# containerd.io-1.7.*.el9.x86_64.rpm
# docker-buildx-plugin-*.el9.x86_64.rpm
# docker-compose-plugin-*.el9.x86_64.rpm
# iptables-*.rpm、libseccomp-*.rpm ……(依赖)
CentOS 7 / RHEL 7 的联网机没有 dnf download,改用 yumdownloader:
# CentOS 7 / RHEL 7
yum install -y yum-utils
yumdownloader --resolve --destdir=./docker-rpms \
docker-ce-25.0.4 docker-ce-cli-25.0.4 containerd.io \
docker-buildx-plugin docker-compose-plugin
5.2 传到目标机并安装
# 传包
scp -r ~/docker-rpms root@目标机IP:/root/
# 目标机上安装(dnf 会自动处理本地包之间的依赖关系)
cd /root/docker-rpms
dnf install -y ./*.rpm
# RHEL 7 / CentOS 7 用:yum localinstall -y ./*.rpm
# 启动并验证
systemctl enable --now docker
docker version
注意两点:一是 docker-ce 要求 containerd.io 不低于 1.6.24,--resolve 会自动拉取满足要求的版本,不用手工挑;二是 RHEL 7/8/9 的包不能混用,el7 的包只能装在 7 上,el9 的包只能装在 9 上。
6. 方法三:DEB 离线安装(Ubuntu / Debian)
6.1 在联网机上下载 DEB 包
DEB 包的版本号里带发行版代号,下载前先确认目标机的版本。Ubuntu 22.04(jammy)、Ubuntu 20.04(focal)、Debian 12(bookworm)的版本号各不相同:
# Ubuntu 22.04(jammy)示例
mkdir -p ~/docker-debs && cd ~/docker-debs
apt-get update
apt-get download \
docker-ce=5:25.0.4-1~ubuntu.22.04~jammy \
docker-ce-cli=5:25.0.4-1~ubuntu.22.04~jammy \
containerd.io docker-buildx-plugin docker-compose-plugin
# Ubuntu 20.04 把 jammy 换成 focal;Debian 12 换成 5:25.0.4-1~debian.12~bookworm
# 版本号里的 5: 是 epoch,照抄不要漏
# 依赖包一起下载(iptables、libseccomp2 等)
apt-get download $(apt-cache depends --recurse --no-recommends --no-suggests \
--no-conflicts --no-breaks --no-replaces --no-enhances \
docker-ce=5:25.0.4-1~ubuntu.22.04~jammy | grep "^\w" | sort -u)
更省事的办法是在联网机上用 --download-only 让 apt 自己算依赖:
# 先在联网机上配好 Docker 官方 apt 源,再只下载不安装
apt-get install -y --download-only \
docker-ce=5:25.0.4-1~ubuntu.22.04~jammy \
docker-ce-cli=5:25.0.4-1~ubuntu.22.04~jammy \
containerd.io docker-buildx-plugin docker-compose-plugin
# 下载的 deb 在 /var/cache/apt/archives/,全部拷走
cp /var/cache/apt/archives/*.deb ~/docker-debs/
6.2 传到目标机并安装
scp -r ~/docker-debs root@目标机IP:/root/
cd /root/docker-debs
dpkg -i *.deb
# 如果报依赖问题,用 apt-get install -f 修复——但离线环境下这一步可能拉不到包,
# 所以第 6.1 节的依赖一定要下全
systemctl enable --now docker
docker version
7. daemon.json 常用配置详解
装完先别急着跑容器,把 daemon.json 按实际环境调好。离线环境最常用的几项:
| 配置项 | 作用 | 离线环境建议 |
|---|---|---|
| data-root | 镜像、容器、卷的存放目录,默认 /var/lib/docker | 根分区空间紧张时改到数据盘,如 /data/docker |
| storage-driver | 存储驱动 | overlay2,绝大多数场景的首选 |
| log-driver / log-opts | 容器日志驱动和轮转策略 | json-file + max-size 100m + max-file 3,防止日志撑爆磁盘 |
| exec-opts | 运行时参数 | native.cgroupdriver=systemd,和 systemd 的 cgroup 驱动保持一致 |
| registry-mirrors | 镜像加速地址 | 纯离线不用配;内网有 Harbor 时配内网地址 |
| insecure-registries | 允许 HTTP 方式访问的私有仓库 | 内网 Harbor 没配 HTTPS 时加,如 "192.168.1.100:8080" |
| live-restore | dockerd 重启时容器保持运行 | true,生产环境建议开,避免 dockerd 升级重启导致业务中断 |
| default-address-pools | 容器网段池 | 和内网网段冲突时改,如 10.200.0.0/16,避免 docker 默认 172.17.0.0/16 和业务网段撞车 |
cat > /etc/docker/daemon.json <<'EOF'
{
"data-root": "/data/docker",
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "3"
},
"storage-driver": "overlay2",
"exec-opts": ["native.cgroupdriver=systemd"],
"live-restore": true
}
EOF
# 改完配置要重启 dockerd 才生效(live-restore 开了之后重启不影响运行中的容器)
systemctl restart docker
docker info | grep -E 'Docker Root Dir|Logging Driver|Cgroup Driver'
8. 离线镜像管理:save / load 与内网仓库
Docker 装好了,但离线机拉不到镜像。标准做法是在联网机上 pull 好再 docker save 打包,传到目标机 docker load 导入:
# === 联网机上操作 ===
docker pull hello-world:latest
docker pull nginx:1.25.4
# 打包成 tar(多个镜像可以打进同一个文件)
docker save -o images.tar hello-world:latest nginx:1.25.4
ls -lh images.tar
# === 目标机上操作 ===
scp images.tar root@目标机IP:/root/
docker load -i images.tar
# 输出:Loaded image: hello-world:latest / Loaded image: nginx:1.25.4
docker images
# 验证容器能正常跑起来
docker run --rm hello-world
# Hello from Docker!(看到这句就说明容器运行时完全正常)
docker run -d --name test-nginx -p 8080:80 nginx:1.25.4
curl http://localhost:8080
docker rm -f test-nginx
镜像一多,每次 scp 传 tar 就很麻烦。长期方案是在内网搭一个私有仓库,一次导入、内网所有机器共享:
- Harbor:功能最全(Web 界面、权限、镜像复制、漏洞扫描),适合团队和生产环境,离线安装包从 GitHub Releases 下载
- Docker Registry:官方轻量仓库,一个容器就跑起来,适合只有几台机器的小环境
- registry 容器本身也是镜像:先在联网机上
docker save registry:2,传到内网机 load 再跑起来,仓库就有了
9. 安装验证清单
按顺序跑完下面这组命令,全部通过才算安装完成:
# 1. 版本
docker version
# 2. 服务状态
systemctl is-active docker containerd # 都应输出 active
systemctl is-enabled docker containerd # 都应输出 enabled
# 3. 运行时信息
docker info | grep -E 'Server Version|Storage Driver|Cgroup Driver|Cgroup Version|Docker Root Dir'
# 4. 容器实跑
docker run --rm hello-world
# 5. 网络
docker run --rm --name net-test -p 18080:80 -d nginx:1.25.4 && curl -s -o /dev/null -w "%{http_code}\n" http://localhost:18080
docker rm -f net-test
10. 常见问题排查
10.1 Cannot connect to the Docker daemon
最常见的报错,意思是客户端连不上 dockerd。先看服务在不在:
systemctl status docker --no-pager
# 如果是 inactive:systemctl start docker
# 如果是 failed:看日志找原因
journalctl -u docker -xe --no-pager | tail -50
10.2 dockerd 启动失败:failed to start daemon
先看日志最后一屏,90% 的问题出在下面三处:
# daemon.json 写错了(少逗号、多逗号、中文引号)——JSON 校验
python3 -m json.tool /etc/docker/daemon.json
# data-root 目录不存在或没权限
ls -ld /data/docker # 不存在就 mkdir -p /data/docker
# 端口或 socket 被占
ss -tlnp | grep -E '2375|2376'
ls -l /run/docker.sock # 有残留的旧 socket 就删掉再启动
10.3 静态安装缺 iptables:Failed to initialize network controller
静态二进制包不装依赖,目标机如果没有 iptables,dockerd 启动时会报网络控制器初始化失败。RHEL 8/9 装 iptables-nft,RHEL 7 装 iptables,Debian/Ubuntu 装 iptables:
# RHEL 8/9 / Rocky 9(联网机上 dnf download iptables-nft 一起带过来)
dnf install -y iptables-nft
# RHEL 7 / CentOS 7
yum install -y iptables
# Ubuntu / Debian
apt-get install -y iptables
# 装完重启 docker
systemctl restart docker
10.4 overlay2 初始化失败:error initializing graphdriver
# 内核没加载 overlay 模块
modprobe overlay
lsmod | grep overlay
# 让它开机自动加载
echo overlay > /etc/modules-load.d/overlay.conf
# 如果文件系统是 xfs 且没开 d_type,也会报这个错,检查:
xfs_info /var/lib/docker 2>/dev/null | grep ftype # ftype=1 才正常
# ftype=0 的老 xfs 分区不支持 overlay2,只能换分区或改用 devicemapper(不推荐)
10.5 SELinux 拒绝访问(RHEL 系常见)
# 先确认是不是 SELinux 的问题:临时关掉再启动 docker
setenforce 0
systemctl restart docker
docker run --rm hello-world # 能跑就是 SELinux 挡的
# 确认后恢复 enforcing,再给数据目录打标签(不要长期关 SELinux)
setenforce 1
semanage fcontext -a -t container_file_t "/data/docker(/.*)?"
restorecon -Rv /data/docker
# 没有 semanage 命令:dnf install -y policycoreutils-python-utils
10.6 cgroup driver 不一致
dockerd 默认用 cgroupfs,而 systemd 管理的系统(RHEL 8/9、Ubuntu 22.04)建议用 systemd,否则后续接 Kubernetes 会报驱动不一致。daemon.json 里加一行即可:
# daemon.json 中加入
# "exec-opts": ["native.cgroupdriver=systemd"]
systemctl restart docker
docker info | grep 'Cgroup Driver' # 应显示 systemd
10.7 普通用户报 permission denied
# 用户不在 docker 组,或加组后没重新登录
id yourname # 看输出里有没有 docker 组
newgrp docker # 当前会话立即生效(或重新登录)
# 检查 socket 权限
ls -l /run/docker.sock # 应为 srw-rw---- root docker
10.8 firewalld 和 Docker 的 iptables 规则打架
RHEL 系开了 firewalld 后,Docker 写入的 iptables 规则可能被 firewalld reload 冲掉,导致容器网络时好时坏。两个办法:要么关 firewalld(内网机房常见做法),要么在 firewalld 里放行 docker0 网桥:
# 方案 A:停用 firewalld(内网有硬件防火墙时常用)
systemctl stop firewalld
systemctl disable firewalld
systemctl restart docker
# 方案 B:保留 firewalld,放行 docker 网段
firewall-cmd --permanent --zone=trusted --add-interface=docker0
firewall-cmd --permanent --zone=trusted --add-source=172.17.0.0/16
firewall-cmd --reload
systemctl restart docker
10.9 203/EXEC:systemd 执行不了二进制
如果 docker 和 containerd 两个服务同时报 status=203/EXEC,问题不在 service 文件,而在 /usr/bin 下的二进制本身——systemd 执行不了它们。常见三种原因:
# 定位原因
ls -la /usr/bin/docker* /usr/bin/containerd* /usr/bin/runc /usr/bin/ctr
file /usr/bin/dockerd /usr/bin/containerd
uname -m
- /usr/bin 下根本没这些文件:4.1 那步的
cp docker/* /usr/bin/没真正执行成功(常见原因是解压目录不对)。回到解压出docker/目录的地方,重跑cp docker/* /usr/bin/。 - file 显示 ARM aarch64,但 uname -m 是 x86_64:下错架构的包了,重新下载 x86_64 的 tgz。
- 文件在但没有执行权限:补权限
chmod +x /usr/bin/docker* /usr/bin/containerd* /usr/bin/runc /usr/bin/ctr。
修好后不用改 service 文件,直接重启服务即可。注意服务此时处在 auto-restart 循环里,二进制修好后自己会起来:
systemctl restart containerd docker
systemctl status docker --no-pager
11. 卸载步骤
# RPM / DEB 安装的卸载
dnf remove -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# 或:apt-get purge -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# 静态二进制安装的卸载
systemctl stop docker containerd
systemctl disable docker containerd
rm -f /etc/systemd/system/docker.service /etc/systemd/system/docker.socket /etc/systemd/system/containerd.service
rm -f /usr/bin/docker /usr/bin/dockerd /usr/bin/containerd* /usr/bin/runc /usr/bin/ctr /usr/bin/docker-*
systemctl daemon-reload
# 通用清理(数据全删,操作前确认镜像和容器都不需要了)
rm -rf /var/lib/docker /var/lib/containerd /etc/docker
groupdel docker
12. 附录:文件清单与命令速查
| 文件 / 目录 | 作用 |
|---|---|
| /usr/bin/dockerd、/usr/bin/docker | 守护进程与客户端 |
| /etc/systemd/system/docker.service | docker 的 systemd 服务(静态安装需手写) |
| /etc/systemd/system/docker.socket | docker API socket 定义 |
| /etc/systemd/system/containerd.service | containerd 的 systemd 服务 |
| /etc/docker/daemon.json | dockerd 主配置文件 |
| /var/lib/docker(或 data-root 指定目录) | 镜像、容器、卷的数据目录 |
| /run/docker.sock | docker API 的 Unix socket |
| /run/containerd/containerd.sock | containerd 的 socket |
# 服务管理
systemctl start|stop|restart|status docker
systemctl enable|disable docker
journalctl -u docker -f # 实时看日志
journalctl -u docker --since "1 hour ago" --no-pager
# 镜像管理(离线)
docker save -o images.tar 镜像:标签 # 导出
docker load -i images.tar # 导入
docker images # 查看
docker rmi 镜像:标签 # 删除
# 容器管理
docker ps -a
docker logs -f 容器名
docker exec -it 容器名 /bin/bash
docker inspect 容器名
三种方法任选其一,静态二进制最通用,RPM/DEB 最省事。装完记得用 docker run --rm hello-world 做一次端到端验证——只看 docker version 是不够的,容器真正跑起来才算装好。如果内网机器多,建议把验证过的离线包和镜像 tar 归档到内网文件服务器,再搭一个 Harbor 做私有仓库,后面就不用一台台传包了。






