Systemd-Mount 解析

本文档详细介绍如何使用 systemd 的 .mount 单元来管理各种类型的挂载(CIFS、NFS、WebDAV、本地磁盘、ISO 镜像等),取代或补充传统的 /etc/fstab。systemd 挂载单元提供了更精确的依赖控制、按需挂载(automount)、失败处理等现代特性。

目录

  1. 基本概念

  2. 挂载单元命名规则

  3. 通用编写步骤

  4. 各类挂载示例

    • CIFS / SMB 网络共享

    • NFS 网络共享

    • WebDAV 共享

    • 本地磁盘(固定)

    • 外置热插拔硬盘

    • ISO 镜像文件

  5. 按需挂载 (automount)

  6. 启用、启动与验证

  7. 与 /etc/fstab 的关系

  8. 故障排除

  9. 常见问题


1. 基本概念

  • .mount 单元:systemd 中用于定义挂载点的配置文件,类似于 /etc/fstab 中的一行,但功能更强大。

  • .automount 单元:与 .mount 配对使用,实现“首次访问时自动挂载”,可减少启动时对网络或硬件的依赖。

  • 单元名称:基于挂载点路径转换而来,规则严格(见下文)。

  • 依赖与顺序:通过 AfterBeforeRequiresWants 等指令精确控制挂载时机。

2. 挂载单元命名规则

systemd 要求 .mount 单元的文件名必须等于其挂载点路径,并将路径中的 / 替换为 -,且以 .mount 结尾。

转换规则

  • 绝对路径去掉开头的 /,然后将所有 / 替换为 -

  • 如果路径中含有空格或特殊字符,需要使用 \x20\x2d 等十六进制转义(但建议避免使用空格)。

示例

挂载点路径

单元文件名

/mnt/data

mnt-data.mount

/mnt/backup

mnt-backup.mount

/home/user/My Drive

home-user-My\x20Drive.mount

/(根目录)

-.mount(特殊,一般不应手动创建)

重要:文件名必须精确匹配,否则 systemd 无法识别。

3. 通用编写步骤

  1. 创建单元文件
    使用文本编辑器(如 vimnano)创建文件:

    bash

    sudo nano /etc/systemd/system/<mount-unit-name>.mount
  2. 编写单元内容
    基本结构:

    ini

    [Unit]
    Description=描述信息
    After=依赖的目标或服务
    Wants=可选依赖
    
    [Mount]
    What=要挂载的设备或资源
    Where=挂载点绝对路径
    Type=文件系统类型
    Options=挂载选项(逗号分隔)
    TimeoutSec=超时秒数(可选)
    
    [Install]
    WantedBy=multi-user.target

    关键字段

    • [Unit] 中的 After:指定挂载必须在哪些单元之后启动(例如 network-online.target 用于网络文件系统)。

    • [Mount] 中的 Options:支持所有传统 mount 选项(noautoro_netdevnofail 等)。

    • [Install] 中的 WantedBy:通常设为 multi-user.target,表示系统进入多用户模式时挂载。

  3. 创建挂载点目录
    如果目录不存在,先创建:

    bash

    sudo mkdir -p /mnt/point
  4. 重新加载 systemd

    bash

    sudo systemctl daemon-reload
  5. 测试挂载

    bash

    sudo systemctl start <mount-unit-name>.mount
  6. 设置开机自动挂载

    bash

    sudo systemctl enable <mount-unit-name>.mount

4. 各类挂载示例

以下示例均需根据实际环境修改 WhatWhereOptions 等参数。

4.1 CIFS / SMB 网络共享

前置条件:容器或主机需安装 cifs-utils(Debian/Ubuntu: apt install cifs-utils

ini

[Unit]
Description=Mount NAS Downloads
After=network-online.target
Wants=network-online.target

[Mount]
What=//192.168.1.15/downloads
Where=/mnt/fn/downloads
Type=cifs
Options=credentials=/etc/samba/creds,_netdev,nofail,vers=3.0
TimeoutSec=30

[Install]
WantedBy=multi-user.target

保存为 mnt-fn-downloads.mount

说明

  • credentials=/etc/samba/creds:存放用户名和密码的文件,格式:

    text

    username=myuser
    password=mypass
    domain=WORKGROUP
  • _netdev:标记为网络设备,系统会等待网络就绪。

  • nofail:挂载失败不阻塞启动。

  • vers=3.0:使用 SMB 3.0 协议。

4.2 NFS 网络共享

前置条件:安装 nfs-common(Debian/Ubuntu: apt install nfs-common

ini

[Unit]
Description=Mount NFS Export
After=network-online.target
Wants=network-online.target

[Mount]
What=192.168.1.100:/export/data
Where=/mnt/nfs_data
Type=nfs
Options=vers=4.2,noatime,_netdev,nofail

[Install]
WantedBy=multi-user.target

保存为 mnt-nfs_data.mount

提示:NFS 版本建议明确指定 vers=4.2vers=3

4.3 WebDAV 共享

前置条件:安装 davfs2

bash

sudo apt install davfs2
sudo usermod -aG davfs2 $USER   # 如果普通用户挂载

ini

[Unit]
Description=Mount WebDAV Share
After=network-online.target

[Mount]
What=https://example.com/remote.php/dav/files/user/
Where=/mnt/webdav
Type=davfs
Options=uid=1000,gid=1000,file_mode=0644,dir_mode=0755,_netdev,nofail
TimeoutSec=60

[Install]
WantedBy=multi-user.target

凭据配置
WebDAV 的用户名密码需要写入 /etc/davfs2/secrets(全局)或 ~/.davfs2/secrets(用户):

text

https://example.com/remote.php/dav/files/user/ username password

注意:如果挂载点为系统路径(如 /mnt/webdav),建议使用全局 secrets 文件并设置 uid=0,gid=0 或适当权限。

4.4 本地磁盘(固定)

适用于内置硬盘、SSD 等。使用 UUID 或 LABEL 代替设备名,避免设备名漂移。

ini

[Unit]
Description=Mount Internal Data Disk
After=local-fs.target

[Mount]
What=/dev/disk/by-uuid/3A2C-1E4F9A5B8C0D
Where=/mnt/data
Type=ext4
Options=defaults,noatime,nofail

[Install]
WantedBy=multi-user.target

保存为 mnt-data.mount

获取 UUIDlsblk -fblkid

4.5 外置热插拔硬盘

对于 USB 硬盘,推荐与 .automount 配合实现按需挂载,避免开机时因磁盘未插入而失败。

创建 .mount 单元

ini

# /etc/systemd/system/mnt-usbdrive.mount
[Unit]
Description=Mount External USB Drive

[Mount]
What=/dev/disk/by-uuid/4E5F-1234
Where=/mnt/usbdrive
Type=exfat
Options=defaults,uid=1000,gid=1000,nofail

[Install]
WantedBy=multi-user.target

创建对应的 .automount 单元

文件名必须与 .mount 一致,但扩展名为 .automount

bash

sudo nano /etc/systemd/system/mnt-usbdrive.automount

内容:

ini

[Unit]
Description=Automount External USB Drive

[Automount]
Where=/mnt/usbdrive
TimeoutIdleSec=300   # 空闲5分钟后自动卸载

[Install]
WantedBy=multi-user.target

启用

bash

sudo systemctl enable --now mnt-usbdrive.automount

现在访问 /mnt/usbdrive 时会自动挂载;空闲 300 秒后自动卸载。

4.6 ISO 镜像文件

ini

[Unit]
Description=Mount ISO Image
After=local-fs.target

[Mount]
What=/path/to/ubuntu-24.04.iso
Where=/mnt/iso
Type=iso9660
Options=loop,ro,nofail

[Install]
WantedBy=multi-user.target

保存为 mnt-iso.mount

5. 按需挂载 (automount)

.automount 单元可实现“第一次访问时挂载”,特别适合网络共享或可移动设备。创建步骤:

  1. 确保已有 .mount 单元文件。

  2. 创建同名 .automount 单元,指定 Where 字段(与 .mount 中的 Where 一致)。

  3. 启用 .automount 单元(不要直接启用 .mount 单元,否则会变成开机挂载)。

示例 mnt-backup.automount

ini

[Unit]
Description=Automount Backup Share

[Automount]
Where=/mnt/backup
TimeoutIdleSec=600

[Install]
WantedBy=multi-user.target

启用:

bash

sudo systemctl enable --now mnt-backup.automount

原理:systemd 会在 /mnt/backup 上设置一个“占位”,当任何进程访问该目录时,自动触发对应的 .mount 单元完成挂载。

6. 启用、启动与验证

6.1 常用命令

操作

命令

重新加载 systemd 配置

sudo systemctl daemon-reload

启动挂载单元(立即挂载)

sudo systemctl start <unit>.mount

停止挂载单元(卸载)

sudo systemctl stop <unit>.mount

启用开机自动挂载

sudo systemctl enable <unit>.mount

禁用开机自动挂载

sudo systemctl disable <unit>.mount

查看挂载状态

sudo systemctl status <unit>.mount

查看所有挂载单元

systemctl list-units --type=mount

查看失败记录

journalctl -u <unit>.mount -e

6.2 验证自动挂载是否生效

bash

# 检查单元是否已启用
systemctl is-enabled mnt-fn-downloads.mount

# 重启后检查是否已挂载
df -h /mnt/fn/downloads

7. 与 /etc/fstab 的关系

  • 优先级:systemd 会同时解析 /etc/fstab/etc/systemd/system/*.mount。如果同名挂载点同时存在于两者,自定义 .mount 单元会覆盖 fstab 条目(但可能产生警告)。

  • 最佳实践:一旦使用 .mount 单元管理某个挂载点,应将 /etc/fstab 中对应的行注释或删除,避免冲突和混淆。

  • fstab 转换:可以使用 systemd-fstab-generator 将 fstab 转换为动态单元,但自定义单元更具可读性和可维护性。

8. 故障排除

8.1 挂载失败,状态为 “failed”

  • 检查语法:systemctl status <unit>.mount 会显示错误信息。

  • 检查挂载点目录是否存在:mkdir -p /mnt/point

  • 手动测试挂载命令:例如 mount -t cifs //server/share /mnt/test -o options,看是否工作。

8.2 启用时提示 “Unit file … is masked”

  • 文件可能被屏蔽,解除屏蔽:sudo systemctl unmask <unit>.mount

8.3 网络文件系统挂载时提示 “Network is unreachable”

  • 确保 [Unit] 中有 After=network-online.target,并安装了 network-online.target(通常由 NetworkManager 或 systemd-networkd 提供)。

  • 在 LXC 容器中,可能需要添加 _netdev 并确认容器具有 CAP_NET_ADMIN 及 network 功能。

8.4 自定义单元被忽略,系统仍然使用 fstab

  • 检查单元文件名是否与挂载点路径严格匹配。

  • 运行 systemctl daemon-reload

  • 注释 fstab 中的对应行。

8.5 外置硬盘的 automount 不生效

  • 确保 .automount 单元已启用且处于活动状态:systemctl status <unit>.automount

  • 检查 Where 是否与 .mount 中的 Where 完全一致。

  • 手动触发:ls /mnt/usbdrive 应该能激活挂载。

9. 常见问题

Q: 可以在 .mount 单元中使用环境变量吗?
A: 不能直接使用。但可以通过 systemctl set-environmentEnvironmentFile=[Service] 类型单元中使用,不过对 [Mount] 不适用。建议直接用绝对路径。

Q: 如何给挂载单元添加前置脚本(如创建目录)?
A: 使用 ExecStartPre= 只能在 .service 单元中使用。对于挂载,最好在单元文件外手动创建目录,或者使用 mountdir_mode 选项。另一种做法:编写一个包装服务,先执行脚本,再启动挂载。

Q: 多个挂载点之间有依赖(如先挂载 A 再挂载 B)?
A: 在 B 的 .mount 单元的 [Unit] 中使用 After=A.mountRequires=A.mount

Q: 如何让挂载点在网络启动后才尝试,但失败不阻塞启动?
A: 使用 After=network-online.target + nofail 挂载选项。

Q: 如何临时挂载一个 systemd 单元定义的挂载点?
A: systemctl start <unit>.mount。停止则 systemctl stop

Q: 如何在 LXC 无特权容器中使用 systemd 挂载?
A: 无特权容器无法直接挂载 CIFS/NFS,因为需要内核权限。解决方案:在宿主机挂载,然后通过 bind mount 传入容器(参考 Proxmox 的 mpX 配置)。

10. 总结

Systemd 挂载单元提供了一个强大、灵活、可脚本化的挂载管理方法,适用于从简单的本地磁盘到复杂的远程存储。通过遵循命名规则、编写清晰的 [Mount][Install] 段落,并搭配 .automount 实现按需挂载,可以完全摆脱 /etc/fstab 的限制。结合 systemctl 命令进行管理和排错,你将拥有一个现代 Linux 系统下的标准化挂载方案。

最后建议:对于重要的生产环境挂载,始终保留单元文件的备份,并用 systemctl enable 确保开机生效。记录每次修改,定期检查日志。

评论