OpenWrt 从U盘迁移到内置 eMMC,并完成扩容与 Docker 安装

OpenWrt 从U盘迁移到内置 eMMC,并完成扩容与 Docker 安装

一、前言

很多 x86 软路由设备出厂时带有一块容量有限的 eMMC,安装 OpenWrt 时,通常先将固件写入U盘,再从U盘启动系统。

确认固件能够正常运行后,可以进一步完成以下操作:

  1. 将U盘中的 OpenWrt 系统写入内置 eMMC;
  2. 修复克隆镜像后出现的 GPT 分区表警告;
  3. 利用 eMMC 剩余空间扩容 /overlay
  4. 单独创建 /opt 分区存放 Docker 数据;
  5. 安装 Docker 和 LuCI 可视化管理界面;
  6. 配置日志、资源限制和数据备份。

OpenWrt 可以通过 extroot 将独立存储分区作为新的可写层,从而扩展软件包和系统配置空间;Docker 则可以通过 luci-app-dockerman 集成到 LuCI 管理后台。

本文采用的实际环境如下:

项目 配置
启动U盘 /dev/sda
内置 eMMC /dev/mmcblk0
eMMC 容量 约 29.12 GiB
固件类型 x86-64、SquashFS、UEFI
固件文件 openwrt-gdq-version-v1[2025]-x86-64-generic-squashfs-uefi.img.gz
固件保存位置 /overlay
包管理器 opkg
建议 /overlay 容量 4 GiB
建议 /opt 容量 剩余全部空间,约 24 GiB

严重警告:

本文中的 ddmkfs.ext4 和分区操作会直接覆盖磁盘数据。

执行前必须确认:

  • /dev/sda 是启动U盘;
  • /dev/mmcblk0 是准备安装系统的内置 eMMC。

一旦目标磁盘写错,原有数据通常无法恢复。


二、整体磁盘规划

固件写入 eMMC 后,镜像本身只创建了大约 1 GiB 的系统分区,但 eMMC 总容量接近 30 GiB。

本文最终采用以下分区结构:

分区 大小 用途
/dev/mmcblk0p1 16 MiB 固件已有系统分区,不修改
/dev/mmcblk0p2 1 GiB 固件已有系统分区,不修改
/dev/mmcblk0p128 约 239 KiB 启动相关分区,不修改
/dev/mmcblk0p3 4 GiB 新的 /overlay
/dev/mmcblk0p4 剩余空间 /opt,存放 Docker 数据

其中:

  • /overlay 存放 OpenWrt 的配置、插件和后续安装的软件包;
  • /opt 存放 Docker 镜像、容器、数据卷和应用配置;
  • 原有的 p1p2p128 均不得删除或格式化。

三、从U盘启动 OpenWrt

先将 OpenWrt 固件写入U盘,并让软路由从U盘启动。

进入系统后,通过 SSH 登录:

bash 复制代码
ssh root@192.168.1.1

具体 IP 地址应以当前 OpenWrt 的 LAN 地址为准。

登录后确认磁盘:

bash 复制代码
lsblk -o NAME,SIZE,MODEL,TYPE,FSTYPE,MOUNTPOINTS

如果没有 lsblk,可以使用:

bash 复制代码
fdisk -l

本教程的识别结果为:

text 复制代码
/dev/sda       启动U盘
/dev/mmcblk0   内置 eMMC

再次确认内置盘容量:

bash 复制代码
fdisk -l /dev/mmcblk0

只有确认目标磁盘是 /dev/mmcblk0 后,才能继续。


四、上传 OpenWrt 镜像

通过 OpenWrt 文件管理器、SCP 或其他方式,将固件上传到:

text 复制代码
/overlay

完整路径为:

text 复制代码
/overlay/openwrt-gdq-version-v1[2025]-x86-64-generic-squashfs-uefi.img.gz

检查文件是否存在:

bash 复制代码
ls -lh '/overlay/openwrt-gdq-version-v1[2025]-x86-64-generic-squashfs-uefi.img.gz'

由于文件名中包含方括号:

text 复制代码
[2025]

Shell 可能将其识别为通配符,因此命令中必须使用单引号或双引号。

建议先检查压缩包完整性:

bash 复制代码
gzip -t '/overlay/openwrt-gdq-version-v1[2025]-x86-64-generic-squashfs-uefi.img.gz'

如果命令没有输出错误,说明压缩包结构正常。

也可以将文件改成简单名称:

bash 复制代码
mv '/overlay/openwrt-gdq-version-v1[2025]-x86-64-generic-squashfs-uefi.img.gz' \
   /overlay/openwrt.img.gz

后续就可以使用:

text 复制代码
/overlay/openwrt.img.gz

本文仍保留原始文件名进行演示。


五、将系统写入内置 eMMC

1. 卸载 eMMC 原有分区

执行:

bash 复制代码
umount /dev/mmcblk0p* 2>/dev/null

检查是否还有 eMMC 分区处于挂载状态:

bash 复制代码
mount | grep mmcblk0

如果没有输出,即可继续。

2. 直接解压并写入

不需要提前使用 gzip -d 解压整个镜像,可以采用管道方式边解压边写入:

bash 复制代码
gzip -dc '/overlay/openwrt-gdq-version-v1[2025]-x86-64-generic-squashfs-uefi.img.gz' \
  | dd of=/dev/mmcblk0 bs=4M

完成后执行:

bash 复制代码
sync

这里必须写入整块 eMMC:

text 复制代码
正确:/dev/mmcblk0
错误:/dev/mmcblk0p1
错误:/dev/sda

写入过程中可能看到:

text 复制代码
0+33168 records in
0+33168 records out

这不代表写入了 0 字节。由于数据是通过 gzip 管道分块传递给 dd,会出现大量不完整块记录。

3. 检查写入结果

执行:

bash 复制代码
fdisk -l /dev/mmcblk0

正常情况下会识别出类似:

text 复制代码
/dev/mmcblk0p1
/dev/mmcblk0p2
/dev/mmcblk0p128

说明镜像已经写入 eMMC。


六、处理 GPT 分区表警告

将一个约 1 GiB 的磁盘镜像写入 29 GiB eMMC 后,可能出现:

text 复制代码
GPT PMBR size mismatch
The backup GPT table is corrupt
The backup GPT table is not on the end of the device

原因是镜像中的备用 GPT 表仍位于原镜像末尾,而不是当前 eMMC 的真正末尾。

这通常不代表镜像损坏。

执行:

bash 复制代码
fdisk /dev/mmcblk0

进入 fdisk 后,可以先输入:

text 复制代码
p

查看当前分区表。

确认 p1p2p128 均正常后,输入:

text 复制代码
w

写回分区表。

然后执行:

bash 复制代码
sync
reboot

重启后再次检查:

bash 复制代码
fdisk -l /dev/mmcblk0

GPT 尾表位置相关警告通常会消失。

即使仍然看到:

text 复制代码
Partition table entries are not in disk order

一般也不影响启动。这是因为编号为 p128 的启动分区实际位于磁盘前部,导致分区编号顺序和物理位置顺序不同。


七、从内置 eMMC 启动

执行:

bash 复制代码
poweroff

设备完全关机后:

  1. 拔掉启动U盘;
  2. 重新开机;
  3. 进入 BIOS;
  4. 将启动模式设置为 UEFI;
  5. 将 eMMC、MMC 或内置磁盘设置为第一启动项;
  6. 如果无法启动,可以尝试关闭 Secure Boot。

系统启动后再次登录 SSH,并检查:

bash 复制代码
lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINTS

也可以检查:

bash 复制代码
mount | grep -E ' /rom | /overlay '

此时必须确认当前系统已经从 /dev/mmcblk0 启动,而不是仍然从 /dev/sda 启动。

不要在U盘系统中迁移 /overlay

否则复制的是U盘系统的可写层,而不是刚刚安装到 eMMC 中的系统。


八、创建 /overlay/opt 分区

1. 进入 cfdisk

执行:

bash 复制代码
cfdisk /dev/mmcblk0

进入界面后,应该能看到原有分区以及大约 28 GiB 的:

text 复制代码
Free space

2. 创建 /overlay 分区

使用上下方向键选中 Free space,然后:

  1. 使用左右方向键选择 [ New ]
  2. 按回车;
  3. 输入大小:
text 复制代码
4G
  1. 按回车;
  2. 类型保持为:
text 复制代码
Linux filesystem

正常情况下会生成:

text 复制代码
/dev/mmcblk0p3

3. 创建 /opt 分区

继续选中剩余的 Free space

  1. 选择 [ New ]
  2. 使用默认大小,占满所有剩余空间;
  3. 按回车;
  4. 类型保持 Linux filesystem

正常情况下会生成:

text 复制代码
/dev/mmcblk0p4

4. 写入分区表

选择:

text 复制代码
[ Write ]

按回车后,输入完整的:

text 复制代码
yes

然后选择:

text 复制代码
[ Quit ]

退出。

重启系统:

bash 复制代码
reboot

5. 检查分区

重启后执行:

bash 复制代码
lsblk -o NAME,SIZE,FSTYPE,LABEL,MOUNTPOINTS /dev/mmcblk0

预期结构类似:

text 复制代码
mmcblk0          29.1G
├─mmcblk0p1        16M
├─mmcblk0p2         1G
├─mmcblk0p3         4G
├─mmcblk0p4        24G
└─mmcblk0p128     239K

九、格式化新分区

检查工具是否存在:

bash 复制代码
command -v mkfs.ext4
command -v block

如果缺少相关工具,可尝试安装:

bash 复制代码
opkg update
opkg install block-mount e2fsprogs

格式化 /overlay 分区:

bash 复制代码
mkfs.ext4 -F -m 0 -L extroot /dev/mmcblk0p3

格式化 /opt 分区:

bash 复制代码
mkfs.ext4 -F -m 0 -L opt /dev/mmcblk0p4

其中:

text 复制代码
-F

表示确认创建文件系统;

text 复制代码
-m 0

表示不为 root 额外预留默认百分比的磁盘空间。

检查结果:

bash 复制代码
block info /dev/mmcblk0p3
block info /dev/mmcblk0p4

应当看到类似:

text 复制代码
/dev/mmcblk0p3: UUID="..." LABEL="extroot" TYPE="ext4"
/dev/mmcblk0p4: UUID="..." LABEL="opt" TYPE="ext4"

十、迁移并扩容 /overlay

/overlay 是 OpenWrt 的可写层,不能直接把一个空分区挂载到 /overlay

如果直接挂载空分区,当前软件包、配置和可写数据会被空目录遮住。

正确流程是:

  1. 临时挂载新分区;
  2. 复制现有 /overlay
  3. 配置开机挂载;
  4. 重启切换。

OpenWrt 官方 extroot 流程也是将新存储配置为 /overlay,并在重启后让系统使用新的可写分区。

1. 临时挂载新分区

执行:

bash 复制代码
mkdir -p /mnt/new_overlay
mount -t ext4 /dev/mmcblk0p3 /mnt/new_overlay

检查:

bash 复制代码
df -hT /mnt/new_overlay

2. 复制现有 overlay

执行:

bash 复制代码
tar -C /overlay -cf - . | tar -C /mnt/new_overlay -xf -

复制完成后检查:

bash 复制代码
ls -la /mnt/new_overlay

通常可以看到:

text 复制代码
upper
work

同步数据:

bash 复制代码
sync

然后卸载:

bash 复制代码
umount /mnt/new_overlay

3. 获取 UUID

执行:

bash 复制代码
OVERLAY_UUID="$(block info /dev/mmcblk0p3 \
  | sed -n 's/.*UUID="\([^"]*\)".*/\1/p')"

echo "$OVERLAY_UUID"

必须能看到一串 UUID,例如:

text 复制代码
12345678-abcd-1234-abcd-123456789abc

如果输出为空,不要继续配置。

4. 检查旧挂载配置

执行:

bash 复制代码
uci show fstab 2>/dev/null | grep "target='/overlay'"

如果没有输出,说明当前没有旧的显式 /overlay 挂载项。

如果存在旧条目,应当禁用或删除对应的旧配置,再创建新的 extroot 条目。

不要在系统运行过程中执行:

bash 复制代码
umount /overlay

因为当前系统正在使用 /overlay

5. 添加 extroot 配置

执行:

bash 复制代码
uci -q delete fstab.extroot

uci set fstab.extroot='mount'
uci set fstab.extroot.uuid="$OVERLAY_UUID"
uci set fstab.extroot.target='/overlay'
uci set fstab.extroot.fstype='ext4'
uci set fstab.extroot.options='rw,noatime'
uci set fstab.extroot.enabled='1'
uci set fstab.extroot.enabled_fsck='1'

uci commit fstab

启用挂载服务:

bash 复制代码
/etc/init.d/fstab enable

不要在当前系统中立即重启挂载服务,以免空分区或错误配置直接覆盖现有 /overlay

直接重启:

bash 复制代码
reboot

6. 验证扩容

重启后执行:

bash 复制代码
df -hT /
df -hT /overlay

再检查挂载关系:

bash 复制代码
mount | grep -E ' /overlay |overlayfs'

检查分区:

bash 复制代码
lsblk -o NAME,SIZE,FSTYPE,LABEL,MOUNTPOINTS /dev/mmcblk0

成功后,根目录或 /overlay 的可用空间应接近 4 GiB。

同时确认:

  • LuCI 可以正常访问;
  • 网络配置仍然存在;
  • 已安装插件没有丢失;
  • 重启后设置能够保存。

确认 /overlay 正常后,再继续配置 /opt


十一、挂载 /opt

1. 临时挂载

创建目录:

bash 复制代码
mkdir -p /opt
mkdir -p /mnt/new_opt

挂载新分区:

bash 复制代码
mount -t ext4 /dev/mmcblk0p4 /mnt/new_opt

2. 复制现有 /opt

即使当前 /opt 为空,也可以执行:

bash 复制代码
tar -C /opt -cf - . | tar -C /mnt/new_opt -xf -

同步并卸载:

bash 复制代码
sync
umount /mnt/new_opt

3. 获取 UUID

执行:

bash 复制代码
OPT_UUID="$(block info /dev/mmcblk0p4 \
  | sed -n 's/.*UUID="\([^"]*\)".*/\1/p')"

echo "$OPT_UUID"

确认 UUID 不为空。

4. 配置自动挂载

执行:

bash 复制代码
uci -q delete fstab.opt

uci set fstab.opt='mount'
uci set fstab.opt.uuid="$OPT_UUID"
uci set fstab.opt.target='/opt'
uci set fstab.opt.fstype='ext4'
uci set fstab.opt.options='rw,noatime'
uci set fstab.opt.enabled='1'
uci set fstab.opt.enabled_fsck='1'

uci commit fstab

重启:

bash 复制代码
reboot

5. 验证 /opt

执行:

bash 复制代码
df -hT /opt

查看挂载来源:

bash 复制代码
mount | grep ' /opt '

预期类似:

text 复制代码
/dev/mmcblk0p4 on /opt type ext4

再综合检查:

bash 复制代码
df -hT / /overlay /opt

正常情况下:

text 复制代码
/ 或 /overlay     约 4G
/opt             约 24G

十二、安装 Docker

1. 检查软件源

执行:

bash 复制代码
cat /etc/openwrt_release
uname -r
opkg print-architecture

更新软件列表:

bash 复制代码
opkg update

检查 Docker 软件包:

bash 复制代码
opkg list | grep -E '^(dockerd|docker |luci-app-dockerman)'

2. 安装 Docker 和管理界面

执行:

bash 复制代码
opkg install dockerd docker luci-app-dockerman

OpenWrt 官方 Docker 主机文档提供了 luci-app-dockerman 作为 LuCI 管理客户端;具体依赖关系会随固件分支和软件源版本变化,因此本文显式安装 Docker 服务端、客户端和 LuCI 插件。

如果还需要 Compose,并且软件源中存在,可以安装:

bash 复制代码
opkg install docker-compose

如果提示:

text 复制代码
Unknown package 'docker-compose'

可以暂时跳过,不影响普通 Docker 容器运行。

如果提示:

text 复制代码
Unknown package 'dockerd'

通常说明:

  • 软件源失效;
  • 固件和软件源版本不一致;
  • 当前定制固件没有提供 Docker 软件包;
  • 内核模块和仓库版本不匹配。

不要从不明来源下载其他版本的 kmod-* 或 Docker .ipk 强制安装。更稳妥的方法是使用与当前固件内核完全匹配的软件源,或更换已经包含 Docker 的同类固件。


十三、设置 Docker 数据目录

创建 Docker 数据目录:

bash 复制代码
mkdir -p /opt/docker

查看当前配置:

bash 复制代码
cat /etc/config/dockerd

或者:

bash 复制代码
uci show dockerd

将 Docker 根目录设置为:

text 复制代码
/opt/docker/

执行:

bash 复制代码
uci set dockerd.globals.data_root='/opt/docker/'
uci commit dockerd

启用并启动 Docker:

bash 复制代码
/etc/init.d/dockerd enable
/etc/init.d/dockerd restart

检查状态:

bash 复制代码
docker version
docker info

重点查看:

bash 复制代码
docker info | grep -E 'Storage Driver|Docker Root Dir'

预期结果类似:

text 复制代码
Storage Driver: overlay2
Docker Root Dir: /opt/docker

如果 Docker Root Dir 不是 /opt/docker,应重新检查:

bash 复制代码
uci show dockerd
mount | grep ' /opt '

十四、打开 Docker 可视化管理页面

安装 luci-app-dockerman 后,清理 LuCI 缓存:

bash 复制代码
rm -f /tmp/luci-indexcache
rm -rf /tmp/luci-modulecache
/etc/init.d/uhttpd restart

退出 LuCI 后重新登录。

浏览器打开:

text 复制代码
http://192.168.1.1

Docker 菜单通常位于:

text 复制代码
服务 → Docker

部分定制固件可能显示为:

text 复制代码
Docker

或者:

text 复制代码
服务 → Docker 容器

确认插件已经安装:

bash 复制代码
opkg list-installed | grep -E 'dockerd|docker|luci-app-dockerman'

十五、安装中文语言包

如果 Docker 管理页面中部分内容是中文、部分内容是英文,通常只是翻译不完整,不影响实际功能。

检查可用中文语言包:

bash 复制代码
opkg update
opkg list | grep -E 'luci-i18n-(dockerman|docker)-zh-cn'

如果存在,可以安装:

bash 复制代码
opkg install luci-i18n-dockerman-zh-cn

部分固件可能使用:

bash 复制代码
opkg install luci-i18n-docker-zh-cn

安装后清理缓存:

bash 复制代码
rm -f /tmp/luci-indexcache
rm -rf /tmp/luci-modulecache
/etc/init.d/uhttpd restart

浏览器使用:

text 复制代码
Ctrl + F5

强制刷新。

即使仍然存在英文,也属于正常现象。常见术语包括:

英文 中文
Container 容器
Image 镜像
Network 网络
Volume 数据卷
Registry 镜像仓库
Logs 日志
Port 端口
Bind Mount 目录映射
Environment 环境变量
Restart Policy 重启策略

十六、测试 Docker

执行:

bash 复制代码
docker run --rm hello-world

如果能够正常下载镜像并输出欢迎信息,说明 Docker 工作正常。

检查容器:

bash 复制代码
docker ps -a

检查磁盘:

bash 复制代码
df -hT /opt
du -sh /opt/docker
docker system df

十七、建议的 Docker 数据目录结构

建议将应用配置和 Docker 自身数据分开。

创建统一应用目录:

bash 复制代码
mkdir -p /opt/appdata

例如:

text 复制代码
/opt/docker/                 Docker 镜像、容器层和内部数据
/opt/appdata/alist/          Alist 配置
/opt/appdata/homeassistant/  Home Assistant 配置
/opt/appdata/adguardhome/    AdGuard Home 配置
/opt/appdata/nginx/          Nginx 配置

创建容器时,通过目录映射保存重要数据:

bash 复制代码
docker run -d \
  --name example \
  -v /opt/appdata/example:/config \
  image-name

不要只将重要配置保存在容器内部。删除并重建容器后,未映射的数据可能随容器一起丢失。


十八、设置容器资源限制

Docker 容器默认没有强制的 CPU 和内存上限,理论上可以使用宿主机允许的全部资源。对于同时承担路由、DNS、代理等任务的 OpenWrt,异常容器可能影响整台设备,因此建议为容器设置内存和 CPU 限制。

例如:

bash 复制代码
docker run -d \
  --name example \
  --memory=512m \
  --cpus=1 \
  --restart=unless-stopped \
  image-name

参数含义:

参数 作用
--memory=512m 最大使用 512 MiB 内存
--cpus=1 最大使用约 1 个 CPU 核心
--restart=unless-stopped 非手动停止时自动重启

查看实时资源占用:

bash 复制代码
docker stats

资源限制应根据软路由实际内存和处理器性能设置,不要直接照搬固定数值。


十九、限制 Docker 日志大小

Docker 的 json-file 日志驱动支持通过 max-sizemax-file 自动轮转日志。若不设置大小上限,长期运行的容器可能不断写入日志并占满 /opt

创建容器时建议加入:

bash 复制代码
--log-opt max-size=10m \
--log-opt max-file=3

完整示例:

bash 复制代码
docker run -d \
  --name example \
  --restart=unless-stopped \
  --memory=512m \
  --cpus=1 \
  --log-opt max-size=10m \
  --log-opt max-file=3 \
  -v /opt/appdata/example:/config \
  image-name

这表示:

  • 单个日志文件最大 10 MiB;
  • 最多保留 3 个日志文件;
  • 超出数量后删除最旧日志。

日志设置只会自动应用于新创建的容器,已经存在的容器通常需要重新创建后才能使用新的日志参数。


二十、注意端口暴露

查看当前容器端口:

bash 复制代码
docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'

如果看到:

text 复制代码
0.0.0.0:8080->80/tcp

表示容器端口绑定到了宿主机所有 IPv4 接口。

只希望局域网访问时,可以绑定 OpenWrt 的 LAN 地址:

bash 复制代码
docker run -d \
  -p 192.168.1.1:8080:80 \
  image-name

还需要注意:

  • 不要将 LuCI 管理页面直接开放到 WAN;
  • 不要开放未经保护的 Docker API 端口;
  • 不要随意将 /var/run/docker.sock 映射给不可信容器;
  • 不要直接使用来源不明的高权限容器镜像;
  • 除非应用明确需要,否则不要启用 --privileged

二十一、系统备份

系统配置稳定后,应立即生成备份。

1. LuCI 备份

进入:

text 复制代码
系统 → 备份/升级 → 生成备份

将备份文件保存到电脑。

2. 命令行备份

执行:

bash 复制代码
sysupgrade -b "/tmp/openwrt-backup-$(date +%F).tar.gz"

保存软件包列表:

bash 复制代码
opkg list-installed > "/tmp/packages-$(date +%F).txt"

记录分区结构:

bash 复制代码
fdisk -l /dev/mmcblk0 > /tmp/mmcblk0-partitions.txt
block info > /tmp/block-info.txt

重点备份:

text 复制代码
/etc/config/fstab
/etc/config/dockerd
/etc/config/network
/etc/config/firewall

Docker 应用数据还要单独备份:

text 复制代码
/opt/appdata

OpenWrt 系统配置备份并不等同于 Docker 应用数据备份。


二十二、固件升级注意事项

当前磁盘结构中,p3p4 是写入原始固件后额外创建的。

以后不要在没有备份的情况下直接执行:

bash 复制代码
dd if=新固件.img of=/dev/mmcblk0

整盘镜像会重新覆盖 eMMC 开头的 GPT 分区表,可能导致:

  • p3p4 分区记录消失;
  • extroot 无法挂载;
  • /opt 暂时无法访问;
  • Docker 镜像和应用数据看似丢失。

升级前至少应当:

  1. 备份 OpenWrt 配置;
  2. 备份 /opt/appdata
  3. 保存 fdisk -lblock info 输出;
  4. 确认固件作者提供的升级方式;
  5. 确认新固件是否兼容现有 extroot;
  6. 保留原启动U盘作为恢复环境。

二十三、日常维护命令

检查磁盘空间:

bash 复制代码
df -hT / /overlay /opt

检查 Docker 空间:

bash 复制代码
docker system df

查看容器:

bash 复制代码
docker ps -a

查看容器资源:

bash 复制代码
docker stats

检查 Docker 日志:

bash 复制代码
logread -e dockerd

检查 eMMC 和 ext4 错误:

bash 复制代码
dmesg | grep -Ei 'mmc|ext4|error|I/O'

清理未使用的悬空镜像:

bash 复制代码
docker image prune

不要在不清楚后果的情况下执行:

bash 复制代码
docker system prune -a --volumes

该命令可能删除:

  • 已停止的容器;
  • 未使用的镜像;
  • 未使用的网络;
  • 未挂载的数据卷。

建议 /opt 长期至少保留 15% 左右的可用空间。


二十四、常见问题排查

1. cfdisk 中没有剩余空间

先检查 GPT:

bash 复制代码
fdisk -l /dev/mmcblk0

如果存在备用 GPT 不在磁盘末尾的警告,可以执行:

bash 复制代码
fdisk /dev/mmcblk0

输入:

text 复制代码
w

然后重启:

bash 复制代码
reboot

再次进入 cfdisk

2. 重启后 /overlay 容量没有变化

检查:

bash 复制代码
block info /dev/mmcblk0p3
uci show fstab.extroot
mount | grep -E ' /overlay |overlayfs'
logread | grep -Ei 'mount|extroot|overlay'

重点确认:

  • UUID 是否正确;
  • 分区是否为 ext4;
  • target 是否为 /overlay
  • enabled 是否为 1
  • 新分区中是否已经复制 upperwork

3. /opt 没有挂载

执行:

bash 复制代码
block info /dev/mmcblk0p4
uci show fstab.opt
mount | grep ' /opt '

必要时手动测试:

bash 复制代码
mount /dev/mmcblk0p4 /opt

如果手动挂载正常,说明主要问题在 /etc/config/fstab

4. Docker 页面没有出现

检查:

bash 复制代码
opkg list-installed | grep luci-app-dockerman

清理缓存:

bash 复制代码
rm -f /tmp/luci-indexcache
rm -rf /tmp/luci-modulecache
/etc/init.d/uhttpd restart

然后退出 LuCI 并重新登录。

5. Docker 无法启动

执行:

bash 复制代码
/etc/init.d/dockerd restart
logread -e dockerd
docker info

同时检查:

bash 复制代码
df -hT /opt
mount | grep ' /opt '
uci show dockerd

6. Docker 数据没有写到 /opt

执行:

bash 复制代码
docker info | grep 'Docker Root Dir'

如果不是:

text 复制代码
/opt/docker

重新设置:

bash 复制代码
uci set dockerd.globals.data_root='/opt/docker/'
uci commit dockerd
/etc/init.d/dockerd restart

7. 页面有中文也有英文

这是语言包翻译不完整造成的,不影响 Docker 实际运行。

可以尝试安装:

bash 复制代码
opkg install luci-i18n-dockerman-zh-cn

如果软件源没有对应语言包,保留中英文混合界面即可。


二十五、最终验收清单

完成全部配置后,依次执行:

bash 复制代码
lsblk -o NAME,SIZE,FSTYPE,LABEL,MOUNTPOINTS /dev/mmcblk0
bash 复制代码
df -hT / /overlay /opt
bash 复制代码
mount | grep -E ' /overlay | /opt '
bash 复制代码
docker info | grep -E 'Storage Driver|Docker Root Dir'
bash 复制代码
docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
bash 复制代码
docker system df

最终应满足:

  • 系统能够在拔掉U盘后从 eMMC 启动;
  • /overlay 使用 /dev/mmcblk0p3
  • /opt 使用 /dev/mmcblk0p4
  • /overlay 容量约为 4 GiB;
  • /opt 容量约为 24 GiB;
  • Docker Root Dir 为 /opt/docker
  • Docker LuCI 可视化页面可以正常打开;
  • hello-world 容器能够正常运行;
  • 系统配置和 Docker 应用数据已经完成备份;
  • 容器日志和资源使用已经设置合理上限。

至此,OpenWrt 从U盘迁移到内置 eMMC、系统扩容、Docker 安装和可视化管理全部完成。

相关推荐
就改了1 小时前
SpringBoot 自定义线程池 + 实时监控指标
java·spring boot·后端
Eloudy1 小时前
docker build 与 docker buildx build 的应用场景
docker·构建
plainGeekDev1 小时前
运行时获取依赖 → 编译时注入
android·java·kotlin
瞬间&永恒~2 小时前
【Docker】(三)联合文件系统UnionFS + Overlay2
docker·云原生·容器
玖石书3 小时前
ASP.NET Core 迁移至 Spring系列:类库框架篇
java·后端·asp.net
笨蛋不要掉眼泪3 小时前
RabbitMQ消息队列:延迟消息
java·rabbitmq·java-rabbitmq
Adios7943 小时前
搜索二维矩阵 II
java·数据结构·算法
摇滚侠4 小时前
《SpringBoot 3:入门与应用实战》第 15 章 生产级特性 监控指标 Metrics 阅读笔记
java·spring boot·笔记
骇客野人4 小时前
IDEA 安装 Trae(TRAE AI: Coding Assistant)完整步骤
java·ide·intellij-idea