Docker 基础体系 · 第 63/70 篇。示例以现代 Docker Engine、BuildKit 与 Compose 规范为基础,并明确 Linux 容器边界。
Docker Live Restore 与重启恢复:Daemon 故障、容器存活和限制
Docker 中有三个经常被混为一谈的问题:
dockerd进程重启或暂时不可用时,已经运行的容器是否继续运行?- 宿主机重启后,容器是否能够自动恢复?
- Docker 服务恢复后,容器、网络、日志和应用状态是否都已经恢复?
这三个问题分别对应 Live Restore(实时恢复)、容器重启策略以及应用自身的持久化与恢复能力。它们解决的故障层级不同,不能互相替代。
本文讨论现代 Docker Engine、BuildKit 与 Compose 规范下的 Linux 容器,重点解释 Docker Daemon 故障、容器进程存活、宿主机重启恢复和相关限制。
一、先区分 Docker Daemon、容器和宿主机
1. Docker Daemon 是控制面,不等于容器进程
Docker Daemon 通常指 dockerd,它负责:
- 解析 Docker API 请求;
- 创建、启动、停止和删除容器;
- 管理镜像、网络、卷和插件;
- 与 containerd、容器运行时以及 Linux 内核交互;
- 提供
docker ps、docker run等命令背后的服务端能力。
容器本身不是一个独立的虚拟机。一个 Linux 容器通常只是宿主机上的一组进程,它们通过以下 Linux 机制隔离:
- PID namespace;
- mount namespace;
- network namespace;
- user namespace;
- cgroup;
- capabilities、seccomp 和其他安全限制。
在现代 Docker Engine 中,典型进程关系可以简化为:
flowchart TD
CLI["docker CLI / API 客户端"]
D["dockerd"]
CT["containerd"]
SHIM["containerd-shim"]
RUNC["runc"]
P["容器进程"]
K["Linux Kernel"]
CLI --> D
D --> CT
CT --> SHIM
SHIM --> RUNC
RUNC --> P
P --> K
SHIM --> K
runc 通常负责创建容器,完成后退出;容器长期运行时,containerd-shim 会承担与容器进程相关的管理和 I/O 连接职责。具体进程划分会随 Docker Engine、containerd 和运行时版本变化,但关键事实是:
dockerd是 Docker 的控制面,而容器进程最终由 Linux 内核调度和维护。
因此,dockerd 崩溃不必然意味着容器进程已经退出;反过来,dockerd 正常运行也不能保证容器内应用没有崩溃。
2. docker ps 不是容器存活本身
执行:
docker ps
需要 Docker API 服务可用。如果 dockerd 正在重启,可能出现:
Cannot connect to the Docker daemon at unix:///var/run/docker.sock.
Is the docker daemon running?
这只能说明 Docker 客户端暂时无法访问 Daemon,不能直接推出容器已经停止。
判断容器内进程是否仍然存在,需要从宿主机进程、容器运行时或应用端口等多个角度验证。例如:
ps -ef | grep '[d]ocker-proxy'
ps -ef | grep '[c]ontainerd-shim'
ss -lntp
curl -fsS http://127.0.0.1:8080/health
其中每种检查回答的问题不同:
docker ps:Docker 控制面是否能看到容器;containerd-shim:相关运行时管理进程是否仍存在;ss:宿主机监听端口是否仍然存在;- 应用健康检查:应用是否真的能够提供服务。
二、什么是 Live Restore
1. 定义
Docker Live Restore 是 Docker Engine 的一个 Daemon 配置能力。启用后,当 dockerd 暂时不可用或重启时,已经运行的容器可以继续运行,而不必因为 Daemon 的退出而被主动停止。
配置方式是在 Docker Daemon 配置文件中加入:
{
"live-restore": true
}
Linux 上通常使用:
/etc/docker/daemon.json
如果该文件已经存在,必须把配置合并到原有 JSON 中,不能直接覆盖原配置。例如:
{
"data-root": "/var/lib/docker",
"log-driver": "local",
"live-restore": true
}
配置文件必须是合法 JSON:
- 不能写注释;
- 字符串使用双引号;
- 最后一项不能多逗号;
- 同一个选项不能同时在命令行和配置文件中定义出冲突值。
可以先验证配置:
sudo dockerd --validate --config-file=/etc/docker/daemon.json
成功时,现代 Docker Engine 通常输出类似:
configuration OK
不同版本对验证输出的具体文字可能不同;关键是命令退出状态为成功,并且没有报告未知字段或冲突配置。
然后重启 Docker 服务使配置生效:
sudo systemctl restart docker
检查是否启用:
docker info --format '{{json .LiveRestoreEnabled}}'
典型输出:
true
也可以直接查看:
docker info
并查找:
Live Restore Enabled: true
2. Live Restore 的核心条件
可以把 Live Restore 的目标抽象为:
则在满足运行时和配置限制时,期望:
其中:
- 表示 Docker Daemon;
- 表示容器进程;
- 表示宿主机 Linux 内核;
- 是 Daemon 故障时间;
- 是 Daemon 恢复或观察时间。
这个条件的直觉是:Live Restore 保留的是已经存在的容器进程及其运行时状态,不是把容器状态保存成一个可以跨宿主机启动的快照。
因此,以下情况不能仅靠 Live Restore 解决:
- 宿主机重启;
- 宿主机断电;
- Linux 内核崩溃;
- 容器进程自身崩溃;
- 需要重新创建容器;
- 需要恢复未持久化到卷或外部存储的数据。
三、Daemon 重启时,容器为什么可以继续运行
1. 没有 Live Restore 时的常见路径
如果没有启用 Live Restore,Docker Daemon 停止时,Docker 可能会停止它管理的容器。抽象流程如下:
sequenceDiagram
participant A as 运维人员
participant D as dockerd
participant R as containerd/shim
participant C as 容器进程
A->>D: systemctl restart docker
D->>R: 停止或断开管理关系
R->>C: 停止容器
D-->>A: Daemon 重新启动
D->>R: 重新扫描容器
Note over C: 原容器已经退出
这里不能简单理解为“Daemon 是容器的父进程,所以 Daemon 一死容器必死”。真实行为还受到 containerd、shim、systemd 服务单元和 Docker Engine 版本影响。但在未启用 Live Restore 时,Docker 默认可以在 Daemon 停止期间停止容器,因此不应依赖容器继续运行。
2. 启用 Live Restore 后的路径
启用 Live Restore 后,Daemon 重启期间的目标路径变为:
sequenceDiagram
participant A as 运维人员
participant D as dockerd
participant R as containerd/shim
participant C as 容器进程
participant K as Linux 内核
A->>D: systemctl restart docker
D--xR: dockerd 暂时退出
Note over R,C: shim 和容器进程保持运行
C->>K: 继续运行、使用 namespace/cgroup
D->>R: 新实例启动并重新连接
R-->>D: 返回容器状态
D-->>A: docker ps 恢复可用
关键点有两个:
- 容器进程在 Daemon 暂时不可用期间仍存在;
- Daemon 恢复后重新接管和展示这些容器。
Live Restore 不是把容器迁移到另一个节点,也不是在内存中创建容器副本。容器始终运行在原来的宿主机上。
3. 一个可验证的实验
先启动一个持续写入时间的容器:
docker run -d \
--name live-restore-demo \
--restart unless-stopped \
busybox \
sh -c 'i=0; while true; do date -Iseconds; i=$((i+1)); sleep 2; done'
查看容器状态:
docker ps --filter name=live-restore-demo
然后重启 Docker:
sudo systemctl restart docker
几秒后再次查看:
docker ps --filter name=live-restore-demo
docker logs --tail 10 live-restore-demo
启用并正确工作的 Live Restore 环境中,预期现象是:
- Docker 客户端在 Daemon 重启的短时间内可能无法连接;
- Daemon 恢复后,容器仍显示为
Up; - 容器内的时间输出没有因为 Daemon 重启而重新从零开始;
- 容器 ID 不变。
可以进一步记录容器启动时间:
docker inspect -f \
'status={{.State.Status}} started={{.State.StartedAt}} restartCount={{.RestartCount}}' \
live-restore-demo
如果只是 Daemon 重启而容器进程未退出,StartedAt 通常不会被更新为一次新的容器启动时间,RestartCount 也不应因为这次 Daemon 重启而增加。
这个实验验证的是“Daemon 重启期间容器是否存活”,不是应用高可用。若应用本身在此期间崩溃,Live Restore 不会阻止它退出。
四、Live Restore 不等于宿主机重启恢复
1. 宿主机重启会销毁运行时进程
宿主机重启时,Linux 内核会停止所有用户空间进程,包括:
dockerd;- containerd;
- containerd-shim;
- 容器中的应用进程。
因此,Live Restore 的前提:
在宿主机重启时不成立。容器内进程不会跨越内核重启继续存在。
宿主机启动后,Docker Daemon 会从 Docker 数据目录读取容器元数据,例如:
- 容器配置;
- 镜像引用;
- 挂载信息;
- 重启策略;
- 网络配置;
- 容器状态记录。
随后,Docker 根据容器的重启策略决定是否重新启动容器。
2. 重启策略的形式化理解
设容器发生退出事件,退出码为 ,并且 Docker Daemon 在运行。重启策略可以粗略表示为:
no
无论容器如何退出,都不自动重启。no 是默认策略。
on-failure[:N]
其中:
- 是容器退出码;
- 是已发生的失败重启次数;
- 是可选的最大重启次数。
例如:
docker run -d \
--name retry-demo \
--restart on-failure:5 \
alpine \
sh -c 'exit 1'
该容器异常退出后最多尝试有限次数。它不表示宿主机启动时一定恢复一个此前被手动停止的容器,也不表示应用已经健康。
always
容器退出后自动启动;Daemon 启动时通常也会启动该容器。手动停止容器后,Daemon 重启可能再次启动它。
unless-stopped
行为接近 always,但如果管理员明确停止容器,Docker 会记录这一意图,Daemon 后续启动时通常不会自动启动该容器,直到再次手动启动。
创建示例:
docker run -d \
--name web \
--restart unless-stopped \
nginx:alpine
为已有容器修改策略:
docker update --restart unless-stopped web
检查策略:
docker inspect -f '{{json .HostConfig.RestartPolicy}}' web
可能得到:
{"Name":"unless-stopped","MaximumRetryCount":0}
3. Compose 中的重启策略
Compose 文件可以写:
services:
web:
image: nginx:alpine
restart: unless-stopped
ports:
- "8080:80"
启动:
docker compose up -d
这里的 restart 是 Compose 管理的容器重启策略。
不要把它与以下字段混淆:
deploy:
restart_policy:
condition: on-failure
deploy.restart_policy 主要用于 Swarm 服务部署语义;在普通的 docker compose up 场景中,不能把它当作普通 Compose 容器的等价替代。目标环境不同,生效字段也不同。
4. 重启策略的边界
重启策略只处理“容器进程退出后的再次启动”,不保证:
- 容器内数据没有丢失;
- 应用已经完成初始化;
- 依赖数据库已经可用;
- 网络路由已经恢复;
- 消息不会重复消费;
- 端口已经可以接受请求;
- 多个服务按照业务依赖顺序恢复。
例如,以下容器即使不断重启,也不能形成有效服务:
docker run -d \
--name api \
--restart always \
my-api:latest
如果 my-api 启动后立即因为数据库连接失败而退出,Docker 只会不断重复同一个失败过程。
HEALTHCHECK 也不会自动重启一个仍然运行但健康检查失败的容器。健康检查的结果主要用于状态观察和编排决策;若需要根据健康状态执行重启,必须由外部控制器、编排系统或运维逻辑明确实现。
五、Daemon 故障、容器存活和请求可用性不是同一件事
1. 运行中的容器可能继续响应请求
假设一个容器中的 HTTP 服务已经监听 0.0.0.0:8080,宿主机通过端口映射提供服务:
docker run -d \
--name http-demo \
--restart unless-stopped \
-p 8080:80 \
nginx:alpine
当 dockerd 暂时重启时,已有的容器网络 namespace、应用监听 socket 以及部分宿主机网络规则可能继续存在。因此,现有连接或新连接在某些环境下仍可能成功。
但这不是一个可以无条件扩展的保证。结果取决于:
- 容器是否仍然运行;
- 宿主机网络规则是否仍然存在;
- 使用的网络驱动;
- 连接是否依赖 Docker 内置 DNS;
- 日志驱动是否需要 Daemon;
- 外部负载均衡器如何判断后端健康;
- 应用是否依赖 Daemon API。
因此,正确的验证不是只执行:
systemctl is-active docker
而是同时测试业务路径:
curl -v http://127.0.0.1:8080/
如果 HTTP 请求在 Daemon 重启期间成功,这说明业务数据路径仍可用;如果失败,则还需要确定失败点是容器进程、网络、端口映射还是应用自身。
2. 新操作在 Daemon 不可用时不能完成
Live Restore 保留的是已有容器,而不是 Docker API 的可用性。Daemon 故障期间通常不能可靠执行:
docker run ...
docker exec ...
docker cp ...
docker inspect ...
docker logs ...
docker stop ...
docker rm ...
客户端可能直接报无法连接 Daemon;即使某些操作在恢复后可以完成,也不应假设故障期间的控制请求会被排队并自动执行。
这产生一个重要差异:
| 操作或能力 | Daemon 暂时不可用时 |
|---|---|
| 已有容器中的进程继续运行 | Live Restore 目标能力 |
| 创建新容器 | 不可用 |
| 删除容器 | 不可用 |
docker exec 进入容器 |
通常不可用 |
| 通过 Docker API 读取状态 | 不可用 |
| 应用自行访问外部数据库 | 取决于网络和依赖 |
| 宿主机直接访问已监听端口 | 可能可用,必须验证 |
Live Restore 解决的是运行面短暂保持,不是管理面持续可用。
六、Live Restore 的限制
1. 宿主机内核必须持续工作
Live Restore 不能跨越:
- 关机;
- 重启;
- 断电;
- 内核崩溃;
- 宿主机硬件故障;
- 虚拟机被底层平台强制销毁。
如果业务要求节点故障后仍可用,需要多个节点、负载均衡、编排调度或外部故障转移,而不是只依赖单机 Live Restore。
2. 容器自身退出时,Live Restore 不会“复活”它
例如:
docker run -d \
--name crash-demo \
--restart no \
busybox \
sh -c 'sleep 5; exit 1'
5 秒后容器会退出。此时即使 dockerd 完全正常,Live Restore 也没有任何作用,因为它只处理 Daemon 与运行中容器之间的关系,不负责把已退出的应用变成健康应用。
如果需要自动重启,应使用合适的 --restart 策略,但仍要通过日志和退出码调查根因。
3. 配置变更不会自动重建运行中的容器
Live Restore 期间保留的是原容器状态。修改 /etc/docker/daemon.json 后重启 Daemon,不会自动把已有容器按照所有新配置重新创建。
例如修改:
{
"log-driver": "local"
}
不会自动把旧容器已经建立的日志后端转换为新的日志配置。许多容器级配置是在创建容器时确定的,通常需要:
docker compose up -d --force-recreate
或删除后重新创建容器,才能使新配置真正作用于容器。
重新创建有数据和连接风险:
- 容器 ID 会变化;
- 容器临时可写层会丢失;
- 未挂载到卷的数据会丢失;
- 短暂停止可能导致业务中断;
- 依赖容器 IP 的配置可能失效。
4. 日志驱动存在兼容边界
容器输出的处理路径不一定完全独立于 Docker Daemon。Live Restore 对日志驱动有兼容限制,官方文档明确建议使用受支持的 json-file 或 local 日志驱动验证该能力;使用其他日志驱动时,Daemon 不可用期间的日志行为可能不同,不能假设容器和日志采集都能无缝继续。
检查当前默认日志驱动:
docker info --format '{{.LoggingDriver}}'
检查某个容器:
docker inspect -f '{{.HostConfig.LogConfig.Type}}' live-restore-demo
即使容器继续运行,也要考虑:
- 日志是否暂存在运行时缓冲区;
- 日志是否会阻塞应用;
- Daemon 恢复后是否能继续读取;
- 远程日志后端是否独立可用;
- 容器日志是否因为磁盘满而导致应用异常。
生产环境不应仅用“容器还在运行”推断“日志链路正常”。
5. Swarm 服务不是普通单机容器
Live Restore 针对 Docker Engine 管理的容器。Swarm 服务还包含:
- 服务期望状态;
- 调度器;
- 节点状态;
- overlay network;
- service task;
- manager quorum。
不能把单机容器的 Live Restore 直接等同于 Swarm 服务高可用。Swarm 的服务恢复依赖 Swarm 控制面和调度机制,必须分别验证 manager、worker、task 和网络行为。
尤其要注意:
“单机容器在 Daemon 重启时继续运行”不等于“编排系统在节点故障时完成跨节点接管”。
6. Live Restore 不是 checkpoint、快照或迁移
Live Restore 不保存一个可以在另一台机器恢复的容器内存快照。它不能直接完成:
- 把运行中的容器迁移到另一台宿主机;
- 恢复容器内存中的连接和线程;
- 在不同内核或不同架构上恢复进程;
- 从备份恢复容器的瞬时运行状态。
容器镜像、容器配置和卷数据可以被备份或重新部署,但这与进程级状态恢复是不同问题。
七、Daemon 重启与宿主机重启的故障路径对比
| 故障 | Daemon 是否可用 | 已运行容器 | 新建容器 | 是否跨越宿主机重启 |
|---|---|---|---|---|
dockerd 短暂重启,未启用 Live Restore |
暂时不可用 | 可能被停止 | 不可用 | 不适用 |
dockerd 短暂重启,启用 Live Restore |
暂时不可用 | 目标是继续运行 | 不可用 | 不适用 |
| Daemon 崩溃后恢复 | 暂时不可用 | 取决于 Live Restore、运行时和故障路径 | 恢复后可用 | 不适用 |
| 宿主机正常重启 | 重启期间不可用 | 所有进程退出 | 启动后可用 | 需要重启策略 |
| 宿主机断电或内核崩溃 | 不可用 | 所有进程丢失 | 恢复后可用 | 需要持久化和自动启动 |
| 宿主机永久损坏 | 永久不可用 | 丢失 | 需迁移或重建 | 需要多节点或备份 |
这个表中的“容器继续运行”只说明进程生命周期,不说明服务一定能够对外提供正确结果。
八、Docker 服务恢复时到底发生了什么
以配置了 unless-stopped 的容器为例,宿主机重启后的典型流程如下:
stateDiagram-v2
[*] --> Running
Running --> DaemonUnavailable: dockerd 崩溃或重启
DaemonUnavailable --> Running: Live Restore 且宿主机未重启
DaemonUnavailable --> ProcessLost: 宿主机重启/内核故障
ProcessLost --> DaemonStarting: 宿主机启动
DaemonStarting --> RestartEvaluated: dockerd 读取元数据
RestartEvaluated --> Running: 重启策略允许启动
RestartEvaluated --> Stopped: 无重启策略或曾被明确停止
Running --> Exited: 应用进程退出
Exited --> Running: 重启策略触发
Exited --> Stopped: 重启策略不触发或达到上限
宿主机重启后的恢复至少涉及四层:
- systemd 是否启动 Docker 服务;
- Docker 是否能够读取 data-root;
- 容器的重启策略是否允许启动;
- 应用依赖的卷、网络、DNS 和外部服务是否已就绪。
例如,Docker 数据目录放在单独磁盘:
{
"data-root": "/srv/docker"
}
如果 /srv/docker 对应的文件系统尚未挂载,Docker 可能启动失败,或者更危险地使用了错误的空目录。此时重启策略没有机会发挥作用,因为负责解释重启策略的 Daemon 本身没有正确启动。
因此,Daemon 配置中的 data-root、日志路径、代理、镜像源、TLS 证书和 systemd 挂载依赖,都属于恢复链路的一部分。
九、一个更完整的恢复测试
不能只测试 systemctl restart docker。建议分别验证 Daemon 重启和宿主机重启。
1. 准备测试容器
docker run -d \
--name recovery-demo \
--restart unless-stopped \
-p 18080:80 \
nginx:alpine
检查容器和策略:
docker inspect recovery-demo \
--format 'status={{.State.Status}} restart={{.HostConfig.RestartPolicy.Name}} started={{.State.StartedAt}}'
测试服务:
curl -fsS http://127.0.0.1:18080/ >/dev/null
echo $?
返回 0 表示这一次 HTTP 请求成功,不代表完整恢复流程已经验证。
2. 验证 Daemon 重启
sudo systemctl restart docker
恢复后执行:
docker inspect recovery-demo \
--format 'status={{.State.Status}} restartCount={{.RestartCount}} started={{.State.StartedAt}}'
curl -fsS http://127.0.0.1:18080/ >/dev/null
应分别关注:
- 容器是否仍为
running; restartCount是否意外增加;- 应用端口是否仍可访问;
- Daemon 日志中是否有 containerd、shim、网络或日志驱动错误。
查看 Daemon 日志:
sudo journalctl -u docker --since '-10 minutes' --no-pager
查看容器日志:
docker logs --tail 50 recovery-demo
3. 验证宿主机重启
宿主机重启是有风险的操作,必须先确认:
- 具备带外管理或控制台;
- SSH 恢复路径已验证;
- 业务可以承受测试窗口;
- 卷和关键数据已有备份;
- 不会误把生产节点从集群中永久移除。
重启:
sudo reboot
恢复后先检查服务:
systemctl is-active docker
docker info
docker ps
再检查容器:
docker inspect recovery-demo \
--format 'status={{.State.Status}} restartCount={{.RestartCount}} started={{.State.StartedAt}}'
curl -fsS http://127.0.0.1:18080/ >/dev/null
如果容器未恢复,应按顺序排查:
sudo systemctl status docker --no-pager
sudo journalctl -u docker -b --no-pager
docker inspect recovery-demo
findmnt /srv/docker
df -h
这里的 -b 表示查看本次启动周期的 systemd 日志。排查重点包括:
- Docker 是否启动失败;
- data-root 是否挂载;
- 磁盘是否满;
- 镜像和容器元数据是否可读;
- 端口是否被其他进程占用;
- restart policy 是否为
no; - 容器是否因为应用错误启动后立即退出。
十、常见误解与失败表现
误解一:启用 Live Restore 后,docker 命令仍然应该可用
错误。Live Restore 保持的是容器运行,不是 Docker API 可用。
Daemon 重启期间:
docker ps
可能失败,但容器进程仍可能继续处理现有业务流量。
误解二:有 --restart always,就不需要 Live Restore
两者触发时机不同:
- Live Restore:Daemon 暂时不可用时,尽量不停止已经运行的容器;
- restart policy:容器退出后,Daemon 负责重新启动容器。
没有 Live Restore 时,Daemon 重启可能先导致容器退出,再由 Daemon 恢复后尝试重启。这个过程会产生服务中断。restart policy 不能消除这段中断。
误解三:Live Restore 可以防止容器崩溃
错误。容器中的 PID 1 退出,容器就会退出。Live Restore 不会修复:
- 空指针崩溃;
- OOM;
- 配置错误;
- 依赖服务不可用;
- 应用主动退出;
- 容器被内核或管理员杀死。
误解四:容器恢复就等于数据恢复
错误。容器临时可写层不是可靠的数据持久化位置。需要保留的数据应放在:
- Docker volume;
- 绑定挂载的持久化文件系统;
- 外部数据库;
- 对象存储;
- 其他明确设计的持久化系统。
例如:
docker run -d \
--name db \
--restart unless-stopped \
-v db-data:/var/lib/postgresql/data \
postgres:16
即使容器因为宿主机重启而被重新创建或重新启动,卷中的数据库文件仍有机会保留。但“文件保留”不等于“数据库事务一定一致”,数据库仍然需要自己的崩溃恢复和备份机制。
误解五:depends_on 可以保证恢复顺序和服务可用
Compose 的 depends_on 可以影响容器创建或启动顺序;即使结合健康检查,也不能自动解决所有恢复问题,例如:
- 数据库端口已经打开,但还没有完成恢复;
- 应用启动后需要执行迁移;
- 外部服务尚未可用;
- 多个副本同时恢复造成资源竞争。
应用必须对依赖失败、连接重试和幂等初始化负责。
十一、Daemon 升级时的取舍
Live Restore 常被用于降低 Docker Engine 重启或升级期间的容器中断。升级前仍需区分两个风险:
- Daemon 进程暂时不可用;
- 新版本 Docker、containerd、运行时或存储驱动与现有状态不兼容。
Live Restore 只能帮助处理第一类风险,不能消除第二类风险。
升级前至少验证:
docker version
docker info
docker ps -a
docker system df
并记录:
- Docker Engine 版本;
- containerd 和 runc 版本;
- 存储驱动;
- cgroup 模式;
- 日志驱动;
data-root;- 运行中的容器及其镜像;
- Compose 文件和环境变量;
- 卷清单;
- Daemon 配置和 TLS 证书。
升级后需要验证:
docker version
docker info
docker ps
docker inspect <container>
docker logs <container>
并进行真实业务检查,而不是只确认 docker info 成功。
如果升级涉及存储驱动、cgroup、网络插件、日志插件或 Docker API 兼容性,Live Restore 不能作为“可以跳过灰度和回滚”的理由。正在运行的旧容器虽然可能继续存活,但新 Daemon 是否能够正确重新连接、展示和管理这些容器,仍取决于版本兼容性和运行时状态。
十二、生产环境中的合理组合
对于单台 Linux Docker 主机,可以把恢复能力拆成四个层次:
层次一:Daemon 短暂故障
启用:
{
"live-restore": true
}
目标是减少 dockerd 重启造成的容器中断。
层次二:容器进程退出
为适合自动恢复的服务设置:
services:
api:
image: example/api:1.2.3
restart: unless-stopped
同时保证应用能够:
- 正确处理 SIGTERM;
- 在依赖暂时不可用时重试;
- 启动过程幂等;
- 不把临时文件当作持久数据;
- 通过健康检查暴露真实状态。
层次三:宿主机重启
确保:
- Docker systemd 服务启用;
- data-root 所在文件系统先挂载;
- 容器具有正确的 restart policy;
- 卷和外部依赖可用;
- 启动后的端口和健康检查经过验证。
例如:
sudo systemctl enable docker
具体发行版可能还需要检查 containerd、网络服务或挂载单元的启动依赖。
层次四:宿主机故障
Live Restore 和 restart policy 都不能提供跨节点故障转移。此时需要:
- 多节点部署;
- 负载均衡;
- 编排系统;
- 数据复制;
- 备份和恢复演练;
- 明确的 RTO 与 RPO。
其中:
- RTO 是恢复服务所允许的最大时间;
- RPO 是可以接受的数据丢失时间窗口。
单机 Live Restore 主要改善 Daemon 级别的 RTO,不能把单机变成高可用集群。
十三、排查顺序
当“Daemon 重启后容器似乎不工作”时,不要直接执行 docker restart,否则可能覆盖原始故障证据。可以按以下顺序判断:
1. 先确认 Daemon
systemctl is-active docker
docker info
sudo journalctl -u docker -b --no-pager
2. 再确认宿主机进程和端口
ps -ef | grep '[c]ontainerd-shim'
ss -lntp
如果 Docker API 不可用,宿主机级别的进程和端口检查尤其重要。
3. Daemon 恢复后检查容器状态
docker ps -a
docker inspect <container>
重点看:
docker inspect <container> \
--format '
status={{.State.Status}}
exitCode={{.State.ExitCode}}
oomKilled={{.State.OOMKilled}}
error={{.State.Error}}
started={{.State.StartedAt}}
finished={{.State.FinishedAt}}
restartCount={{.RestartCount}}
restartPolicy={{.HostConfig.RestartPolicy.Name}}
'
4. 判断是容器退出还是应用不健康
Status=exited:容器进程已退出;Status=running但请求失败:检查应用、网络、端口和依赖;OOMKilled=true:检查内存限制和宿主机压力;restartCount持续增加:可能是启动失败循环;- Daemon 日志有日志驱动错误:检查日志路径和驱动兼容性;
- 容器运行但 DNS 失败:检查 Docker 网络和应用的 DNS 依赖。
5. 最后决定恢复动作
只有在保留证据后,才考虑:
docker logs <container>
docker restart <container>
docker compose up -d
如果需要重新创建:
docker compose up -d --force-recreate
必须先确认容器临时层中没有唯一数据,并确认重新创建不会改变关键网络、卷或证书配置。
结语
Docker Live Restore 的准确含义是:
当 Docker Daemon 暂时不可用时,尽量让已经运行的 Linux 容器进程继续存活,并在 Daemon 恢复后重新建立管理关系。
它的边界同样明确:
- 它不能跨越宿主机重启;
- 它不能防止应用自身退出;
- 它不能替代容器 restart policy;
- 它不能保证日志、DNS、网络和外部依赖都不受影响;
- 它不能提供跨节点故障转移;
- 它不能恢复未持久化的数据;
- 它不能替代 Docker Engine 升级验证和回滚方案。
因此,完整的恢复设计应当把问题拆开处理:用 Live Restore 缩短 Daemon 故障影响,用重启策略恢复退出或宿主机重启后的容器,用卷和外部存储保护数据,再用多节点和编排机制处理宿主机级故障。只有分别验证这些层次,才能知道一次“Docker 重启后服务仍然可用”究竟依赖了什么,以及在什么故障边界下会失效。
系列导航与关联阅读
- 系列入口:Docker 完整学习路线:从镜像与容器到安全、可观测和生产交付
- 上一篇:Docker User Namespace Remap:UID 映射、Volume、权限和迁移
- 下一篇:Docker Engine 升级:兼容、存储驱动、API、灰度、回滚和验证
- 延伸:Docker Daemon 配置:data-root、日志、代理、镜像源、TLS 和验证
官方资料
本文依据 Docker、OCI 与 CNCF 官方文档重新梳理;正文与生产检查清单由 WR BLOG 编写。

评论
0 条讨论