设备:绿联私有云DH2100(Realtek RTD1296 / ARM Cortex‑A53 四核 1.4GHz /aarch64 64 位/ 2GB DDR4 / 8GB eMMC / 千兆)
系统:UGOS 18.06(⚠️ 不是 Debian,也不是 UGOS Pro)
成果:Docker 24.0.9 跑起来 + MediaGo原生 arm64(不用 qemu 模拟)+ 下载直接落 NAS 自己的硬盘
网上关于 DH2100 能不能装 Docker 的说法非常混乱,有说不支持的、有说 x86 处理器+2.5G 网口的(跟官方参数完全不符)。这篇是在我自己机器上一步步实测通过的完整记录,包括三个别人没提过的致命坑。
一、先搞清楚你面对的是什么系统
开启 SSH 登录后第一条命令:
cat/etc/os-release# NAME="UGOS"# VERSION="18.06-SNAPSHOT" ← 这个版本号是 OpenWrt 的命名习惯uname-a# Linux UGREEN-xxxx 4.9.119 #0 SMP PREEMPT ... aarch64 GNU/Linuxdf-h# /rom 243.8M 243.8M 0 100% /rom ← OpenWrt 典型特征# /overlay 5.1G 932.6M 3.9G 19% /overlay# /dev/md0 9.0T 7.7T 877G 90% /mnt/md0 ← 你的数据盘# /dev/md1 9.0T 172.8G 8.4T 2% /mnt/md1结论:UGOS 是基于 OpenWrt 18.06 定制的嵌入式系统,这决定了后面所有做法:
| 特性 | 影响 |
|---|---|
| 无 apt / dpkg / opkg / yum | ❌ 不能apt install docker,只能用静态二进制 |
| busybox ash(无 nohup、无 setsid) | 守护进程要用start-stop-daemon -b |
busybox 的timeout是旧语法 | 要写timeout -t 60 cmd,不是timeout 60 cmd |
| wget 直接 Segmentation fault | 下载别用它,用 scp 或容器内的网络栈 |
| 内核 4.9.119,未编译 POSIX mqueue | ⚠️ 最大的坑,见第四节 |
二、拿到 root:端口是 922,不是 22
绿联的「远程调试」开启后,SSH 端口是922:
ssh-p922<你的账号>@192.168.0.101# 普通账号能进,但不在 sudoers,提不了权ssh-p922root@192.168.0.101# ← 要用这个root 密码就是 UGOS 调试页面给的验证码(一般 3 天有效)。登进去确认:
id# uid=0(root) gid=0(root) groups=0(root),1023(media_rw)坑 1:用普通账号登录后会发现
sudo存在(且是 setuid root),但会告诉你xxx is not in sudoers file。而且sudo 不带 TTY 时是静默失败的——不加-tt你什么都看不到,
很容易误判为"sudo 卡住了"。
三、装 Docker(静态二进制方案)
1. 选版本:别用最新的
4.9 内核配 Docker 29 太激进,**Docker 24.0.9(containerd 1.7)**是最稳的。
# 在本机下载(阿里云镜像),再 scp 上去,因为 NAS 上的 wget 是坏的curl-LOhttps://mirrors.aliyun.com/docker-ce/linux/static/stable/aarch64/docker-24.0.9.tgzscp-P922docker-24.0.9.tgz root@192.168.0.101:/mnt/md1/2. 解压到 /usr/local
ssh-p922root@192.168.0.101cd/usr/local&&tarxzf /mnt/md1/docker-24.0.9.tgz /usr/local/docker/dockerd--version# Docker version 24.0.93. 关键启动参数
UGOS 自带 OpenWrt 的fw3 防火墙,不能让 Docker 乱改 iptables;内核也没有 bridge/veth 模块。
exportPATH=/usr/local/docker:/usr/bin:/bin:/usr/sbin:/sbin /sbin/start-stop-daemon-S-b-x/usr/local/docker/dockerd --\--data-root=/mnt/md1/docker\--exec-root=/var/run/docker\--pidfile=/var/run/docker.pid\--iptables=false--ip6tables=false\--bridge=none--data-root=/mnt/md1/docker:镜像容器全放数据盘(那块有 8.4T)--iptables=false:不碰防火墙规则--bridge=none:不建 docker0 ⇒代价:容器必须用--network hoststart-stop-daemon -b:因为没有 nohup
4. 配国内镜像源
/etc/docker/daemon.json:
{"registry-mirrors":["https://docker.1ms.run","https://docker.m.daocloud.io"]}注意:NAS 本身的 DNS 是通的,但
registry-1.docker.io会被污染解析到 31.13.95.34,
所以必须配加速源才能 pull。
四、⭐ 致命坑:内核没有 mqueue,容器一律起不来
满怀信心执行:
dockerrun--rm--networkhostalpineechohi报错:
runc create failed: unable to start container process: error mounting "mqueue" to rootfs at "/dev/mqueue": no such device原因:内核没编译CONFIG_POSIX_MQUEUE。验证一下,全是死路:
grepmqueue /proc/filesystems# 没有ls/proc/sys/fs/mqueue# 不存在find/lib/modules-iname"*mqueue*"# 无对应模块(mqueue 本身也不是可加载模块)--ipc=host、--privileged全都绕不过,因为 runc 无条件会挂/dev/mqueue。
解法:给 runc 套一层壳
把真正的 runc 改名,用一个脚本顶替它的位置,在创建容器前把 OCI spec 里的 mqueue 挂载改成 tmpfs(等价占位):
cd/usr/local/dockermvrunc runc.realcat>runc<<'EOF' #!/bin/sh REAL_RUNC=/usr/local/docker/runc.real BUNDLE="" prev="" for a in "$@"; do if [ "$prev" = "--bundle" ]; then BUNDLE="$a"; fi prev="$a" done if [ -n "$BUNDLE" ] && [ -f "$BUNDLE/config.json" ]; then sed -i 's/"type":[[:space:]]*"mqueue"/"type":"tmpfs"/g; s/"source":[[:space:]]*"mqueue"/"source":"tmpfs"/g' "$BUNDLE/config.json" fi exec "$REAL_RUNC" "$@" EOFchmod+x runc然后重启 dockerd(让 containerd 走新的 runc),再试:
dockerrun--rm--networkhostalpine:3.19uname-m# aarch64 ✅ 成功副作用:容器内 POSIX 消息队列不可用(绝大多数应用不受影响)。
UGOS 升级固件后需要重打这个补丁。
五、原生 arm64 跑 MediaGo(不用 qemu)
MediaGo 官方镜像caorushizi/mediago:3.5.0有个著名的架构 bug:
/usr/local/bin/mediago-core -> x86-64 ← 唯一的异类 /app/deps/aria2c -> arm64 ← 其余依赖都是原生 /app/deps/ffmpeg -> arm64 /app/deps/yt-dlp -> arm64 /app/deps/N_m3u8DL-RE -> arm64在树莓派上通用解法是装 qemu 模拟。但在绿联这台没有包管理器的机器上装 qemu 很麻烦,
更好的办法:只替换那个唯一的 x86-64 主程序。
把它准备好的arm64 版 mediago-core传上去,然后挂载覆盖:
scp-P922mediago-core-arm64 root@192.168.0.101:/mnt/md1/mediago-core-arm64⚠️ 坑 3:entrypoint 会硬塞参数
镜像的docker-entrypoint.sh长这样:
execmediago-core\--port=8899\--static-dir=/app/static\# ← arm64 版主程序不认这个 flag--enable-auth\# ← 还会强制打开鉴权--db-path=... --config-dir=... --local-dir=... --deps-dir=/app/deps\"$@"所以即使你在docker run后面写自己的参数,它追加的--static-dir依然存在,
arm64 主程序会直接罢工:flag provided but not defined: -static-dir。
解法:用--entrypoint直接指定主程序,完全绕过这个脚本(连--enable-auth也一并绕掉,实现免登录):
dockerrun-d--namemediago\--networkhost--restartunless-stopped\-eTZ=Asia/Shanghai\--entrypoint/usr/local/bin/mediago-core\-v/mnt/md1/mediago-core-arm64:/usr/local/bin/mediago-core:ro\-v/mnt/md1/mediago/data:/app/mediago/data\-v/mnt/md1/mediago/logs:/app/mediago/logs\-v/mnt/md0/.ugreen_nas/25507/downloads/mediago:/app/mediago/downloads\docker.1ms.run/caorushizi/mediago:3.5.0\--port=8899\--db-path=/app/mediago/data/mediago.db\--config-dir=/app/mediago/data\--log-dir=/app/mediago/logs\--local-dir=/app/mediago/downloads\--deps-dir=/app/deps
-static-dir这一条要从参数里去掉(arm64 版主程序的 flag 列表里没有它,
用--help可以核对:-config-dir -db-path -deps-dir -enable-auth -local-dir -log-dir -log-level -max-runner -port -proxy -schema-path -use-proxy)。
其中/mnt/md0/.ugreen_nas/25507就是你的 SMB 共享根目录
(从/etc/config/samba4里option path查得到),
所以下载的文件会直接出现在 NAS 正常的文件管理里,不用再绕一层网络挂载。
六、验证(每条都要做)
# 1. 容器是否稳定dockerps# mediago Up 2 minutes# 2. Web 是否可访问curl-s-o/dev/null-w"%{http_code}\n"http://192.168.0.101:8899/# 200# 3. 是否免登录curl-shttp://192.168.0.101:8899/api/auth/status# {"data":{"setuped":false}} ← false 才是免登录# 4. 下载器是否真的能执行(原生 arm64)dockerexecmediago /app/deps/aria2c--version# aria2 version 1.36.0dockerexecmediago /app/deps/ffmpeg-version# ffmpeg version 6.0# 5. ⭐ 落盘闭环:容器内写 → NAS 共享里真的出现dockerexecmediagosh-c'echo ok > /app/mediago/downloads/_t.txt'cat/mnt/md0/.ugreen_nas/25507/downloads/mediago/_t.txt# 必须能读到七、日常使用 & 已知限制
/usr/local/docker-up# 启动 Docker daemon(UGOS 无 systemd,不会自启)/usr/local/mediago-up# 启动 MediaGo(会顺带拉起 dockerd)限制清单一览:
| 项目 | 说明 |
|---|---|
| 开机自启 | 需自己在/etc/init.d/写 OpenWrt 服务脚本,UGOS 升级可能被覆盖 |
| 容器网络 | 必须--network host,不能用-p端口映射(bridge 被关掉) |
| 内存 | 实测 1552MB,跑 MediaGo 后剩 ~720MB,只适合轻量容器,别跑转码类 |
| 远程调试 | 验证码 3 天过期,过期后 SSH 进不去,需要重新生成 |
| 保修 | 官方不承诺这类玩法,理论上存在风险;所有文件都在/usr/local、/mnt/md1下,可完整回滚:删掉那几个目录即可,没有动过 UGOS 系统文件 |