ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Docker解压安装实操:静态二进制包离线部署与Compose配置指南

Docker解压安装实操:静态二进制包离线部署与Compose配置指南 1. 解压安装的思路拆解为什么要把 Docker 弄成“绿色免安装版”1.1 包管理器装 Docker 的三个尴尬时刻我第一次被“解压安装 Docker”这个方案救场是在一台不能随便动软件源的离线服务器上。那台机器跑的还是老系统内网环境里既没有 docker-ce 的 rpm 包也没有外网apt/yum 源里唯一能装的是古董级的 docker.io。如果你忍痛装上再用大概率会被 Docker 版本太老、命令残缺、compose 不可用、bug 一堆这四连击折磨到怀疑人生。包管理器安装的痛其实远不止版本老。先说 yum install docker 这一系默认源里的 docker 主程序往往停留在 Docker 1.13 时代那时候连 docker compose 子命令都没有容器管理也是老一套 API。再说 apt install docker.io版本稍微新一点但同样远远落后于官方 release你想用上 containerd snapshotter 这类新特性想都别想。更麻烦的是你往生产环境上一跑想升级还得看发行版维护者的脸色他什么时候给源里更新你什么时候才能升级和官方发布节奏完全脱节。还有个非常现实的场景发行版源里压根没有 Docker 包。国产的麒麟、统信、欧拉这类系统虽然底子多半是 CentOS 或 Debian 系但源里不一定有 docker-ce 仓库。你按网上教程去 add repo经常碰上证书问题、签名问题、依赖链缺包。折腾半天最后发现官方明明提供了静态二进制包解压就能跑根本不用伺候包管理器。当年我在麒麟 v10 x86_64 上装 Docker 26 和 Compose最终就是靠解压 tar 包一把过的那一刻我真心觉得这条路才是 Linux 上装 Docker 最通用的姿势。1.2 “解压安装”的本质是什么很多人对“解压安装”有误解以为这是某种 hack 或者不稳定的野路子。其实正好相反这才是 Docker 官方一直在维护的发行方式之一。Docker 官网的静态二进制下载页面就是为这种安装场景准备的。官方把 dockerd、containerd、runc、docker CLI、docker-proxy、docker-init 等所有组件打进一个 tar.gz 包里面全是静态编译好的可执行文件。所谓静态编译就是二进制已经把需要的库函数全部揉进去了不依赖系统里的动态库版本不怕 glibc 不一致也不怕缺这缺那。换句话说Docker 官方发布的就是一个 Linux 版“绿色免安装包”解压、复制、运行三步到位。从原理上讲Docker 本体是一组客户端-服务端程序你敲的 docker 命令是客户端真正干活的是后台守护进程 dockerddockerd 又依赖 containerd 来管理容器生命周期。静态包把这些组件按目录结构打包解压后你会看到一个 docker 文件夹里面躺着 docker、dockerd、containerd、containerd-shim-runc-v2、ctr、docker-init、docker-proxy、runc 这些文件。整个过程没有任何编译操作也不需要 Python 环境、不需要额外的运行时更不会往系统里塞一堆依赖库。这和 Windows 上的“免安装绿色版”思路一模一样唯一的区别是在 Linux 上还需要你自己写一个 systemd service 文件让系统知道怎么托管这个守护进程、怎么开机自启。1.3 哪些场景真正适合解压安装根据我这几年的实操经验下面几类场景我基本无脑选解压安装离线内网环境包管理器没源、没网、没法在线装一个 U 盘拷贝 tar 包进去就能搞定。国产化及非主流发行版麒麟、统信、欧拉、龙蜥这类系统官方 docker-ce 仓库往往适配不全静态包反而通吃。需要固定或指定版本比如线上已经用 Docker 27.1.1 验证过不想被 yum 源悄悄升到 27.2 甚至 28.x用二进制包锁版本最稳。批量初始化云主机或容器镜像脚本里下载、解压、配 systemd幂等性好重复执行也不会像包管理器那样出现依赖冲突。当然解压安装也不是没有缺点。它不会自动帮你做安全更新你得自己关注官方 release 手动换二进制也不会自动处理内核模块之类的底层要求比如 overlay 模块得系统自己支持。还有一点如果你哪天想卸载包管理器一条 remove 命令搞定解压安装就得自己删文件、清 systemd unit、删数据目录。所以我的建议是在线环境、标准发行版、懒得维护的情况下直接用官方脚本或者 docker-ce 源也挺好一旦你碰到上述四类场景解压安装就是那个最可靠、最少幺蛾子的方案。2. 解压安装 Docker 核心实操从 tar 包到 systemd 一步到位2.1 下载官方静态包与解压这一步最关键的只有一件事去官方静态下载页拿对应架构的包。Docker 官方把静态包放在了独立路径下格式是这样的https://download.docker.com/linux/static/stable/x86_64/docker-27.1.1.tgz其中 x86_64 可以换成 aarch64、armv7l、riscv64 等架构后面的版本号换成你想要的版本即可。注意别拿成 linux/static/edge 之类的测试版本生产环境老老实实用 stable。如果你的服务器能访问外网直接在服务器上 wget 就行如果服务器不能访问外网就在本地浏览器下载好传到服务器上再解压。你可以在 https://download.docker.com/linux/static/stable/ 下按架构目录找版本列表挑一个时间比较近的稳定版本。实操我习惯把下载和解压放在临时目录里mkdir -p /tmp/docker-install cd /tmp/docker-install wget https://download.docker.com/linux/static/stable/x86_64/docker-27.1.1.tgz tar -xzf docker-27.1.1.tgz ls -l docker/解压出来之后你会看到一个 docker 目录。这个目录就是你需要的全部内容了。注意如果你在服务器上没有外网GitHub 和 Docker 官方下载都慢甚至超时一个比较实用的办法是在有网的机器上下载好用scp rsync或 U 盘拷进内网机。国内有些公共镜像站会同步官方静态包但建议优先使用官方源次选镜像站时一定核对 SHA256 校验值和版本号避免拿到被篡改或错版本的文件。2.2 二进制落位与环境检查解压之后别急着跑先想清楚这些二进制要装到哪个目录。我个人的习惯是统一放/usr/bin原因有两个一是 root 用户的 PATH 里一般都有它不会出现命令找不到的问题二是 systemd unit 文件里 ExecStart 路径写起来也简洁。有些教程喜欢放 /usr/local/bin也没问题但你必须确认这台机器的 PATH 里包含这个目录否则非 root 用户敲 docker 会提示 command not found。复制并赋权cp docker/* /usr/bin/ chmod x /usr/bin/docker /usr/bin/dockerd /usr/bin/containerd /usr/bin/containerd-shim-runc-v2 /usr/bin/ctr /usr/bin/docker-init /usr/bin/docker-proxy /usr/bin/runc其实解压出来的二进制本来就是可执行的chmod 这步大多数时候是冗余操作但写成这样能保证万一 tar 解压时权限位受 umask 影响也不出错。验证一下docker --version # Docker version 27.1.1看到版本号说明客户端二进制没问题。但这时候还不能真正用因为 dockerd 还没被系统拉起来。接下来就是解压安装里唯一有点技术含量、也是决定成败的部分让 systemd 接管 Docker。2.3 手写 systemd 服务接管 dockerd有人会问我不写 systemd直接后台敲 dockerd 不行吗行是行但你会立刻遇到几个现实问题一重启服务就没了二进程异常退出没人管三没法开机自启四日志管理混乱。生产环境这样搞运维早晚被你坑死。所以 systemd 这一步必须做而且要做对。Docker 新版运行逻辑是 dockerd 依赖 containerd所以正确的做法是给这两个组件各写一个 service 文件。先创建 containerd 的服务cat /etc/systemd/system/containerd.service EOF [Unit] Descriptioncontainerd container runtime Documentationhttps://containerd.io Afternetwork-online.target local-fs.target [Service] ExecStartPre-/sbin/modprobe overlay ExecStart/usr/bin/containerd Typenotify Delegateyes KillModeprocess Restartalways LimitNOFILE1048576 TasksMaxinfinity [Install] WantedBymulti-user.target EOF再创建 dockerd 的服务cat /etc/systemd/system/docker.service EOF [Unit] DescriptionDocker Application Container Engine Documentationhttps://docs.docker.com Afternetwork-online.target docker.socket firewalld.service containerd.service Wantsnetwork-online.target Requirescontainerd.service [Service] Typenotify ExecStart/usr/bin/dockerd ExecReload/bin/kill -s HUP $MAINPID LimitNOFILE1048576 LimitNPROCinfinity LimitCOREinfinity TasksMaxinfinity TimeoutStartSec0 Delegateyes KillModeprocess Restartalways StartLimitBurst3 StartLimitInterval60s [Install] WantedBymulti-user.target EOF这里解释几个关键参数免得你抄完不懂出了事不知道从哪调。Typenotify表示 dockerd 启动完成之后会主动给 systemd 发一个“我已就绪”的信号systemd 收到才认为服务启动成功这比默认的 simple 类型更精确。TimeoutStartSec0表示不限制启动等待时间因为机器上如果数据盘很大、Docker 首次初始化要扫描一堆存储目录启动时间可能超过 systemd 默认的 90 秒到时候会被误杀。Delegateyes允许 Docker 接管某些 cgroup 子系统的管理权限这是容器正常运行的前提之一。KillModeprocess表示停止服务时只杀主进程不杀子进程避免 dpkg 这类场景出问题。Restartalways让守护进程崩溃后自动拉起。写完这两个文件后执行systemctl daemon-reload systemctl enable --now containerd systemctl enable --now docker systemctl status docker --no-pager这里有个经验之谈一定要先启动 containerd再启动 docker。虽然 docker.service 里写了 Requires 和 After但如果你手动先启 docker 再补 containerd偶尔会在 socket 通信上出现时序问题。按上面的顺序执行是最不容易出错的。2.4 启动验证与开机自启确认服务起来以后用 docker info 看整体状态docker info重点看 Server Version、Storage Driver、Cgroup Driver 这三项。正常输出里 Storage Driver 应该是 overlay2Cgroup Driver 在现代系统上是 systemd。看到这些说明 dockerd 已经真正跑起来了。接着验证容器创建能力docker run --rm hello-world这条命令会从远端拉取 hello-world 镜像并运行。如果你的环境能拉镜像输出那段经典欢迎语就说明整个链路全通了。如果是离线环境拉不到镜像也不用慌用 docker version 分别看 Client 和 Server 的版本Server 版本能正常输出就说明 dockerd 是活的。另外强烈建议在 /etc/docker/daemon.json 里配好基础项尤其是日志轮转不然默认的 json-file 日志会无限增长用不了多久就能把磁盘写满。我常用的配置{ log-driver: json-file, log-opts: { max-size: 100m, max-file: 3 }, data-root: /data/docker, storage-driver: overlay2 }其中>COMPOSE_VERSIONv2.29.2 curl -L https://github.com/docker/compose/releases/download/${COMPOSE_VERSION}/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose chmod x /usr/local/bin/docker-compose docker-compose version如果 curl 下载失败检查要么是网络问题要么是版本号写错了。GitHub 下载慢在国内是很常见的事你可以去 https://github.com/docker/compose/releases 页面确认你要的 release 版本号然后在能访问外网的机器下载好再传进内网机或者找国内公共镜像仓库下载同版本同架构的产物下载后务必执行chmod x。3.3 注册为 Docker CLI 插件安装独立命令之后再把这个二进制链接到 Docker CLI 插件目录让docker compose子命令也能用mkdir -p /usr/local/lib/docker/cli-plugins ln -s /usr/local/bin/docker-compose /usr/local/lib/docker/cli-plugins/docker-compose docker compose version这里要注意插件路径有讲究。Docker CLI 会从两个位置加载插件一个是用户目录~/.docker/cli-plugins一个是系统级目录/usr/local/lib/docker/cli-plugins或/usr/lib/docker/cli-plugins。给所有用户都用就放系统级目录。验证时如果docker compose version能输出 Compose 版本说明插件加载成功如果提示 unknown command多半就是路径不对或者没执行chmod x。还有个小细节插件文件名必须是 docker-compose不能改成 dockercompose、compose 之类的名字否则 CLI 识别不了。3.4 用一条 Compose 配置做安装验证装完 Compose光看版本不够最好真刀真枪跑一个验证。我常用的验证方式是用一个极简的 Nginx 服务配置内容少、镜像常见、效果直观services: nginx: image: nginx:1.27-alpine container_name: compose-demo-nginx ports: - 8080:80 restart: unless-stopped先把内容写到/tmp/compose-demo/docker-compose.yml然后在那个目录下执行cd /tmp/compose-demo docker compose up -d docker compose ps curl -I http://127.0.0.1:8080看到 HTTP 200 和 nginx 的响应头说明 Compose 能正常解析配置、拉镜像、建容器、做端口映射整个安装链路彻底验证完毕。跑完别忘清理验证容器docker compose down注意如果服务器在离线环境拉不到 nginx 镜像这一步先跳过用docker compose config来验证配置文件语法是否能通过。docker compose config会读取配置并输出标准化后的 YAML能正常输出说明 Compose 本身没装坏。4. 常见问题与排查技巧实录4.1 docker: unknown command: docker compose这个报错在所有“Docker Compose 安装”相关搜索里常年霸榜。原因基本有三类一是 Docker 版本太老低于 20.10 的版本没有 compose 子命令二是插件没装或者装错位置三是权限不足当前用户读不到插件文件。排查顺序建议这样先docker --version看版本再检查/usr/local/lib/docker/cli-plugins/docker-compose是否存在且有执行权限最后用docker compose version再试。如果确实想快速绕过问题直接用docker-compose version独立命令也能工作不影响日常使用。4.2 dockerd 启动失败containerd 与 socket 冲突最典型的症状是systemctl start docker卡很久甚至报 failed看日志用journalctl -u docker -f --no-pager。常见原因有这么几个containerd 没起来导致 dockerd 连不上 containerd 的 socket/var/run/docker.sock 或 /var/lib/docker 目录权限不对系统之前装过别的容器运行时留下了冲突的 socket 文件。我的处理习惯是systemctl status containerd先确认 containerd 活着再用ls -l /var/run/docker.sock看看 socket 属主必要时停掉冲突进程删掉残留 socket 和锁文件再systemctl restart docker。4.3 容器之间网络不通或容器无法访问外网如果你启动容器后容器内ping 8.8.8.8不通但 Docker 服务本身是正常的90% 是内核 IP 转发没开。检查命令sysctl net.ipv4.ip_forward如果输出是 0改成 1echo net.ipv4.ip_forward1 /etc/sysctl.conf sysctl -p改完一般就通了。另一种情况是防火墙策略太激进比如 firewalld 默认 zone 的 FORWARD 链把所有转发都 DROP 了Docker 建的 bridge 网络流量被卡住。这时候先systemctl status firewalld确认防火墙状态再决定是调整策略还是临时systemctl stop firewalld做对照测试。网上很多“docker 网络不通”的求助最后排查下来更像是 host 的网络和防火墙问题而不是 Docker 本身装坏了。4.4 非 root 用户不能使用 Docker还有一种高频情况Docker 装好了root 下一切正常但切到普通用户敲 docker 就报权限 denied。原因是 docker 默认通过 unix socket 与守护进程通信这个 socket 文件属于 root 组 docker。把用户加进 docker 组即可usermod -aG docker your_username执行后必须重新登录或者newgrp docker让组关系生效否则当前会话还是老的组信息。我见过太多人加了组却不重登回头又到处找问题。另外补充一句安全提醒有 docker 组权限的普通用户基本等价于 root 权限因为可以挂载宿主机目录进容器做任意操作。生产环境给谁加这个组要想清楚。4.5 日志文件暴涨导致磁盘报警这个问题容易被新手上手阶段忽略。Docker 默认的日志驱动是 json-file而且默认不裁剪。如果容器里跑的是 Nginx 或者 Java 应用访问量一大日志文件能以 GB 级速度增长。所以前面我强烈建议在 daemon.json 里提前配 log-opts把 max-size 和 max-file 设好。如果已经涨起来了可以用docker logs --tail看日志没问题但清理已有日志文件要到/var/lib/docker/containers/container-id/下面用truncate -s 0 xxx-json.log清空。改完 daemon.json 后记得重启 docker 才会对新容器生效。5. 最后再分享几个经验解压安装这条路我在不同系统上反复走了几十遍之后习惯已经固化成了一套流程下载 tar 包、归档到 /opt/archive、解压、复制、写两个 systemd unit、配置 daemon.json、启动、装 compose、刷一遍验证命令。这么做的好处是所有操作都可脚本化不会像包管理器那样受到源配置影响。你可以把整套流程写成一个 shell 脚本参数化版本号和架构之后新机器初始化就变成一行命令的事。有一个细节我特别想强调升级和回滚。用包管理器装的 Docker升级是“隐式”的你甚至不知道源里更新了。用解压安装升级就是“显式”的把旧二进制备份一份解压新包替换重启服务。如果新版本出了问题把备份拷回来再重启一次三分钟内回滚到旧版本。这种可控感在线上环境里值千金。我后来把内网所有服务器的 Docker 都换成了这种安装方式运维同事再也没因为 Docker 版本不一致来敲过我门。如果你按照这篇教程装完顺手把 daemon.json、systemd unit、docker-compose 二进制都归档一份到安全位置以后不管碰到什么发行版都能在被折腾到怀疑人生的时候想起还有“解压安装”这条保底路线。
返回列表