1. 飞牛NAS的系统分区与存储空间,到底是什么关系
很多刚上手飞牛系统(fnOS)的朋友,遇到的第一道坎不是装系统,而是用着用着突然发现系统盘红了。明明自己只存了几部电影、跑了一两个Docker容器,怎么系统分区就满了?更麻烦的是,在后台点来点去,也没找到“把系统空间挪到存储空间”的入口,于是就开始搜“飞牛系统分区迁移空间至存储空间 1”之类的关键词。
先别急着操作,我先把飞牛的存储逻辑捋清楚。飞牛系统在安装时,默认会把系统装在一块硬盘上,并且会在这块盘上划出几个独立分区:引导分区、系统分区、交换分区,这些分区各自承担系统启动、核心文件和内存交换的职责。这部分空间是给系统本身用的,不是给你存影视资源的。而在剩余空间里,飞牛会创建存储空间,默认可能叫“存储空间 1”,这部分才是你平时放照片、视频、Docker数据的地方。
问题就出在这套默认分配逻辑上。飞牛系统分区默认给的容量并不宽裕,一般只有几十GB,甚至在某些镜像里只给十几个GB。而系统分区里实际上会承担很多额外写入任务:系统更新缓存、Docker的镜像和容器日志、日志系统(journald)、临时文件、应用数据,都会往系统分区里塞。我见过不少人装完系统没几个月,系统分区占用率直接飙到90%以上,然后系统开始疯狂告警:Web界面打不开、应用启动失败、文件服务卡顿,甚至连关机都变得异常缓慢。
那“分区迁移空间至存储空间 1”这个需求,本质上就是想干两件事:要么把系统分区和存储空间1之间的空间重新做平衡,要么把系统分区里那些吃空间的大头目录,迁移到存储空间1去,让系统分区瘦身。但问题是,很多人的设备里,系统盘和存储空间1根本是两块不同的硬盘,物理位置都不在一起,“迁移空间”就不是拖动一下滑块那么简单了。
所以这篇文章,我会把几种可行的迁移思路都拆开讲清楚:LVM逻辑卷扩容、目录迁往存储空间1、以及相关挂载与校验操作。全程按照我实际操作过的流程来写,不绕弯子,也不整玄学。
1.1 飞牛默认安装分区结构:系统盘为什么总是不够用
要给系统做空间迁移,第一步是先看懂自己的分区结构。飞牛基于Linux内核,安装在实体机或虚拟机上都支持,默认分区方案大致是这样:
/boot:引导分区,一般只有几百MB到1GB,装内核和引导文件。/:系统根分区,也就是系统盘的主要分区,飞牛默认给的大约20GB到50GB不等。swap:交换分区,内存不够时的后备缓冲。- 剩余空间:用于构建存储空间,通常挂载在
/vol1、/vol2这类路径下。
注意,这里的“剩余空间”如果和系统根分区在同一块物理硬盘上,那么飞牛在安装时会自动把剩余空间做成存储空间,不需要你手动处理。如果你的机器上只有一块盘,那么存储空间1和系统分区都在同一块SSD或机械硬盘上,只是不同的分区而已。
听起来是不是很简单?但问题恰恰出在“同一块盘”和“不同分区”上。因为系统分区是固定大小的,你在飞牛安装完成后,就算存储空间1还有大量空闲,系统分区也无法自动“借用”这些空间。而系统分区一旦被日志、Docker镜像、更新包塞满,系统整体的稳定性就会受到影响。
我在实际维护中遇到的最典型一个案例,是一台装了飞牛的小主机,硬盘总共512GB,系统分区30GB,存储空间1约450GB。结果用户把Docker的数据目录默认放到了/var/lib/docker,这正好在系统分区里,跑了一个下载容器,几天就写了30GB的临时数据,直接干爆了根分区,整个Web服务挂掉。这就是典型的“空间分配不合理”引发的故障。
所以在动手迁移之前,你至少要会用三个命令来确认当前状态:
df -hT lsblk cat /etc/fstabdf -hT能告诉你每个分区的文件系统类型和使用率,lsblk能展示完整的磁盘和分区树状结构,cat /etc/fstab则是查看系统启动时的挂载规则,后面做绑定挂载时肯定用得到。
1.2 系统空间告急的典型症状与元凶定位
再说说系统分区满了之后会出现什么症状。它的表现不是单纯的“存储空间不足”提示,而是一连串连锁反应:
- Web管理界面能进,但点击“应用中心”或“Docker”页面时半天无响应;
- 日志疯狂刷写失败,容器反复重启;
- SMB/NFS共享服务突然中断,局域网内访问不到文件;
- 系统设置中显示“系统分区已满”,但存储空间1却显示正常;
- 更严重的,重启后系统进入维护模式,无法正常启动。
为什么系统分区满了影响这么大?因为Linux系统的正常运行极度依赖根分区的可用空间。很多服务都要在运行时写临时文件、写缓存、写socket,一旦根分区满了,这些服务就会集体罢工。你可以把系统分区理解成家里的门厅过道,存储空间是卧室和车库。门厅堆满杂物,你连走到卧室的通道都没了,更别说把车开进来。
找到症状之后,就要定位“元凶”。大多数情况下,空间的大头无非这么几个目录:
/var/lib/docker:Docker的默认数据目录,镜像、容器层、卷数据都在这里;/var/log:系统日志,journald日志长期不清理会非常可观;/tmp:临时文件,某些应用崩溃后残留的大文件;/var/cache:软件包缓存和更新缓存;/home下如果有用户数据且没有挂载到存储空间,也会占系统盘。
快速定位元凶很简单,一句命令即可:
du -h --max-depth=1 / 2>/dev/null | sort -h按目录大小从下往上排序,看一眼就能知道是谁在偷偷吃空间。我遇到的情况里,Docker数据占据比例最高,其次是journald日志,剩下的就是系统更新缓存。定位清楚之后,你才好决定自己到底用哪种迁移方案。
2. 迁移思路选型:扩容、搬家还是重新规划
搞清楚系统分区为什么满之后,下一个问题就是怎么把它“救回来”。我现在能想到的可行办法大致有三种:
- LVM逻辑卷扩容:前提是你的系统盘用的是LVM管理,并且存储池里有可用的物理卷空间,或者能把存储空间1的部分空间释放出来加入系统卷组,然后在线扩展根分区。
- 目录迁移:把
/var/lib/docker、/var/log这类吃空间的大目录,用rsync搬到存储空间1,再用绑定挂载的方式让系统继续按原路径访问。 - 重装系统并重新规划分区:这是最粗暴、但也是数据风险最高的办法,只建议在设备还没存重要数据时使用。
三种办法各有利弊,不能一概而论。我在下面分别展开。
2.1 方案A:LVM逻辑卷在线扩容
LVM全称 Logical Volume Manager,是Linux下非常成熟的磁盘管理机制。它的核心理念就是把物理磁盘抽象成物理卷(PV)、卷组(VG)和逻辑卷(LV)三层。逻辑卷的大小可以在线调整,只要卷组里有足够的剩余空间。
飞牛系统在部分安装场景下确实启用了LVM,系统分区就是挂在一个名为fnOS_vg之类的卷组下的逻辑卷。这种情况下,理想的扩容路径是:
- 找到一块有剩余空间的物理卷,或者干脆把存储空间1所在磁盘释放出未分配区域,做成新的物理卷;
- 把物理卷加入系统卷组;
- 用
lvextend扩大根逻辑卷; - 用
resize2fs或xfs_growfs扩大文件系统。
这个方案的优点在于可以实现“热扩容”,系统不用重启,逻辑卷扩大后文件系统也随之扩大,整个过程对正在运行的服务几乎没有影响。缺点在于,如果你的系统盘根本不是LVM管理的,这个方案就没法用,只能走目录迁移。
而且,LVM扩容还牵扯到一个很实际的约束:存储空间1是否和系统在同一个卷组?如果不是,你得先把存储空间1里的数据腾出去,再把那块物理磁盘缩容或重新分区,操作复杂度会直线上升。所以动手之前,务必用pvscan、vgscan、lvscan确认当前的LVM拓扑。
2.2 方案B:重负载目录迁移到存储空间1
如果LVM路线走不通,或者你只是单纯不想动分区表,那目录迁移就是最稳妥的替代方案。它的核心逻辑是:系统分区之所以紧张,是因为某些目录数据量太大,而这些数据并不一定要放在系统盘上。我们把它们整体搬到存储空间1,然后在原路径上做一个“绑定挂载”(bind mount),让系统以为数据还在原处。
这里以最常出问题的 Docker 数据目录为例,迁移流程可以概括为:
systemctl stop docker rsync -aXS /var/lib/docker/ /vol1/docker/ mount --bind /vol1/docker /var/lib/docker systemctl start docker这套操作的优点非常明显:不需要动分区表,不依赖LVM,只要你存储空间1有足够容量就能执行。而且可迁移的目录不限于Docker,日志目录、下载缓存目录、应用数据目录都可以如法炮制。
缺点呢,就是路径绑定这件事需要在系统重启后依然生效,所以你必须把挂载规则写进/etc/fstab。如果只敲了mount --bind但没写fstab,系统一重启,绑定关系就没了,服务会再次找到原来那个几乎是空的目录,到时候表现出来的就是“数据不见了”的假象。
2.3 三种方案怎么选:对比与适用场景
这里我把三种方案整理成一张表格,方便你对照自己的设备情况做判断:
| 方案 | 前提条件 | 操作复杂度 | 数据风险 | 适用场景 |
|---|---|---|---|---|
| LVM在线扩容 | 系统使用LVM;有可用物理卷空间 | 中高 | 中(涉及卷组操作) | 系统盘与存储空间同盘,且分区为LVM管理 |
| 目录迁移+绑定挂载 | 存储空间1有足够容量 | 低 | 低(数据复制式迁移) | 系统分区满、Docker/日志等数据占用大 |
| 重装系统重新分区 | 无重要数据或数据已备份 | 中 | 高 | 设备刚入手,尚未存储重要资料 |
我个人更推荐第二种。原因很简单:大多数人的核心诉求不是“让系统分区变大”,而是“别再让系统分区塞满导致服务挂掉”。目录迁移够用了,而且回滚也方便。真要硬着头皮去动LVM卷组,反而可能把整个存储空间搞乱。
如果你在虚拟化环境(比如VMware)里跑飞牛,想让存储空间分配更合理,其实更推荐直接在虚拟机层面把虚拟磁盘扩容,再进入系统用分区工具或LVM把多出来的空间分配给系统分区或存储空间,这样比在系统内部拆东墙补西墙要省事得多。
3. 实操:分区空间迁移到存储空间1的完整流程
理论部分说得再多,不实操都是纸上谈兵。下面进入正题,我把这两条路线分别走一遍,记录完整的操作步骤和关键命令。你操作之前,先记住一句保命箴言:不管走哪条路,重要数据先备份。
别嫌我啰嗦。你接下来要动的是分区表、挂载配置、Docker目录,任何一个疏忽都可能导致服务异常或者数据路径错乱。我见过太多人在这一步贪快,结果事后花了两天恢复数据。
3.1 准备工作:备份、查看分区结构、确认文件系统
我先按实际操作顺序列一下准备阶段要做的事。
第一步,打开飞牛系统的SSH终端,或者直接在系统设置里开启终端功能。没有SSH权限的话,后面所有命令都跑不了。
第二步,确认分区结构和LVM状态。依次执行以下命令,把输出仔细看一遍:
df -hT lsblk pvscan vgscan lvscan blkid cat /etc/fstab重点看三样东西:
- 根分区挂载点
/的文件系统类型,是ext4还是xfs,这决定了扩容时用哪个扩展命令; - 根分区所在逻辑卷或物理分区的名称;
- 存储空间1的挂载路径,一般可能是
/vol1。
第三步,备份关键配置。至少把/etc/fstab备份一份:
cp /etc/fstab /etc/fstab.bak第四步,查看存储空间1的可用空间:
df -h /vol1如果存储空间1可用空间充足,那目录迁移路线基本稳了。如果存储空间1也满了,那就得先往存储空间1里腾空间,或者换一块更大的存储盘再说。
3.2 实操A:用LVM给系统逻辑卷扩容
如果你的飞牛系统分区是LVM管理的,而且你确认卷组里还有未分配的空间,那么扩容根分区的操作其实非常快。我先演示一个把空闲空间全部扩展到根逻辑卷的例子。
查看当前的卷组信息:
vgdisplay输出里会有一个Free PE / Size字段,这个就是还能用的空闲容量。注意,这里的空闲空间必须是在你的系统卷组(比如fnOS_vg)内。如果显示为0,说明卷组里没有富余空间,那就需要先做物理卷扩容,或者释放空间。
假如卷组里有空闲空间,执行扩展:
lvextend -l +100%FREE /dev/fnOS_vg/root这条命令的意思是把根逻辑卷扩展到占用卷组所有剩余空间。等系统输出“Logical volume root successfully resized”后,再扩展文件系统。
文件系统类型不同,命令不同。ext4用:
resize2fs /dev/fnOS_vg/rootxfs用:
xfs_growfs /完成后用df -h /验证一下,根分区容量应该已经变大。
这里有个非常关键的细节:如果你发现系统根分区并不是LVM逻辑卷,而是一个普通物理分区(比如/dev/sda2),那你不能直接lvextend,会因为找不到逻辑卷直接报错。这种情况只有两条路可以走:要么用fdisk/parted调整物理分区表(需要重启,且操作风险极大),要么干脆放弃扩容路线,改用目录迁移方案。我强烈建议普通人选后者,别为了一点系统空间去赌分区表操作的成功率。
3.3 实操B:把Docker/日志目录迁移到存储空间1
这一节是本文的绝对重点,也是我认为最值得收藏的部分。我以迁移Docker数据目录/var/lib/docker到/vol1/docker为例,完整走一遍。
先停掉Docker服务:
systemctl stop docker这一步不能省。如果Docker服务还在运行,它可能正在向数据目录写入文件,此时直接rsync复制,源数据处于活动状态,复制出来的结果不等价,回写时会出错。停服之后,数据目录就静态了,复制出来的镜像和容器层才是一份一致性快照。
确认服务完全停止:
systemctl status docker然后创建目标目录并同步数据:
mkdir -p /vol1/docker rsync -aXS /var/lib/docker/ /vol1/docker/这里的几个参数解释一下:
-a归档模式,保留权限、时间戳、符号链接;-X保留扩展属性,Docker容器文件里可能涉及;-S处理稀疏文件,避免复制无用的空洞导致空间浪费。
同步过程中,我建议你开一个新的SSH窗口,用du -sh /vol1/docker随时观察目标目录大小,确认数据确实在增长。同步完成后,对比一下源和目标的大小:
du -sh /var/lib/docker du -sh /vol1/docker两者大小应当接近一致。确认无误后,把原来的数据目录改名留存,作为回滚保险:
mv /var/lib/docker /var/lib/docker.bak mkdir -p /var/lib/docker接着做绑定挂载:
mount --bind /vol1/docker /var/lib/docker这条命令执行后,系统访问/var/lib/docker时,实际读写的已经是/vol1/docker的内容了。但注意,这只是临时挂载,重启后失效。所以要把挂载规则写入/etc/fstab:
vim /etc/fstab在文件末尾加一行:
/vol1/docker /var/lib/docker none bind 0 0然后执行:
mount -a如果没有报错,说明fstab配置没问题。最后启动Docker服务:
systemctl start docker启动后用docker ps验证容器是否正常还活着。如果之前跑着的容器都正常显示,说明数据迁移成功。
日志目录的迁移方式一模一样,唯一的区别是路径不同。你只需要把/var/lib/docker替换成/var/log,目标目录换成/vol1/log,然后先执行日志瘦身再迁移也行,比如用journalctl --vacuum-size=500M先把旧日志清理一波,减小迁移体积。
3.4 迁移后验证与回收系统空间
迁移完Docker目录,你可能会发现系统分区还是没降下去多少。这是正常的,因为旧的/var/lib/docker.bak还在原地占着空间。确认一切运行正常后,再把它清掉:
rm -rf /var/lib/docker.bak清理之后,用df -h /再看一眼系统分区的使用率,理论上应该大幅下降。
这里有一个我在实践中总结的验证习惯:迁移完成后,不要只看df -h的数字,还要实际检查一下核心服务是否可用。比如飞牛的SMB共享能不能正常访问、应用中心的已安装应用能不能正常启动、Docker容器日志能不能正常写入。因为有些时候,文件系统层面看起来没问题,但服务因为路径权限或者挂载顺序的问题,实际上已经处于半瘫痪状态。
再检查一下权限:存储空间1如果之前有其他数据目录,目录所有权可能和Docker需要的root:root不一致。可以用:
ls -ld /vol1/docker /var/lib/docker chown -R root:root /vol1/docker确保权限正确后,再重启一次Docker服务做最终确认。
4. 迁移后的常见问题速查:未挂载、起不来、权限异常
迁移这件事,最怕的不是操作过程出问题,而是操作完了一段时间后突然出问题。尤其是“飞牛系统存储空间未挂载”这个关键词,几乎隔几天就有人在社区里问。我这里把几类高频问题集中梳理一下,方便你对症下药。
4.1 存储空间未挂载的排查流程
“存储空间未挂载”这个提示,一般出现在系统刚启动完或者硬盘插拔之后。常见原因有四种:
- 系统异常断电,文件系统发生错误,导致自动挂载失败;
- 硬盘识别顺序发生变化,导致挂载规则中的UUID与实际设备对不上;
- 手动改过
/etc/fstab,写入了错误的分区或者绑定路径; - 硬盘或数据线接触不良,系统启动时根本没识别到设备。
排查思路按顺序来。先看设备是否被识别:
lsblk blkid如果设备在,再用dmesg查看内核日志:
dmesg | tail -50看看有没有文件系统错误或挂载失败的报错信息。如果是文件系统损坏,先卸载对应分区,再执行:
fsck /dev/sdb1注意,fsck必须在分区未挂载的状态下执行,否则大概率会把文件系统修坏。如果设备不在,优先检查物理连接和系统启动时的日志。
还有一种常见情况是绑定挂载未生效。比如你迁移Docker目录后重启,发现容器全不见了,但/vol1/docker里的数据明明还在。这时候先执行:
mount -a看fstab里的绑定规则能不能补挂上。如果提示找不到挂载点,就把/etc/fstab里的那个绑定路径检查一遍,确保源目录和目标目录都存在。
4.2 迁移后服务启动异常的修复
这个问题的触发点很典型:Docker数据迁移完成后,systemctl start docker时Docker能起来,但容器启动时各种报错,比如容器有权限问题、文件找不到、目录不存在。
八成是两种原因。第一种是rsync复制时没有保留好原有所有权和权限,导致容器内用户无法正常访问挂载卷。第二种是源目录在复制之后又有新数据写入,你在旧目录上又起过服务,然后新旧目录之间出现了数据差异,而绑定挂载指向了旧目录的快照。
第一种情况的解决办法是核对权限:
ls -ln /vol1/docker对比原来的目录权限和所有权,必要时用chown修正。第二种情况回滚更简单,先把绑定挂载去掉,恢复旧目录,再重新同步一次,确保源和目标完全一致后再次绑定。
这类问题我在实际维护中遇到过不止一次,操作上我建议迁移过程中把Docker服务停的时间尽量延长一点,不要急。宁可多停十分钟,也不要停在复制到一半就去启动服务。
4.3 重启后挂载失效的Fix
绑定挂载写进/etc/fstab之后,理论上重启会自动加载。但如果你在fstab里写的目标挂载点路径本身就不固定,或者挂载点目录在启动时还没创建好,就会导致挂载失效。
比如你的存储空间1的挂载路径是/vol1,如果写入fstab的绑定源路径依赖存储空间1先挂载成功,那启动顺序一旦变化,绑定就会失败。稳定做法是在fstab里用UUID来指定存储分区的挂载,而不是用/dev/sda1这种设备名。设备名在系统启动时可能因为硬盘枚举顺序变化而改变,UUID则是分区本身的唯一标识,不会变。
确认UUID:
blkid /dev/sdb1然后修改/etc/fstab中的存储分区挂载行,把/dev/sdb1换成实际的UUID。绑定挂载那行保持:
/vol1/docker /var/lib/docker none bind 0 0这样系统启动时会先按UUID挂载存储空间1,再执行绑定挂载,顺序就稳定了。
我个人在实际操作中还有一个习惯:每次改完fstab,都先执行mount -a确认没有报错,再重启验证一遍。如果重启后挂载没生效,立刻在启动后手动执行mount -a,输出信息会直接告诉你问题出在哪一行。
再分享一个排查小技巧:飞牛系统出现挂载异常时,很多老手习惯先看/etc/mtab文件,它记录了当前所有已生效的挂载点。如果系统启动了但fstab里的绑定行没生效,/etc/mtab里不会出现对应的记录,这时候问题基本就锁定在fstab配置或启动顺序上。
4.4 迁移完成后的空间维护习惯
最后额外说一个跟“维护”有关的事。很多人迁移完成之后,系统盘空间确实腾出来了,但过了几个月又满了。为什么?因为只要你还在用Docker、还在用飞牛应用中心装应用,日志和缓存就会持续增长。如果不定期清理,系统分区迟早再次告急。
所以我的建议是,迁移完成之后顺手把日志清理策略配一下。把journald的日志上限调低:
journalctl --vacuum-size=300M编辑/etc/systemd/journald.conf,把SystemMaxUse改成500M,重启journald服务生效:
systemctl restart systemd-journaldDocker容器产生的日志如果不加限制,也会无限增长。在 Docker 配置或容器运行参数里加日志轮转,比如限制单容器日志大小:
logging: driver: "json-file" options: max-size: "100m" max-file: "3"这部分虽然不属于“迁移”本身,但和你的系统分区能否长治久安直接相关。
我的体会是:系统分区空间问题,从来不是一次迁移就能一劳永逸的。它更像是一种长期的资源管理习惯,你把大目录搬走了,只是给系统盘腾出了喘息空间,后续的日志控制、缓存清理、Docker数据规划,才真正决定系统盘会不会再次报警。
上面写的这些命令和流程,我基本都在飞牛系统上实测过不同版本。尤其是Docker目录迁移那段,来回操作过好几轮,最顺利的一次从停服到容器恢复只花了不到二十分钟。唯一一次翻车,是我当时图省事,没有把fstab里的绑定挂载写对,结果第二天早上发现系统更新重启之后Docker挂了,所有容器报文件不存在。那之后我就养成了强迫症:每次改fstab,必须执行mount -a,必须重启验证。
希望这篇内容能帮你少走一次弯路。如果你已经迁移到一半卡住了,记住一个原则:先把服务停掉,再把数据同步完整,最后才动挂载配置,顺序别乱,基本不会出大问题。