Redroid 安卓容器导致宿主机开机卡死:排查与处理
一、现象
x86 NAS(飞牛 fnOS,基于 Debian 12)部署 Redroid(Android-in-Docker)容器后:
- 系统反复重启,间隔约 20 分钟
- 无法完成引导,卡在 systemd 启动阶段
- 禁用 Docker 服务后,系统可正常引导
二、环境信息
| 项目 | 值 |
|---|---|
| 操作系统 | 飞牛 fnOS(基于 Debian 12) |
| 内核 | 6.18.18.c1126-trim(x86_64) |
| Docker 数据根目录 | /vol1/docker(由 /etc/docker/daemon.json 的 data-root 指定) |
| 容器 | octop-mobile-android,镜像 redroid/redroid:13.0.0-latest |
| 存储 | LVM + Btrfs |
| 网络 | OVS 网桥 |
三、排查过程
3.1 内核与硬件层检查
sudo sh -c 'zcat -f /var/log/syslog* /var/log/kern.log* | \
grep -aiE "kernel panic|Oops|BUG: |segfault|oom-kill|Hardware Error|hung task"'
| 检查项 | 结果 |
|---|---|
| kernel panic / Oops / BUG | 无 |
| OOM / oom-kill | 无 |
| Hardware Error / MCE | 无 |
| 磁盘 I/O 错误 | 无 |
/sys/fs/pstore |
空 |
/var/crash |
仅历史遗留目录 |
| systemd-coredump | 无 core 文件 |
| 温度 | 硬盘 32–35 °C,GPU 41 °C |
内核层无崩溃、内存耗尽、硬件故障与掉电记录。
3.2 重启来源分析
每次重启前,syslog 中存在完整的服务停止序列:

崩溃或掉电会造成日志中断,不会输出该序列,因此关机流程均正常执行。
比对 shell 历史(HISTFILE 带时间戳)与 syslog:

时间戳 1791435437 对应 2026-10-08 12:57:17,与 syslog 中 Stopping session-1.scope(12:57:17.258)一致。
auth.log 中的操作记录:
sudo: <user> : TTY=tty1 ; COMMAND=/usr/sbin/reboot
另有一条 systemd[1]: Received SIGINT,对应物理键盘的 Ctrl+Alt+Del 事件。
3.3 Docker 服务配置
禁用 Docker 后系统可正常引导,问题范围收敛至 Docker 启动流程。
/etc/systemd/system/docker.service:
[Unit]
Wants=ovsdb-server.service ovs-vswitchd.service
Requires=containerd.service
After=containerd.service ovsdb-server.service ovs-vswitchd.service ...
[Service]
Type=simple
TimeoutStartSec=0
Restart=on-failure
ExecStart=/usr/bin/dockerd ...
TimeoutStartSec=0 表示 systemd 不对该服务设置超时。
/etc/docker/daemon.json:
{
"data-root": "/vol1/docker",
"live-restore": true,
"log-driver": "json-file"
}
live-restore: true 使 dockerd 启动时尝试恢复上次运行的容器。
3.4 容器运行参数
hostconfig.json:
"Privileged": true,
"NetworkMode": "host",
"SecurityOpt": ["label=disable"],
"RestartPolicy": {"Name": "unless-stopped"},
"Binds": ["/dev/binderfs:/dev/binderfs"]
参数含义:
Privileged: true:容器内进程拥有宿主机全部能力NetworkMode: host:容器与宿主机共享网络命名空间,容器内 Android 系统的 netd 可直接修改宿主机路由表与 iptables 规则RestartPolicy: unless-stopped:dockerd 启动时自动拉起该容器
3.5 开机卡死的事件链
- 开机后 systemd 启动 containerd,随后启动
docker.service - dockerd 因
live-restore尝试恢复上次运行的容器 - 该容器因
unless-stopped策略被拉起 - 容器 bind 挂载源
/dev/binderfs不存在:/dev为 tmpfs,每次开机清空,系统中没有任何单元负责挂载 binderfs - 容器启动失败,dockerd 反复重试
TimeoutStartSec=0使 systemd 持续等待docker.service,引导流程无法完成
binderfs 状态与内核支持:
$ ls -la /dev/binderfs
ls: cannot access '/dev/binderfs': No such file or directory
$ grep -iE 'BINDER' /boot/config-$(uname -r)
CONFIG_ANDROID_BINDER_IPC=y
CONFIG_ANDROID_BINDERFS=y
CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder"
内核已内置 binderfs 支持(功能编译进内核而非模块,故 lsmod 中无 binder 条目),但没有任何单元在开机时挂载它。
四、处理步骤
以下操作在 Docker 停止状态下执行。
4.1 修改容器元数据
hostconfig.json:
"RestartPolicy": {"Name": "no", "MaximumRetryCount": 0}
config.v2.json:
"State": {"Running": false, "Pid": 0, ...}
使用 Python 修改并校验 JSON:
python3 -c '
import json
p="/vol1/docker/containers/<ID>/hostconfig.json"
d=json.load(open(p))
d["RestartPolicy"]={"Name":"no","MaximumRetryCount":0}
open(p,"w").write(json.dumps(d,separators=(",",":")))
'
修改前备份原始配置;修改后确认文件属主与权限(-rw------- root root)未变化。
4.2 部署网络守护脚本
#!/bin/bash
LOG=/root/net-guard.log
GW=<网关地址>
for i in $(seq 1 16); do
bad=0
ip route | grep -q "^default via ${GW} dev <主网卡>" || bad=1
ping -c 2 -W 2 "${GW}" >/dev/null 2>&1 || bad=1
if [ "$bad" != "0" ]; then
systemctl stop docker >> "$LOG" 2>&1
exit 1
fi
sleep 30
done
注册为独立定时任务,不依赖 SSH 会话:
systemd-run --unit=net-guard --on-active=25 /root/net-guard.sh
4.3 启动 Docker 并验证容器状态
timeout 150 systemctl start docker
dockerd 3 秒内就绪。
docker inspect -f '{{.Name}} Running={{.State.Running}} Status={{.State.Status}} RestartPolicy={{.HostConfig.RestartPolicy.Name}}' octop-mobile-android
/octop-mobile-android Running=false Status=exited RestartPolicy=no
dockerd 未拉起该容器,路由表与操作前一致。
4.4 删除容器与镜像
docker rm octop-mobile-android
docker rmi redroid/redroid:13.0.0-latest
Untagged: redroid/redroid:13.0.0-latest
Untagged: redroid/redroid@sha256:41e5f0c1ff27...
Deleted: sha256:439b3b1f65db...
Deleted: sha256:ec5b33f9a2b3...
/vol1/docker 占用由 14 GB 降至 12 GB。
4.5 清理应用数据
数据目录占用 2.2 GB:
| 子目录 | 大小 |
|---|---|
.cache(uv 1.3 GB + pip 214 MB) |
1.5 GB |
.local |
405 MB |
.octop |
296 MB |
.octop-browser |
23 MB |
.android |
3.6 MB |
清理前备份配置文件并生成文件清单。
应用本体及其 3 个 systemd 单元一并卸载。该应用的 sudoers 配置为:
Defaults:<user> !requiretty
<user> ALL=(ALL) NOPASSWD: ALL
该文件一并移除,并通过 visudo -c 校验 sudo 配置。
五、容器挂载源审计
校验全部容器的 bind 挂载源是否存在:
- 读取
config.v2.json的MountPoints[].Source - 读取
hostconfig.json的Binds
结果:20 条 MountPoints 与 19 条 Binds 的宿主机源路径全部存在;无容器引用 /dev/binderfs。
MountPoints 的 key 是容器内目标路径,宿主机路径是 Source 字段。
六、重启验证
重启前 boot_id : 940764e6-55bf-47a1-8e35-e60bd66b3c4d
重启后 boot_id : b831d887-4315-457b-836c-b1a350438e3d
Startup finished in 17.111s (firmware) + 9.500s (loader) + 3.728s (kernel)
+ 28.284s (userspace) = 58.724s
graphical.target reached after 28.258s in userspace.

| 检查项 | 结果 |
|---|---|
| 运行容器数 | 13 |
| 默认路由数 | 2 |
| 安卓 / redroid 残留 | 0 |
| failed 单元 | 仅 nut-server |
七、根因
- 日志中不存在内核 panic、OOM 与硬件错误记录
- 引导阻塞由
docker.service的TimeoutStartSec=0、容器unless-stopped重启策略、live-restore机制共同造成 - 容器使用
Privileged: true与NetworkMode: host,可修改宿主机路由表与 iptables 规则 - 阻断路径:在 Docker 停止状态下将容器
RestartPolicy置为no,使 dockerd 启动时不拉起该容器
附录:相关命令
# 崩溃关键字全量扫描(含归档)
sudo sh -c 'zcat -f /var/log/syslog* /var/log/kern.log* | \
grep -aiE "kernel panic|Oops|BUG: |segfault|oom-kill|Hardware Error|hung task"'
# 段错误统计
sudo grep -ac segfault /var/log/kern.log
# 重启与关机历史
last -x -F reboot shutdown
# 关机触发来源
sudo grep -aE "Received SIG" /var/log/syslog
# 重启命令审计
sudo grep -aE "COMMAND=.*(reboot|poweroff)" /var/log/auth.log
# 查看容器完整运行参数
docker inspect -f '{{json .HostConfig}}' <容器名> | python3 -m json.tool
# 校验容器挂载源
docker inspect -f '{{range .Mounts}}{{.Source}} -> {{.Destination}}{{"\n"}}{{end}}' <容器名>