☰
Linux解压安装Docker与Compose:离线部署与版本控制实战
2026/10/2 20:12:11 网站建设 项目流程

聊个技术选型的题。很多人在 Linux 上装 Docker,第一反应就是跑官方一键脚本,或者apt install docker.io、yum install docker-ce。但真正到了生产环境,尤其是离线内网、等保要求严的机房、或者需要精确控制 Docker 引擎版本的场景,这些方式往往会卡壳。我个人的选择是解压安装:下载官方静态二进制包,手动解压、放路径、注册 systemd 服务,Docker Compose 也一样处理。这套流程在 Linux 全系发行版通用,不依赖包管理器,也不会被系统仓库版本牵着鼻子走。

这篇文章就完整走一遍解压安装 Docker 与 Docker Compose 的实操流程,适合三类人:网络环境不自由,打算在内网离线部署的人;想精确控制 Docker 和 Compose 版本,不想被系统包管理干扰的人;还有刚入门但不想无脑复制粘贴脚本,想搞清楚每个文件装到哪、服务怎么拉起来的人。读完之后,你不仅能自己装上,还会知道为什么这样装、装坏了怎么排查。

1. 为什么选择解压安装:跳过包管理器直接吃二进制

1.1 一键脚本与系统仓库的隐藏成本

curl -fsSL https://get.docker.com | sh确实方便,但这个脚本会帮你改系统源、装一堆依赖、设置开机启动,整个过程对系统的侵入性很强。万一脚本执行到一半网络断了,或者源里缺了某个依赖,你得到的是一个半吊子环境,想清理干净还得自己手动查改了哪些文件。更麻烦的是,脚本安装的版本是它决定的,不是你的。同一套 Docker 引擎,在 Ubuntu 20.04 和 CentOS 7 上装出来的版本可能有差异,后续编排文件和镜像兼容性就会出问题。

系统仓库里的docker.io或docker包也好不到哪去。Debian 和 Ubuntu 官方源里的 Docker 版本经常落后好几个大版本,CentOS 源里的老版本更不用提,甚至会出现 containerd 和 runc 版本不匹配的坑。对于只是本地跑着玩的人来说无所谓,但如果要部署微服务、用 Docker Compose 编排 Nacos、MySQL 这类有版本要求的中间件,Docker 引擎版本太老会导致镜像内部依赖异常,问题非常隐蔽。

解压安装就不存在这些麻烦。官方静态二进制包把运行时依赖都打在包里,拷到目标机器上就能解压运行,不碰系统包管理器的源和依赖关系。版本由你自己决定,想用 24.0.7 就用 24.0.7,想升级到 27.x 就重新解压一份替换旧文件,整个过程可控、可回滚、可复制。

1.2 解压安装解决的典型场景

我在实际项目中用解压安装,主要解决三类问题。

第一类是离线内网部署。运维环境经常是物理隔离的,不能访问外网,包管理器源也往往是空的。靠yum或apt装 Docker 基本无解,即便配置了内网源,也可能版本不全。解压安装只需要把 Docker 的 tgz 文件和 Compose 二进制通过移动介质拷进去,配合内网镜像仓库,整套容器环境不需要外网就能跑起来。

第二类是版本一致性控制。我给多个机房的服务器部署同一个 Docker 版本,如果每台机器都用在线脚本安装,可能因为网络延迟和源状态不同,最后装出不同的版本。解压安装则可以把二进制包固化成固定版本,局域网内分发,每台机器解压后的文件内容一模一样。

第三类是特殊系统环境的适配。有些国产 Linux 系统、轻量路由系统或者自研操作系统,既没有 systemd,也没有可用的包管理器仓库,或者官方脚本不支持该系统。解压出来的二进制包放在任意目录下执行,不需要编译,不依赖发行版特定的包管理机制,兼容性好得多。

1.3 环境准备:动手前检查这几项

开始之前,先花两分钟确认基础环境,避免装到一半才发现平台不对。

先看 CPU 架构。几乎所有安装步骤里下载文件的路径都带架构标识,x86 服务器选 x86_64,ARM 服务器选 aarch64,查看方式很简单:

uname -m

然后在 /tmp 或者 /opt 下准备一个工作目录,预留 1GB 以上磁盘空间用于解压缓存,Docker 二进制本身只有几十到上百 MB,不要紧,但运行时的数据目录还是要预留充足。

再确认 Linux 系统有tar和wget或者curl,绝大多数发行版默认都有。如果连这些都没有,那就用apt install tar wget或yum install tar wget临时补一下,后续步骤就顺畅了。

最后,如果你的服务器上有旧版本的 Docker,保险起见先停掉旧的再继续。注意,卸载旧版本时/var/lib/docker目录里的数据卷和镜像会保留,如果不需要旧数据可以一起清掉,有业务数据就千万别乱删。

2. Docker 引擎二进制包下载与解压部署

2.1 获取官方静态二进制包

Docker 官方把所有平台的静态二进制包放在 download.docker.com 的 static 目录下,稳定版的路径格式一般是这样的:

https://download.docker.com/linux/static/stable/x86_64/docker-27.3.1.tgz

把路径里的x86_64换成aarch64就是 ARM 版本。版本号可以按需替换,我建议取一个常用的稳定大版本,比如 24.0.7 或者 27.x,不要一上来就追最新版,因为最新版对内核、iptables 和 cgroup 版本都有要求,老系统可能带不动。

下载的时候顺带把校验文件也下下来,避免传输过程文件损坏:

cd /tmp wget https://download.docker.com/linux/static/stable/x86_64/docker-27.3.1.tgz wget https://download.docker.com/linux/static/stable/x86_64/docker-27.3.1.tgz.sha256 sha256sum -c docker-27.3.1.tgz.sha256

sha256sum -c输出OK就说明文件完整,可以继续。这一步在离线环境尤其重要,移动存储介质拷贝过程中偶尔会出现文件损坏,校验不过的话解压出来出现各种诡异问题,排查时完全摸不着头脑。

2.2 解压文件并安装到系统路径

下载好的是压缩包,解压后是一个 docker 目录:

tar xzvf docker-27.3.1.tgz

解压出来的目录里包含docker、dockerd、containerd、containerd-shim-runc-v2、ctr、runc、docker-init、docker-proxy这些文件。注意,这里面的可执行文件是分散的,不像某些软件包那样有一个统一安装脚本。我们需要把这些二进制复制到/usr/local/bin下,因为这个目录默认在 PATH 环境变量里,而且比/usr/bin优先级更高,不会和系统自带的命令冲突。

sudo cp docker/* /usr/local/bin/ sudo chmod +x /usr/local/bin/docker /usr/local/bin/dockerd

做完之后可以快速验证一下:

docker version

这个命令此时会输出 Client 版本信息,但 Server 版本会显示ERROR: Cannot connect to the Docker daemon,这是正常的,因为我们还没启动服务。这个输出已经能证明二进制文件可以正常运行了。

有一些老手不喜欢把文件直接复制进系统目录,而是解压到一个固定目录如/opt/docker/,再通过软链接接入 PATH:

sudo mkdir -p /opt/docker sudo tar -xzf docker-27.3.1.tgz -C /opt/docker --strip-components=1 sudo ln -s /opt/docker/docker /usr/local/bin/docker sudo ln -s /opt/docker/dockerd /usr/local/bin/dockerd

这种方式的好处是升级和卸载更清晰,把/opt/docker目录删掉就能清理干净,软链接集中管理,不会散落到系统目录里。缺点是其他二进制比如containerd、runc也要同步做软链接,否则后续调用容易有问题。

2.3 校验二进制依赖完整

静态二进制包虽然不依赖系统安装包,但依赖一些系统级的共享库。用ldd检查一下 docker 和 dockerd 的依赖是否能找到:

ldd /usr/local/bin/dockerd

正常输出里会有libc.so.6、libpthread、libsystemd之类的库,如果出现not found,说明系统缺少基础运行库。一般的云服务器或物理机系统不会缺,但如果你在精简到极致的容器场景或嵌入式系统上做解压安装,就需要注意这个问题。

另外,如果你的系统用 SELinux 或者 AppArmor,可能会对二进制文件的执行有一些限制。临时关闭 SELinux 测试:

setenforce 0 docker version

如果能正常输出 Client 信息,说明是 SELinux 策略拦截,后续再针对策略做调整,而不是安装没成功。

3. 创建 systemd 服务:让 Docker 引擎跑起来

3.1 编写 docker.service 与 docker.socket

二进制放好了,但 Docker 引擎需要以后台守护进程方式运行,并随开机自启,所以我们必须给它注册 systemd 服务。解压包里并不会自带服务文件,网上常见做法是直接下载在线安装脚本生成的 service,但我们手动创建完全不难。

先创建 docker 用户组,方便后续非 root 用户使用 docker 命令:

sudo groupadd docker

接着创建 socket 单元文件/etc/systemd/system/docker.socket。很多教程会忽略这一步,直接写 service,但实际上 Docker 的默认启动方式是先建 socket 再监听,如果你只写 service,启动时也可能正常工作,但架构上不完整。

[Unit] Description=Docker Socket for the API PartOf=docker.service [Socket] ListenStream=/var/run/docker.sock SocketMode=0660 SocketUser=root SocketGroup=docker [Install] WantedBy=sockets.target

然后创建主服务文件/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=docker.socket [Service] Type=notify ExecStart=/usr/local/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock ExecReload=/bin/kill -s HUP $MAINPID TimeoutSec=0 RestartSec=2 Restart=always LimitNOFILE=infinity LimitNPROC=infinity LimitCORE=infinity TasksMax=infinity Delegate=yes KillMode=process [Install] WantedBy=multi-user.target

几个关键配置值得解释一下。Type=notify表示 dockerd 启动完成后会通过通知机制告知 systemd,而不是简单地按进程存活判断。ExecStart里有-H fd://,意思是让 dockerd 通过 socket 激活方式接收来自 systemd 的文件描述符,而不是直接自己监听/var/run/docker.sock。Delegate=yes允许 Docker 管理自己的 cgroup 系统,这是容器资源隔离的基础,别随手删掉。Restart=always表示如果守护进程崩溃,systemd 自动拉起,生产环境强烈建议保留。

还有个容易忽略的点:containerd.sock的路径。新版 Docker 依赖 containerd,这个 socket 文件由解压包里的 containerd 创建。后面启动如果报错找不到 containerd.sock,多半是 containerd 没起来或者路径不对。

3.2 启动 Docker 并做最小化验证

单元文件写好后,先重新加载 systemd 配置,再设置开机自启并启动:

sudo systemctl daemon-reload sudo systemctl enable --now docker sudo systemctl status docker

status输出出现active (running)之后,先别急着拉镜像,先验证引擎能否响应 API:

docker info

这条命令输出里能看到 Kernel Version、Operating System、Docker Root Dir、Server Version 这些关键信息。如果报Cannot connect to the Docker daemon,大概率是服务和 socket 没有同时启动,可以强制重启:

sudo systemctl stop docker sudo systemctl start docker.socket sudo systemctl start docker

能跑通docker info就说明引擎已经正常工作了,此时拉一个 hello-world 做进一步验证。如果网络受限拉不动镜像,直接用docker info作为验收依据也是够的,引擎是否可用并不依赖外部镜像。

3.3 调整 daemon.json:目录、日志与网络

刚装好的 Docker 默认数据根目录是/var/lib/docker,日志驱动是 json-file,iptables 默认打开。这些都可以在/etc/docker/daemon.json里覆盖。我一般新建一个基础配置:

{ "data-root": "/data/docker", "log-driver": "json-file", "log-opts": { "max-size": "50m", "max-file": "5" }, "storage-driver": "overlay2", "registry-mirrors": [ "https://加速服务地址" ] }

>sudo systemctl daemon-reload sudo systemctl restart docker docker info | grep "Docker Root Dir"

注意,修改>https://github.com/docker/compose/releases/download/v2.24.7/docker-compose-linux-x86_64

如果系统是 ARM 架构,把文件名末尾换成aarch64:

wget https://github.com/docker/compose/releases/download/v2.24.7/docker-compose-linux-aarch64 -O /tmp/docker-compose

GitHub 在大陆环境可能下载慢,这是比较正常的情况。没有外网条件的离线服务器,可以让能联网的机器下载后,再拷贝过去。文件不大,一般不到一百 MB。

下载完成后,记得加执行权限:

sudo chmod +x /tmp/docker-compose

在拷贝到最终目录前,可以先执行一次验证文件是否完整:

/tmp/docker-compose version

能输出Docker Compose version v2.24.7就说明文件没损坏。

4.2 插件模式与传统 docker-compose 模式

安装 Compose 有两条路径:插件模式,即把它作为 Docker CLI 的子命令docker compose;传统模式,即把它作为独立命令docker-compose。现在官方推荐插件模式,新版 docker compose 的环境信息、docker compose语法和 docker 命令集成得更紧密。

插件模式的文件必须放在 Docker CLI 插件目录。用户级目录是~/.docker/cli-plugins/,系统级目录是/usr/local/lib/docker/cli-plugins/。为了让所有用户都能用,放在系统目录:

sudo mkdir -p /usr/local/lib/docker/cli-plugins sudo mv /tmp/docker-compose /usr/local/lib/docker/cli-plugins/docker-compose sudo chmod +x /usr/local/lib/docker/cli-plugins/docker-compose

放好后验证:

docker compose version

输出Docker Compose version v2.24.7就成功了。

传统模式则简单很多,直接把二进制放到/usr/local/bin/docker-compose:

sudo mv /tmp/docker-compose /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose docker-compose version

两种方式可以同时存在,并不冲突。我建议以插件模式为主,如果你还有老项目里的 shell 脚本调用的是docker-compose -f ... up -d,那就在保留插件模式的同时再加一个传统模式的软链接,两者兼容老脚本和新命令,最稳妥。

4.3 解决 docker compose 找不到命令的问题

经常有人在群里问:明明安装了 compose,运行docker compose version却提示docker: unknown command: "compose"。这个错误的根源只有一个:Docker CLI 在指定插件目录里找不到名为docker-compose的可执行文件。

排查思路很简单。第一步,确认文件确实在插件目录里:

ls -l /usr/local/lib/docker/cli-plugins/docker-compose

第二步,确认文件有可执行权限,没有 x 权限 Docker 不会加载它:

chmod +x /usr/local/lib/docker/cli-plugins/docker-compose

第三步,确认这个可执行文件是正常的、没有损坏。有时候从 Windows 拷贝过来的文件可能是带特殊属性的文本文件,不是 Linux 可执行格式,直接file /usr/local/lib/docker/cli-plugins/docker-compose可以看文件类型。

第四步,检查 PATH 环境变量是否包含了/usr/local/lib/docker/cli-plugins。Docker 默认会扫描这个目录,但如果你手动改过环境,也可能漏掉。

如果还是不行,就退一步用传统模式把二进制放到/usr/local/bin/docker-compose,至少能保证老项目的docker-compose up不受影响。插件模式的问题后续再逐个环节排查。

5. 离线环境与常见问题排查实录

5.1 离线内网环境下怎么把整套环境带进去

解压安装最大的价值就是离线部署。顺一遍完整流程:在有网机器上下载 docker tgz 和 compose 二进制,连同要用到的镜像 tar 文件一起打包:

docker save nginx:alpine mysql:8.0 -o images.tar

然后把这些文件拷贝到离线服务器。Docker 引擎本身不需要额外依赖包,按之前的流程解压安装就行;镜像则用 load 导入:

sudo tar -xzf docker-27.3.1.tgz sudo cp docker/* /usr/local/bin/ sudo groupadd docker # 创建 systemd 文件并启动 sudo systemctl enable --now docker docker load -i images.tar docker images

如果你的团队有内网镜像仓库,那更简单,把daemon.json里的registry-mirrors换成内网仓库地址,或者直接docker pull 内网仓库地址/nginx:alpine,镜像拉取速度非常快。

离线安装时最需要关心的是内核版本和依赖库。如果你的服务器内核太老,overlay2存储驱动起不来,可以把daemon.json改成"storage-driver": "vfs"先应急,等换成新内核后再调回 overlay2。这点在二手设备、老旧国产系统上经常遇到。

5.2 常见错误速查表

实际操作中我踩过的坑整理成表,按出现频率从高到低排列:

错误现象根本原因解决办法
docker: unknown command: "compose"Compose 插件未安装或不在插件目录检查cli-plugins目录和可执行权限,或改用docker-compose独立命令
Cannot connect to the Docker daemon at unix:///var/run/docker.sockdockerd未启动或socket文件未生成systemctl status docker,看日志;手动启动containerd和docker
Got permission denied while trying to connect to the Docker daemon非root用户不在docker组sudo usermod -aG docker 用户名,重新登录
iptables: No chain/target/match by that nameDocker创建iptables链失败,或内核模块未加载重启系统或加载br_netfilter模块,必要时daemon.json设"iptables": false
Error starting daemon: error initializing graphdriver: operation not supported内核不支持overlay2改存储驱动为vfs,或升级内核
listen tcp :53: bind: address already in use端口被占用停止占用进程或调整Docker代理监听端口
docker: Error response from daemon: pull access denied镜像不存在或没有权限检查镜像名拼写、是否登录私有仓库、是否配置registry-mirrors
Failed to connect to containerd: dial unix /run/containerd/containerd.sockcontainerd未启动手动启动containerd,或者在daemon.json里指定containerd路径

有些问题看起来像是配置问题,其实根子在系统内核版本。比如 iptables 规则异常,多半是因为内核没有加载br_netfilter模块,先执行:

modprobe br_netfilter

然后写入/etc/modules-load.d/br_netfilter.conf保证开机自动加载。这个坑在 CentOS 7 的 3.10 内核上特别常见,不做这一步容器网络经常不通。

5.3 升级、卸载与回滚的思路

解压安装的另一个好处是升级和回滚就像换文件一样简单。升级 Docker 引擎,停服、替换二进制、重启服务三步走:

sudo systemctl stop docker sudo tar -xzf docker-27.3.2.tgz sudo cp docker/* /usr/local/bin/ sudo systemctl start docker docker version

这套流程不会动/var/lib/docker下的数据,镜像和容器卷都还在。但升级前最好还是备份一下重要目录:

sudo cp -a /var/lib/docker /var/lib/docker.bak.$(date +%Y%m%d)

回滚也同样是替换二进制,把旧版本的文件重新放回去,重启服务即可。注意,如果升级后新版本自动迁移了数据目录的元数据结构,比如从 overlay2 的旧格式迁移到新格式,这时候用旧二进制回滚可能会识别不了新数据,所以升级前备份数据比备份二进制更重要。

卸载则是另一回事。如果确定哪天不用 Docker 了,先把服务停掉,再删除 systemd 单元文件和二进制目录:

sudo systemctl stop docker docker.socket sudo systemctl disable docker docker.socket sudo rm -f /usr/local/bin/docker /usr/local/bin/dockerd /usr/local/bin/containerd* /usr/local/bin/runc /usr/local/bin/docker-proxy /usr/local/bin/docker-init sudo rm -rf /etc/systemd/system/docker.service /etc/systemd/system/docker.socket /etc/docker sudo systemctl daemon-reload

但是/var/lib/docker里如果有数据库容器的数据卷,删除前务重复确认,建议先整体转移到备份目录,避免误删。我用这套方式维护好几台离线服务器,最大的感触就是一切都在明面上,哪个文件在哪个位置、版本是多少、怎么换,心里清清楚楚,不像在线脚本装完还得猜它改了什么。最后再分享一个小技巧:整套安装过程整理成一个 shell 脚本,把下载、解压、写 systemd 文件、配置 daemon.json 都写成可重复执行的形式,以后每来一台新机器,拿着脚本跑一遍就结束了。这样才叫真正的通用安装。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询