/etc/fstab —— 持久化挂载配置
一句话定义
/etc/fstab(file systems table)告诉系统开机时挂载哪些文件系统。mount 命令是临时操作,重启就没;fstab 是把挂载关系写入配置,开机自动挂。
典型场景
- 装机:新盘 mkfs + mount + 写 fstab,重启后还能用
- K8s 节点重启后数据盘不丢
- 测试 fstab 配置:
mount -a(用 fstab 挂所有还没挂的)
这是个容易让系统启不来的文件。写错一行 + 重启 = 卡 emergency mode。
nofail标记是救命的。
一行 fstab 长这样
# <file system> <mount point> <type> <options> <dump> <pass>
UUID=abc-def-123... /data ext4 defaults,noatime,nofail 0 2
6 个字段:
| 字段 | 含义 |
|---|---|
| file system | 设备 / UUID / LABEL / 远端 |
| mount point | 挂载点(目录路径) |
| type | 文件系统类型(ext4 / xfs / nfs / tmpfs / swap / ...) |
| options | 挂载选项(defaults,noatime,nofail 等) |
| dump | dump 程序是否备份这个 fs(几乎都填 0) |
| pass | fsck 检查顺序(根 1,其它 2,不查 0) |
永远用 UUID,不要用设备名
/dev/sdb1 /data ext4 defaults 0 2 ← ❌ 不稳定
/dev/sdb 可能因为:
- 加新盘后变成
/dev/sdc - 内核扫盘顺序变
- 云厂商热重启后重新分配
→ 挂载失败 → 系统启不来。
正确:用 UUID(mkfs 时自动生成,不随设备号变化):
blkid /dev/sdb1
# /dev/sdb1: UUID="abc-def-..." TYPE="ext4"
# fstab:
UUID=abc-def-... /data ext4 defaults,noatime,nofail 0 2
或者用 LABEL(mkfs 时 -L 给的):
LABEL=data /data ext4 defaults,noatime,nofail 0 2
LABEL 简短易读、UUID 更稳(不会和别人冲突)。生产推荐 UUID。
nofail 是救命标记
UUID=... /data ext4 defaults 0 2 ← ❌ 默认会让系统启动卡死
UUID=... /data ext4 defaults,nofail 0 2 ← ✅ 失败也启动
不加 nofail:
- 盘有问题 / UUID 不对
- 启动时挂载失败
- → systemd 进入 emergency mode 等手动救援
- 你 ssh 不进去(除非内网 console)
加 nofail:
- 挂载失败只是不挂这个盘
- 系统正常启动
- 之后 ssh 进去
journalctl -b -u local-fs.target排查
所有数据盘的 fstab 行都加 nofail。根分区 / 不能加 nofail(根挂不上系统就真完了,需要救援)。
pass 字段(fsck 顺序)
UUID=... / ext4 defaults 0 1 ← 根分区 pass=1
UUID=... /boot ext4 defaults 0 2 ← 其它分区 pass=2
UUID=... /data ext4 defaults,nofail 0 2
UUID=... none swap sw 0 0 ← swap pass=0
tmpfs /tmp tmpfs defaults 0 0 ← tmpfs pass=0
0—— 不查1—— 根分区(必须 1,且整个系统只能有一个 pass=1)2—— 其它分区(并行查)
pass=2 让 fsck 周期性自动检查(默认每 30 次 mount 或 180 天检查一次)。pass=0 跳过——适合外部存储 / NFS / 数据盘允许长时间不查。
K8s 节点上 etcd 数据盘可以设 0(不让 fsck 阻塞启动)。
常见 options 速查
defaults # rw,suid,dev,exec,auto,nouser,async
noatime # 不更新 atime(**生产强烈推荐**)
nodiratime # 不更新目录 atime(通常含在 noatime)
ro / rw # 只读 / 读写
nofail # **fstab 必加(除根分区)**
nodev # 不识别设备文件
nosuid # 忽略 setuid
noexec # 不允许执行
discard # 实时 TRIM(SSD)
auto / noauto # 是否 mount -a 时挂
user / nouser # 普通用户能否 mount
_netdev # 依赖网络(NFS / iSCSI 必加)
x-systemd.automount # 第一次访问时挂(懒挂)
x-systemd.device-timeout=10 # 等设备超时
x-systemd.requires=... # 显式依赖
训练营推荐 options
| 用途 | options |
|---|---|
根分区 / | defaults,errors=remount-ro |
| 普通数据盘 | defaults,noatime,nofail |
| etcd 数据盘 | defaults,noatime,nodiratime,nofail |
| 容器存储(containerd) | defaults,noatime,nofail |
| NFS | defaults,_netdev,nofail,timeo=14,intr |
| swap | sw |
| tmpfs | defaults,size=2G |
实战例子
单行 fstab 全套(K8s 数据盘)
# 1. 拿 UUID
UUID=$(blkid -s UUID -o value /dev/sdb1)
# 2. 写 fstab
echo "UUID=$UUID /var/lib/k8s-data ext4 defaults,noatime,nofail 0 2" >> /etc/fstab
# 3. 验证(不重启就测)
mount -a
# 4. 检查
findmnt /var/lib/k8s-data
df -h /var/lib/k8s-data
多种文件系统的 fstab 例子
# /etc/fstab
# <fs> <mountpoint> <type> <options> <dump> <pass>
UUID=11111111-1111-... / ext4 defaults,errors=remount-ro 0 1
UUID=22222222-2222-... /boot ext4 defaults 0 2
UUID=33333333-3333-... /boot/efi vfat umask=0077 0 1
# K8s 数据盘
UUID=44444444-4444-... /var/lib/containerd ext4 defaults,noatime,nofail 0 2
UUID=55555555-5555-... /var/lib/etcd ext4 defaults,noatime,nodiratime,nofail 0 2
# NFS 共享
nfs.internal:/exports/shared /mnt/shared nfs defaults,_netdev,nofail,vers=4 0 0
# swap
UUID=66666666-6666-... none swap sw 0 0
# tmpfs (大小限制)
tmpfs /tmp tmpfs defaults,nosuid,nodev,size=2G 0 0
测试 fstab 没写错(重启前必做)
mount -a # 用 fstab 挂所有 noauto 之外的
# 报错说明有问题,不要重启
# 看每行的解析
findmnt --verify --verbose # 检查 fstab 一致性
# 看启动时 mount 的日志(之前重启过的话)
journalctl -b | grep -i 'mount'
journalctl -u local-fs.target
写完 fstab 一定 mount -a 验证。否则 reboot 才发现写错就晚了。
救命:fstab 写错系统启不来怎么办
1. 进 emergency mode(grub 选 recovery)
启动时 grub 菜单选 Advanced → recovery mode,进 root shell。
2. 让根分区可写
mount -o remount,rw /
3. 修 fstab
vim /etc/fstab
# 把出错的那行注释掉或者修正
4. 重启
reboot
5. 云机器无法物理 console 怎么办
云厂商通常提供:
- web console(vnc 进系统)
- 救援模式(挂回根分区进救援盘)
或者最简单:联系客服,让他们救。
fstab 之外:systemd 的 .mount 文件
systemd 也能管挂载(更现代):
# /etc/systemd/system/data.mount
[Unit]
Description=Data volume
After=network.target
[Mount]
What=/dev/disk/by-uuid/abc-def-...
Where=/data
Type=ext4
Options=defaults,noatime
[Install]
WantedBy=multi-user.target
systemctl enable --now data.mount
优点:依赖管理更细(After=network.target 让 NFS 在网络起来后挂)。 缺点:写起来比 fstab 烦。
实际上 fstab 在内部就是被 systemd 转成 .mount unit 执行的。systemctl list-units --type=mount 看你 fstab 产生了哪些 unit。
常见踩坑
坑 1:用设备名导致重启挂不上
/dev/sdb1 /data ext4 defaults 0 2
加新盘后 → 设备名变了 → 挂载失败。永远用 UUID 或 LABEL。
坑 2:忘了 nofail,启动卡死
UUID=... /data ext4 defaults 0 2 ← 没 nofail
盘有任何问题 → emergency mode → 救援麻烦。
所有非根分区加 nofail。
坑 3:fstab 第 6 列写错(pass=1 给非根分区)
UUID=... /data ext4 defaults 0 1
两个 pass=1 → fsck 顺序乱套,可能让根分区 fsck 跳过。只有根用 1,其它要么 2 要么 0。
坑 4:第 5 列(dump)填 1
UUID=... /data ext4 defaults 1 2
1 表示让 dump 程序备份这个 fs。99% 系统没装 dump,填 0 即可。0 是标准。
坑 5:NFS 缺 _netdev
nfs:/exports /mnt/nfs nfs defaults 0 0 ← 启动时挂、网络还没起 → 失败
nfs:/exports /mnt/nfs nfs defaults,_netdev 0 0 ← 等网络起来再挂
加 _netdev 让 systemd 知道这是个网络依赖型挂载。
坑 6:UUID 拼错 / 多空格
UUID = abc... ← 等号两边不能有空格
UUID=abc-def-... /data ext4 defaults 0 2 ← 字段间用空白分隔,可以多空格
UUID 后面 = 两边不能有空格。字段间随意(空格或 tab)。
坑 7:把根分区改成 noatime 的副作用
/ 加 noatime 性能更好,但有些老旧应用依赖 atime(例如 mutt 邮件、tmpwatch)。
通常 K8s 节点没事,桌面机别。
坑 8:把 fstab 改成 rm /etc/fstab 解决问题
mv /etc/fstab /etc/fstab.bak # 应急清空
# 重启之后只有 / 还在
可以但根分区必须有——否则 / 都挂不上。生成最小 fstab:
UUID=<根分区 UUID> / ext4 defaults,errors=remount-ro 0 1
坑 9:tmpfs 写 fstab 但没限大小
tmpfs /tmp tmpfs defaults 0 0 ← 没 size,默认 50% 内存
/tmp 会吃到一半内存。永远加 size=:
tmpfs /tmp tmpfs defaults,nosuid,nodev,size=2G 0 0
坑 10:自动 mount 的 systemd hang
系统启动卡在 A start job is running for /mnt/nfs ... 几分钟。 原因:NFS server 不通、systemd 默认等很久。
修:
nfs:/exports /mnt/nfs nfs defaults,_netdev,nofail,x-systemd.mount-timeout=10s 0 0
x-systemd.mount-timeout=10s 让 systemd 最多等 10 秒。
关联命令
- mount ——
mount -a验证 fstab - mkfs —— fstab 之前要先 mkfs
blkid—— 拿 UUID / LABEL / TYPEfindmnt --verify—— 验证 fstab 一致性systemctl list-units --type=mount—— 看 systemd 转换的 mount unit- journalctl —— 启动失败时排查
- lsblk —— 看盘和分区