Зачем NFS
Network File System, стандартный способ "примонтировать чужой диск по сети" в Unix. Прозрачно: open/read/write/close работают как с локальной ФС, всё кэшируется страничным кэшем. Используется для:
- Shared home directories в корпоративных сетях
- Storage для VM-images (KVM, Proxmox)
- ML-датасеты, расшаренные между GPU-нодами
- Backup-таргеты
- Kubernetes Persistent Volumes (NFS-CSI driver)
Альтернативы: SMB/CIFS (Windows-родной), [[cmd-rsync|rsync]] (для периодической синхронизации, не live-mount), CephFS/GlusterFS (распределённое), object-storage (S3, для не-POSIX).
NFSv3 vs NFSv4
| Признак | v3 (1995) | v4.0 (2003) / v4.1 (2010) |
|---|---|---|
| State | stateless | stateful |
| Транспорт | UDP или TCP | TCP only |
| Порты | 111 (rpcbind) + динамические | 2049 single port |
| Lock manager | rpc.lockd (отдельный) | встроенный |
| Auth | sys (uid/gid из RPC) | + Kerberos (krb5/krb5i/krb5p) |
| Делегации | нет | да (read/write delegation) |
| pNFS | нет | да в v4.1 (parallel NFS) |
| ACL | POSIX через protocol-extension | NFSv4 ACL (Windows-style) |
| Через NAT/firewall | сложно (динамические порты) | просто (one port) |
NFSv3 ещё жив в legacy и embedded; для нового кода NFSv4.1+.
Сервер: /etc/exports
# Установка
apt install nfs-kernel-server # Debian/Ubuntu
dnf install nfs-utils # RHEL
# Создать share
mkdir -p /srv/nfs/data
chown nobody:nogroup /srv/nfs/data
/etc/exports:
/srv/nfs/data 10.0.0.0/24(rw,sync,no_subtree_check,root_squash)
/srv/nfs/backup 10.0.0.5(ro,sync,no_subtree_check) 10.0.0.6(rw,sync,no_subtree_check)
/srv/nfs/krb5 *(rw,sync,sec=krb5p,no_subtree_check)
Применить:
exportfs -ra # переэкспорт всех
exportfs -v # покажет активные exports
systemctl enable --now nfs-server
Главные опции exports
| Опция | Что |
|---|---|
rw / ro | права для подсети |
sync (default) | ответ клиенту только после fsync |
async | ответ сразу, fsync позже, быстрее, но при крахе сервера данные теряются |
root_squash (default) | root клиента маппится на nobody, защита |
no_root_squash | root клиента остаётся root'ом, очень опасно |
all_squash | все юзеры → nobody (для public-share) |
anonuid=, anongid= | в кого мапить squashed |
subtree_check / no_subtree_check | проверка что путь внутри export'а; no_subtree_check быстрее, default с modern |
| `sec=sys | krb5 |
nohide | для nested mount'ов на сервере |
crossmnt | пересекать mount-points при обходе |
Клиент: mount
apt install nfs-common # Debian
mount -t nfs server:/srv/nfs/data /mnt/data
mount -t nfs4 server:/srv/nfs/data /mnt/data
В [[mount-and-fstab|fstab]]:
server:/srv/nfs/data /mnt/data nfs4 rw,_netdev,vers=4.2,hard,timeo=600,retrans=3,nofail 0 0
Главные mount-опции:
| Опция | Что |
|---|---|
vers=4.2 | принудительная версия (default, auto-negotiate) |
hard (default) | при потере связи блокировать I/O пока не вернётся |
soft | возвращать I/O error после timeo*retrans мс, опасно, может портить данные |
timeo=N | timeout в децисекундах (600 = 60 сек) |
retrans=N | сколько повторов до признания "сервер мёртв" |
_netdev | сначала поднять сеть (для systemd) |
nolock | без NLM (для read-only mount'ов) |
nfsvers=3,proto=tcp,port=2049 | для жесткого pinning v3 |
noatime | как везде, выкл atime |
nconnect=N | (5.3+) N TCP-соединений к серверу, boost throughput |
hard vs soft: всегда hard. soft теоретически даёт failover,
на практике портит файлы при коротких сетевых разрывах.
Кэширование и согласованность
NFS не гарантирует строгого "записал на одной ноде → видно на другой
немедленно". Модель, close-to-open consistency: при close()
клиент flush'ит; при open() другой клиент проверяет mtime через
GETATTR и инвалидирует кэш.
Это значит: для shared-БД NFS не подходит (разные клиенты не увидят правки). Для shared home / build-output / ML-датасета, норм.
Kerberos: sec=krb5p
Без Kerberos NFS-клиент сам говорит свой UID через RPC AUTH_SYS доверие на уровне "у нас одни UID на всех машинах". В мульти-юзер enterprise-окружениях это слабо.
С sec=krb5p, каждая операция аутентифицирована Kerberos-тикетом
пользователя, payload зашифрован. Требует:
- KDC (kerberos)
- Service principal
nfs/server.example.com@REALMв keytab сервера idmapd.confдля маппингаuser@REALM→ UID на клиентах
Сложно, но единственный production-grade вариант для shared homes.
NFSv3 vs NFSv4 firewall
v3:
- 111 (portmap/rpcbind) TCP/UDP
- 2049 (nfs) TCP/UDP
- mountd, statd, lockd, rquotad, динамические порты!
- Решение:
/etc/nfs.confзафиксировать порты
v4:
- 2049 TCP only, всё через один порт, в т.ч. lock manager
- Через NAT работает без боли
Это одна из главных причин миграции на v4.
Когда что-то пошло не так
mount.nfs: Connection refused, nfs-server не запущен или не слушает 2049 (ss -tlnp | grep 2049).- Зависает
ls /mnt/dataнавсегда,hard-mount, сервер недоступен.umount -f -l /mnt/data(lazy umount). Stale file handle, файл удалён на сервере, клиент держит fd.umount && mountчинит. На v4.1+ менее частая проблема.- Чужие файлы видны как
nobody:nogroup, нет idmapd-маппинга. На NFSv4 убедись чтоnfs-idmapdзапущен иDomain =совпадает в/etc/idmapd.confна обоих. - Performance медленный на больших файлах,
wsize=1048576,rsize=1048576,nconnect=4(5.3+), и проверь jumbo frames на проводе. Permission deniedнесмотря на mode 777,root_squashмапит root'а в nobody. Создавай файлы от обычного юзера, либоno_root_squash(только в trusted-сети!).- Lockd не работает между host'ами, на v3 нужны
rpc.statd- portmap; на v4 встроено. Проверь firewall не режет статд-порт на v3.
Альтернативы
- SMB/CIFS (Samba), Windows-стандарт, работает и в Linux
- CephFS, distributed, replicated, для масштаба
- GlusterFS, то же, deprecated с поглощением Red Hat'а IBM
- sshfs (FUSE), туннель через SSH, для разовых случаев
- S3/MinIO, для не-POSIX object-storage