1. 对比包管理器与二进制通用包什么环境才值得选后者1.1 两种安装方式的分水岭大多数人在 Linux 上装 Docker第一反应就是 apt 或 yum 一把梭。这个思路本身没错apt install docker.io或者yum install docker-ce在普通场景里确实省心依赖自动拉、systemd 单元自动写、启动脚本自动配好几乎零成本。但如果你在下面这几类环境里待过就会明白包管理器方案其实非常别扭内网离线服务器软件源根本没有 Docker 的包想临时挂载一个本地源又要折腾半天发行版比较冷门或者是一个阉割版系统包仓库里没有 Docker或者版本老得没法看生产环境要求版本可预期、可锁定不允许 apt upgrade 一冲动把 Docker 版本顺带换掉需要在一批不同发行版上保持完全一致的 Docker 版本方便排障和运维。有这些需求时官方发布的二进制通用包就是最合适的答案。它本质上是一个静态编译的 tarball不依赖系统里有没有某版本 libc不需要包管理器参与把里面的工具铺好位置自己写好 systemd 单元Docker 就能像原生服务一样跑起来。官方把这种安装方式称为 static binary。下面这张表是我在实际运维中反复对比后的结论对比项包管理器安装apt/yum二进制通用包安装依赖处理自动拉取但可能污染系统中的共享依赖基本零库依赖全部内置在 tar 包中版本控制受仓库源版本约束容易被动升级自己下载指定版本版本完全可控离线安装需要完整的离线源工作量大只需一个 tarball 和校验文件systemd 集成自动完成手动编写 unit 文件约 10 分钟升级/回滚依赖包管理器的行为tar 包覆盖即升级留旧版即回滚学习成本低中等但对排障能力很有帮助一句话包管理器适合求快二进制通用包适合求稳、求可控、求可复现。生产环境我后面基本一律二进制。1.2 二进制包的适用边界与先决条件需要说清楚二进制包不是万能的它也有自己的边界。首先是内核与系统基础组件这恰恰是很多人忽略的点。Docker 的静态包虽然把用户态的东西都打包了但底层仍然依赖 Linux 内核特性比如 namespaces、cgroups、overlayfs、iptables/nftables。也就是说你可以在一个非常精简的最小系统上装 Docker但这个系统的内核要足够新至少能支撑 overlay2 存储驱动和 cgroup v2内核 4.9 以上基本没压力5.x 内核是最舒服的。内核太老的话再高级的二进制包也白搭。其次是进程托管方式。官方二进制包里的 dockerd 不带自带的服务管理逻辑你希望它开机自启、崩溃自动拉起、和 systemd 日志系统无缝集成就得自己写 systemd unit。如果目标机器是 SysV init 或纯容器化环境连 systemd 都没有那就要用dockerd 这类方式凑合但这种跑法不适合长期生产日志和进程管理都很脆弱。最后是SELinux 和 AppArmor。在 RHEL/CentOS 系列上如果用二进制包手动铺装polkit 规则和 SELinux 上下文一般不会自动配好遇上服务起不来 / 容器无法访问文件这类怪问题时优先怀疑 SELinux 而不是 Docker 本身。好在大部分普通场景下把这层先 relax 掉就能跑通具体怎么定位我放到后面故障排查那一节细说。1.3 装之前先明确这套方案的管理成本聊完优点我也得把账算明白。二进制通用包的主要代价就是一切手动不会自动升级安全性补丁需要自己关注 release 动态不会自动补 unit 文件初始化时必须自己写不会自动处理用户组普通用户要访问 Docker 得手动加入 docker 组不会自动处理镜像加速与日志轮转这些都要写进/etc/docker/daemon.json。这些成本加起来差不多也就是半小时的一次性投入换来的是对整套运行时dockerd、containerd、runc的完全掌控。我见过不少团队被包管理器升级搞怕了一次ubuntu unattended-upgrade把 Docker 从 20.10 升到 24.0结果 K8s 集群直接不认存储驱动。用二进制包锁版本之后这种事情再没发生过。接下来我就按完整流程走一遍。2. 下载、校验与拆包把官方仓库的 tarball 变成可控资产2.1 确认架构与官方目录结构动手之前先确认两件事一是目标系统的 CPU 架构二是目标系统能不能访问官方下载站点。架构直接决定下载路径别想当然地以为都是 x86_64。uname -m cat /etc/os-release常规服务器输出一般是x86_64树莓派之类的是aarch64或armv7l还有s390x、ppc64le这类小众架构。Docker 官方下载目录把架构分得很清楚https://download.docker.com/linux/static/stable/x86_64/ https://download.docker.com/linux/static/stable/aarch64/ https://download.docker.com/linux/static/stable/armv7l/ https://download.docker.com/linux/static/stable/s390x/注意stable和edge有的版本叫test的区别。stable目录下的才是经过完整验证的稳定版edge或者test目录下的版本用于试验新功能千万不要拿到生产环境去装。有的教程为了追新版本直接从别处复制一个 URL 就下载这很容易下到非 stable 分支的包后面的行为都不可预期。2.2 选版、下载与校验确认好架构后进目录看一下有哪些版本。我用 x86_64 举例假设当前 stable 目录下的最新版是docker-27.3.1.tgz实际以你在目录列表里看到的为准curl -sSL https://download.docker.com/linux/static/stable/x86_64/ | grep docker-27找个干净的目录比如/opt/software把包下载下来mkdir -p /opt/software cd /opt/software wget https://download.docker.com/linux/static/stable/x86_64/docker-27.3.1.tgz下载完成后务必做校验。这一步很多人会跳过但我强烈建议不要省。静态包大多是压缩包传输过程中有损坏或者镜像源被替换都可能导致后面装出一个行为诡异的 Docker。校验方法很简单sha256sum docker-27.3.1.tgz然后把输出的哈希值和 Docker 官方在该版本 Release Notes 或 GitHub Release 页面公布的校验值对比。同一目录下也有文件大小的参考值连大小都对不上的话基本可以判定文件坏了。我踩过这样一个坑某次在内网通过跳板机传输 tarball中间环节的文件被截断了 200 字节tar没有立刻报错结果解压出来的 dockerd 一启动就 segmentation fault查了大半天才发现是包坏了。从那以后凡是从外部拿回来的安装包一律先sha256sum再落地这应该成为安装规范的一部分。2.3 解包后先验货tarball 里到底有什么下载校验通过后解压tar xzf docker-27.3.1.tgz ls -lh docker/你会看到一个docker目录里面是这套通用包的完整内容。我以某个较新的版本为例典型的文件清单如下docker/ ├── containerd ├── containerd-shim-runc-v2 ├── ctr ├── docker ├── docker-init ├── docker-proxy ├── dockerd └── runc这些文件各管一摊docker客户端 CLI就是你平时敲docker ps、docker run用的那个程序dockerd守护进程端真正管理镜像、容器、网络的那部分containerd容器运行时管理器负责拉镜像、管理容器生命周期Docker 在现代版本里把它作为底层运行时的核心组件containerd-shim-runc-v2容器和 containerd 之间的中间进程负责容器退出后的兜底和 IO 转发runcOCI 容器的真正创建者负责和 Linux 内核打交道ctrcontainerd 自带的调试客户端平时用不到但排查 containerd 问题时要靠它docker-init容器内 PID 1 的轻量初始化程序负责处理孤儿进程和信号转发docker-proxy宿主机端口映射到容器时的辅助代理负责 docker run -p 的端口转发。先知道包里都有什么后面排查问题时思路会清晰很多。比如容器里进程变僵尸、端口映射时灵时不灵你就能联想到是 docker-init 或 docker-proxy 的问题而不是瞎猜。3. 铺装整机二进制布局、权限与三段 systemd 单元3.1 拷贝二进制、准备目录与用户组验完货直接拷贝。我习惯把二进制放到/usr/bin这样 systemd 单元里写ExecStart/usr/bin/dockerd最自然也符合大多数发行版 PATH 的默认范围。如果你想装到/usr/local/bin也完全可以但 unit 文件里的路径必须同步修改别配岔了。cp docker/* /usr/bin/ chmod 755 /usr/bin/docker /usr/bin/dockerd /usr/bin/containerd /usr/bin/runc /usr/bin/ctr /usr/bin/docker-init /usr/bin/docker-proxy /usr/bin/containerd-shim-runc-v2接着准备 Docker 自己的目录和用户组mkdir -p /etc/docker mkdir -p /var/lib/docker groupadd docker/etc/docker是 daemon.json 配置所在地/var/lib/docker是默认数据根目录容器、镜像、卷全在这里。这里有一点值得展开如果你打算把数据盘挂到独立分区一定要在初始化阶段就把>getent group docker || groupadd docker加组这步不会立刻对当前登录的 shell 生效后面我会讲具体怎么让权限马上可用。3.2 containerd 先行为什么这套方案离不开鸡生蛋蛋生鸡的编排老版本的 Docker 直接由 dockerd 自己管理容器运行时新版本的架构则是 dockerd 与 containerd 协作。从 Docker 20.10 以后containerd 必须作为独立服务存在dockerd 启动时会去连 containerd 的 socket默认在/run/containerd/containerd.sock。如果你只把 dockerd 拉起来而 containerd 没运行dockerd 会反复报 failed to connect to containerd 之类的错误。所以这套方案的正确编排是docker.socket先监听好 API socketcontainerd.service先运行起来docker.service再作为最终承载启动 dockerd。三个单元互相之间要靠Requires、After、Wants把顺序约束住否则 systemd 并行启动时会出现竞态偶尔成功偶尔失败。这一段是我实际排障得来的教训。最早我图省事只写了 docker.service 一个单元把 containerd 直接忽略结果服务 10 次里有 3 次起不来起不来时 journald 里的错误信息还非常具有迷惑性。后来老老实实拆成三个单元顺序理顺这个问题彻底消失。3.3 三段 unit 文件逐一拆解下面是三个 unit 文件的具体内容你可以直接复制参考只要把路径和你的环境对齐就可以。先创建/etc/systemd/system/docker.socket[Unit] DescriptionDocker Socket for the API [Socket] ListenStream/var/run/docker.sock SocketMode0660 SocketUserroot SocketGroupdocker [Install] WantedBysockets.target这个 socket 单元的意义在于systemd 会提前把/var/run/docker.sock创建好并监听。这样一来即使 dockerd 还没完全就绪客户端连这个 socket 时 systemd 也能通过 socket activation 机制把 dockerd 拉起来。SocketMode0660和SocketGroupdocker就决定了普通 docker 组成员能不能访问——如果你省掉这个设置后面保准会遇到权限 denied这是权限问题的根源之一。再创建/etc/systemd/system/containerd.service[Unit] Descriptioncontainerd container runtime Documentationhttps://containerd.io Afternetwork.target local-fs.target [Service] ExecStartPre-/sbin/modprobe overlay ExecStart/usr/bin/containerd Typenotify Delegateyes KillModeprocess Restartalways RestartSec5 LimitNOFILE1048576 LimitNPROCinfinity LimitCOREinfinity TasksMaxinfinity [Install] WantedBymulti-user.target这个单元里有几个细节值得说明。ExecStartPre-/sbin/modprobe overlay中的短横线表示这条命令即使失败也不要影响服务启动因为 overlay 模块在很多新内核里已经内置了加载失败不代表有错误。Typenotify表示 containerd 会通过 sd_notify 协议主动告诉 systemd 我已经准备好这比盲目等 timeout 要可靠得多。Delegateyes允许 containerd 完整接管 cgroup 子树的资源管理配合TasksMaxinfinity避免进程数限制导致容器启动报 cgroup 相关错误。最后创建/etc/systemd/system/docker.service这是最核心的一个[Unit] DescriptionDocker Application Container Engine Documentationhttps://docs.docker.com Afternetwork-online.target firewalld.service containerd.service docker.socket Wantsnetwork-online.target Requiresnetwork-online.target docker.socket containerd.service [Service] Typenotify ExecStart/usr/bin/dockerd -H fd:// --containerd/run/containerd/containerd.sock ExecReload/bin/kill -s HUP $MAINPID TimeoutStartSec0 RestartSec2 Restartalways LimitNOFILEinfinity LimitNPROCinfinity LimitCOREinfinity TasksMaxinfinity Delegateyes KillModeprocess [Install] WantedBymulti-user.target解释几个关键点ExecStart里的-H fd://表示 dockerd 通过 systemd 传入的 socket fd 来接收请求而不是自己再开一个 socket 监听。这依赖 docker.socket 单元如果 socket 单元没写对这里就会出现fd://无法工作的怪问题。--containerd/run/containerd/containerd.sock明确指定 dockerd 要找的 containerd socket 路径。TimeoutStartSec0表示不限制 dockerd 启动等待时间。首次启动时 dockerd 要初始化网络、存储、底层运行时等对于大型数据盘或者特殊存储驱动启动可能超过默认的 90 秒不设成 0 就会看到 timed out 但实际服务还在初始化。Restartalways配合RestartSec2进程异常退出后 2 秒自动拉起这在生产环境能大大减少人工干预。三个文件写完后执行systemctl daemon-reload每次修改 unit 文件后都必须daemon-reload否则 systemd 还记着旧配置改了等于白改。3.4 daemon.json 的初始化配置还记得前面建好的/etc/docker目录吗现在给/etc/docker/daemon.json写入一份初始配置。我建议哪怕是临时测试环境也写上避免后面为日志撑爆磁盘而头疼{ data-root: /var/lib/docker, exec-opts: [native.cgroupdriversystemd], log-driver: json-file, log-opts: { max-size: 10m, max-file: 3 }, storage-driver: overlay2, registry-mirrors: [https://your-mirror-address.example.com] }其中exec-opts里的native.cgroupdriversystemd是我的强烈建议。当 Docker 在 systemd 下运行时如果 cgroup 驱动保持默认的 cgroupfs以后要是再叠上 Kubernetes 这类编排系统就会出现 cgroup 驱动不一致的问题K8s 会直接拒绝调度。storage-driveroverlay2是当前 Linux 主流内核环境下的最优选择性能比 vfs 好一个数量级。registry-mirrors留了占位符在实际使用中替换为你所在网络环境里可用且可信的镜像加速地址能显著缓解拉镜像慢的问题。如果写错了 daemon.json 导致 Docker 起不来先别慌把配置一项项读出来检查 JSON 格式逗号、括号最容易错改完再启动。4. 首次启动与全链路验证从 systemd 到拉镜像跑容器4.1 按依赖顺序拉起服务一切就绪执行systemctl enable --now docker.socket containerd.service docker.service用enable --now一次性完成开机自启和立即启动。如果你担心顺序问题可以分步systemctl start docker.socket systemctl start containerd systemctl start docker启动完先用systemctl status看一眼这是最直观的状态反馈systemctl status docker --no-pager -l看到Active: active (running)基本就成功了一大半。然后测试 socket 和进程ls -l /var/run/docker.sock ps aux | grep -E dockerd|containerd/var/run/docker.sock的属主应该是 root属组是 docker权限 0660。如果 socket 不存在说明 docker.socket 单元没生效检查systemctl status docker.socket。4.2 docker version 与 docker info 该看哪些字段服务起来之后立刻验证 CLI 能不能连上 daemondocker version这个命令会分两段显示Client段和Server段。Client来自/usr/bin/docker这个二进制Server来自 dockerd。如果 Server 段正常打印出来说明客户端和 daemon 之间的链路、containerd 的连接都通了。如果 Server 段报错那问题多半在 dockerd 或 containerd需要去 journal 里翻日志。接着看docker info的关键字段docker info重点确认这几项Server Version是否和你下载的版本一致Storage Driver应该是 overlay2如果变成 vfs说明 overlay 模块有问题Cgroup Driversystemd 模式下应该显示 systemdDocker Root Dir确认数据目录是你预期的路径别不知不觉写到了系统盘Containers/Running/Images初始状态为 0这里能快速发现是否有历史数据残留。4.3 hello-world 验证与普通用户免 sudo然后跑最经典的验证docker run --rm hello-world这条命令背后发生了一连串事情CLI 通过 socket 通知 dockerddockerd 让 containerd 去拉取 hello-world 镜像containerd 通过 runc 创建容器容器里输出一段欢迎信息。整条链路任何一个环节断了都会在这条命令上暴露。如果镜像拉取很慢先检查 daemon.json 里的 registry-mirrors 是否生效docker info里会列出当前 registry mirrors。验证 Docker 功能正常后处理普通用户权限。用普通用户执行docker ps时会看到经典的报错permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock处理方式是把自己加入 docker 组sudo usermod -aG docker $USER注意加入 docker 组后不会立刻生效因为当前会话的组信息还停留在登录时。要么重新登录要么在当前 shell 里执行newgrp dockernewgrp这条命令很多人不知道它能直接刷新当前终端进程的组身份不用退出重登省了很多事。之后再用docker ps就正常了。这里多说一句安全话题docker 组等同于 root 权限因为它可以挂载宿主机目录、操作特权容器所以把哪些账号加进 docker 组要慎重开发机无所谓生产机上尽量只给运维账号。到这里一套由二进制通用包搭建的 Docker 已经完整跑起来了。但这只是开始真正有价值的是后面遇到问题时怎么把故障拆解掉。5. 启动失败与权限问题一线排查的完整思路5.1 第一步永远是看日志而不是瞎重启服务起不来的时候我见过太多人第一反应是systemctl restart docker但这基本等于蒙着眼睛开车。正确的第一步是看日志journalctl -u docker -n 100 --no-pager journalctl -u containerd -n 100 --no-pager如果日志里信息不够dockerd 还可以用前台调试模式跑这样所有报错都会打在终端上信息密度比 journal 高很多systemctl stop docker dockerd --debug前台模式下你能看到 dockerd 一步步初始化加载配置、初始化存储驱动、创建网桥、连接 containerd。卡在哪一步错误就在哪一行。看到报错后按 CtrlC 停掉再修复问题。这个方法对一切启动失败但原因扑朔迷离的场景都有效建议每个人都练几遍比背命令有用得多。5.2 Cannot connect to the Docker daemon 的处理路径客户端报Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?时不要急着怀疑 daemon先做三件事第一确认 socket 文件是否存在ls -l /var/run/docker.sock不存在说明 docker.socket 没起来或者启用了但被 systemd 移除了。检查systemctl status docker.socket。第二确认 socket 是否挂在 systemd 手里systemctl list-sockets | grep docker如果 socket 存在但 docker.service 没启动所有连接会在 systemd 层面被 accept然后触发 docker.service 启动。如果 docker.service 启动失败连接就会报错。这时候看前面提到的 journal 日志找 dockerd 的启动错误。第三确认 DOCKER_HOST 环境变量有没有被污染echo $DOCKER_HOST有些教程或者脚本会把DOCKER_HOST设成远程 daemon 地址一旦被设成了非本机地址客户端就会去连一个不存在的地址。清掉这个变量或用docker -H unix:///var/run/docker.sock ps强制指定就是另一个世界。5.3 权限 denieddocker 组与 socket 模式的细节权限问题的典型报错就是 5.3 节开头说的permission denied while trying to connect to the Docker daemon socket。它的根源通常是用户不在 docker 组或者 socket 权限设置不对。先验证你的用户在哪个组id sudo -u $USER groups如果不在 docker 组里按前面 4.3 的方法加组。如果已经在组里还报权限错误那就看 socket 权限ls -l /var/run/docker.sock期望结果是srw-rw----且 root 用户、docker 组。如果你的 socket 权限是 0600 或者其他异常值说明 docker.socket 单元里的SocketMode0660没写或者后来有别的进程改动过 socket 权限。修复方式有两种改 unit 文件然后重启 docker.socket或者手动chmod 0660 /var/run/docker.sock。前者是治本后者是应急。还有一个隐蔽坑在某些精简系统上docker 组可能不存在但 unit 文件里写了SocketGroupdockersystemd 在创建 socket 时发现组不存在会把组设置成一个不正常的值。所以前面提到getent group docker || groupadd docker的预检查要在写 unit 文件之前就做掉。5.4 网络与存储驱动两个高频翻车点网络问题主要集中在宿主机上看到 docker0 网桥没有创建或者容器之间互通异常。dockerd 启动时会自动创建 docker0并往 iptables 里写入 NAT 和 FORWARD 规则。常见故障场景宿主机 netfilter 的 FORWARD 链策略被某些安全软件改成了 DROP导致跨容器、容器外网流量全部被丢。解决办法是显式放行iptables -P FORWARD ACCEPT这只是临时做法更持久的做法是把规则写进防火墙配置里或者研究清楚是谁改了默认策略。缺少br_netfilter内核模块时Docker 网络会出现各种诡异问题modprobe br_netfilter sysctl -w net.bridge.bridge-nf-call-iptables1云平台环境常见的坑是主网卡没有开启混杂模式或受云防 ARP 限制docker0 通了但容器出不去这时排查顺序是宿主机ping 8.8.8.8是否通、容器里ping 宿主机是否通、iptables -t nat -L POSTROUTING里有没有容器网段的 MASQUERADE 规则。存储驱动翻车则主要围绕 overlay2。如果你的内核开启了 module 加载限制或者使用了一个不支持 overlay 的文件系统比如把 Docker 数据目录放在某个云盘的只读挂载点上dockerd 启动会退化成 vfs 驱动性能大打折扣。验证方法cat /proc/filesystems | grep overlay有 overlay 输出说明内核支持。如果不支持可以尝试modprobe overlay还不行就需要检查内核版本或者换一个数据目录位置。用vfs跑生产环境不是不行但容器层文件变化时是完整拷贝镜像体积和 IO 消耗会非常感人。5.5 常见报错速查表下面把我在一线见过的高频报错整理成速查表遇到问题先对照报错特征可能原因处理方向Cannot connect to the Docker daemondaemon 未启动、socket 不存在、DOCKER_HOST 错误查 socket、journal、环境变量permission denied...docker.sock用户不在 docker 组、socket 权限被改usermod -aGchmod 0660newgrpfailed to dial gRPC: containerdcontainerd 未启动、socket 路径不一致启动 containerd核对 dockerd 参数error creating overlay mount内核无 overlay 模块、数据目录文件系统不支持modprobe overlay换存储驱动iptables failed/docker0 not foundFORWARD 策略、br_netfilter 缺失、firewalld 冲突放行 FORWARD、加载模块、处理防火墙error saving image...operation not permitteddaemon.json 路径权限错误、磁盘只读检查 /var/lib/docker 权限与挂载Device cgroup isnt mountedcgroup 挂载异常老内核/容器内嵌套检查 /sys/fs/cgroup 挂载状态cgroup v2: systemd driver vs cgroupfs后续加 K8s 时驱动不一致daemon.json 里统一为 systemd排查的核心思路永远是先看日志、再查链路、最后动配置。别一上来就docker system prune或者重装系统大部分问题都是配置层面的日志里都写着答案。6. 版本升级、回滚与日常维护把二进制安装跑成长久方案6.1 升级操作的标准动作用二进制包方案的长期运行绕不开升级和回滚。升级的标准动作其实很简单# 1. 停止 Docker 相关服务 systemctl stop docker.socket docker.service containerd.service # 2. 下载新版本 tarball 并校验过程参考第二节 cd /opt/software wget https://download.docker.com/linux/static/stable/x86_64/docker-27.4.1.tgz sha256sum docker-27.4.1.tgz # 3. 解压并覆盖旧二进制 tar xzf docker-27.4.1.tgz cp docker/* /usr/bin/ # 4. 重新加载并启动 systemctl daemon-reload systemctl start containerd docker.socket docker.service升级前重点检查两件事。一是兼容性新版本 dockerd 一般能兼容旧版本数据目录但跨大版本升级比如 20.x 直接到 27.x建议先看官方 release notes 里是否提及存储格式或配置变更。二是containerd 版本二进制 tar 包里的 containerd 是和 dockerd 配好套的升级时应该一起覆盖。最忌讳的是系统里原来有一个 apt 装的 containerd你又拿 tar 包的 containerd 覆盖了一半最后两套版本混着用保准出怪问题。6.2 回滚预案升级回滚是二进制方案的天然优势。只要升级前备份了旧版本二进制回滚就是几个命令的事# 假设升级前你把旧二进制都留在了 /opt/docker-backup systemctl stop docker.socket docker.service containerd.service cp /opt/docker-backup/* /usr/bin/ systemctl daemon-reload systemctl start containerd docker.socket docker.service所以关键动作在升级前就要做mkdir -p /opt/docker-backup cp /usr/bin/docker /usr/bin/dockerd /usr/bin/containerd /usr/bin/runc /usr/bin/ctr /usr/bin/docker-init /usr/bin/docker-proxy /usr/bin/containerd-shim-runc-v2 /opt/docker-backup/另外升级前尽量做一次数据层面的快照。/var/lib/docker里存放着容器和镜像数据卷也在这里。虽然版本回滚一般不影响已有数据但万一升级过程中数据目录被新版本 daemon 做了迁移没有备份就只能干瞪眼。数据目录的备份不需要停服务用tar --exclude排除运行时文件也能凑合最稳的还是配合存储的快照能力。6.3 日志、磁盘与孤儿资源长期运行的 Docker 宿主机最容易被忽视的是日志和磁盘。daemon.json 里配置的日志轮转参数要尽早配好。一旦没配容器里程序疯狂打日志json-file 日志文件可能以 GB 计的速度增长直接撑爆系统盘。检查当前各容器日志大小的命令du -sh /var/lib/docker/containers/*/*-json.log | sort -rh | head如果已经积累了大量日志可以即时清掉容器还在运行清完会继续写truncate -s 0 /var/lib/docker/containers/container-id/*-json.log镜像和容器长期增删后悬空镜像和停止的容器会占用不少磁盘。定期清理是必要的docker system prune -f但注意-a参数会把所有未被容器使用的镜像都删掉包括你想本地留档的版本。我自己一般只执行不带-a的docker system prune版本镜像保留用docker image tag打上明确的版本号避免误删。6.4 几点长期经验最后分享几条我用二进制方式维护 Docker 的长期经验一是保留一套固定的安装脚本。把下载、校验、铺装、unit 文件生成写成一个幂等 shell 脚本放到服务器上每次新机器处理直接跑一遍。这样能保证每台机器环境一致出问题也好对比。二是记录版本与校验值。我习惯在安装目录里放一个version.txt记录安装/升级的时间、版本号、sha256 值。等到这台机器变成事故现场时这些记录可能就是唯一能帮助你确认当初到底装了什么的依据。三是关注 containerd 和 runc 的安全通告。二进制方案没有包管理器帮你跟踪 CVE所以最好定期关注 Docker 官方 release 页面确认当前稳定分支有没有重要的安全修复。这个成本不高但收益很高。四是别把 systemd 单元当一次性文件。它和 daemon.json 一样都是这台机器的配置资产。我通常会把这三个 unit 文件和 daemon.json 一起纳入配置管理仓库Git 或 Ansible 都行任何修改走版本化流程而不是直接在机器上改。需要回滚配置时比什么都好使。我从第一台用二进制包方式部署 Docker 的机器算起这套方案已经稳定跑了三四年期间经历了多次大版本升级既没有被包管理器的依赖绑架过也没有因为某次自动升级导致集群不可用。每个方案都有自己的适用场景但如果你和我一样要管理多个发行版混合的环境、又不想被系统包仓库牵着鼻子走二进制通用包这条路值得你认真走一遍。
企业数字化 ERP 产品动态
相关推荐
自带降重+降 AI 率功能!2026这3款降AIGC工具太给力了! 谁还在为AI生成论文的AI率太高发愁?明明用AI省了时间,结果查重时AIGC率超标,直接被老师打回重写,熬夜改到崩溃真的太窒息了!最近被问最多的就是“有没有可以自动降AI率的论文生成工具”,作为过来人… · 2026/9/26 12:36:06
从单点智能到群体协同:工业智能体如何落地? 1. 为什么“单点智能”越来越不够用了:工业现场的真实瓶颈过去几年,我在不少工厂和能源现场转过,也参与过一些数字化改造项目。大家聊得最多的一个词就是“智能”:“我们上了视觉质检”“我们做了设备预测性维护”“我们有一套APS… · 2026/9/26 12:36:06
基于YOLOv8的光伏电池EL图像缺陷检测实战指南 简介:一套基于YOLOv8的光伏电池缺陷检测项目,面向需要掌握目标检测算法落地与工业质检场景的开发者与学习者,覆盖模型训练、推理与部署全流程。项目共收录一千一百一十一个文件,其中包含一百五十九个Python训练/推理脚本、六十八个… · 2026/9/26 12:36:00
spacedesk零配置副屏搭建:网络握手与显卡驱动调优指南 1. 为什么“旧平板变副屏”这件事,90%的人第一次 setup 就卡在了网络握手环节spacedesk 这个名字最近半年在 Windows 用户圈里突然密集出现,不是因为什么新功能发布,而是因为——它真的把“扩展屏”这件事,从硬件依赖的牢笼里撬开… · 2026/9/26 12:35:53
数据库课后习题答案别硬背:当测试用例集刷,效率翻倍 简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、… · 2026/9/26 0:00:21
OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 0:00:40
向下兼容与向上兼容:接口设计中的兼容性策略与工程实践 一次版本升级事故,是很多团队绕不过去的坎。线上环境里,服务端明明已经上线了新版接口,老的移动端还在照着旧文档传参数。请求一到网关,校验直接拒绝,用户操作失败,客服群炸了锅,开发群里开始互… · 2026/9/26 0:00:46