Vous déployez un conteneur parfaitement banal. Il écrit quelques fichiers. Puis, à 02:17, tout se fige comme s’il attendait une autorisation.
df se bloque. Les threads de votre application s’accumulent. Les logs Docker n’indiquent rien d’utile. Le seul indice est une traînée de « nfs: server not responding ».
NFS dans des environnements conteneurisés échoue de manières qui ressemblent à des bugs applicatifs, des bugs du noyau ou des « vibes réseau ».
En général, ce n’est aucune de ces choses. C’est la sémantique de montage qui entre en collision avec des fautes réseau transitoires, des surprises DNS et un driver de volume qui ne vous dit pas ce qu’il a fait.
Pourquoi les volumes NFS Docker arrivent en timeout (et pourquoi ça semble aléatoire)
Les « volumes NFS » de Docker ne sont que des montages NFS Linux créés par l’hôte, puis bind-montés dans les conteneurs.
Ça paraît simple, et ça l’est—jusqu’à ce que vous vous rappeliez que NFS est un système de fichiers réseau avec une sémantique de retry,
des timeouts RPC, du verrouillage et de l’état.
La plupart des « timeouts » ne sont pas un unique timeout
Quand quelqu’un rapporte « NFS a time-out », il veut généralement dire une des choses suivantes :
- Le client réessaie indéfiniment (
hardmount) et le thread de l’application bloque en sommeil non interruptible (étatD). Cela ressemble à un blocage. - Le client a abandonné (
softmount) et a renvoyé une erreur d’E/S. Cela ressemble à de la corruption, des écritures échouées ou « mon appli error aléatoirement ». - Le serveur est parti puis revenu, mais la vue du client sur l’export ne correspond plus (stale file handles). On a l’impression que « ça marchait hier ».
- Problèmes de plomberie RPC (surtout NFSv3 : portmapper/rpcbind, mountd, lockd) provoquent des échecs partiels où certaines opérations fonctionnent et d’autres timeout.
- Fluctuations de résolution de nom ou de routage provoquent des blocages intermittents qui se rétablissent seuls. Ce sont les pires car elles nourrissent les superstitions.
Docker amplifie les modes de panne
NFS est sensible au timing des montages. Docker est très bon pour démarrer des conteneurs rapidement, en parallèle, et parfois avant que le réseau soit prêt.
Si le montage NFS est déclenché à la demande, votre « démarrage de conteneur » devient « démarrage de conteneur plus réseau plus DNS plus réactivité du serveur ».
C’est acceptable en labo. En production, c’est une façon élaborée de transformer une petite gigue réseau en panne majeure.
Hard vs soft n’est pas un réglage de performance ; c’est une décision de risque
Pour la plupart des charges avec état, la valeur sûre par défaut est hard : continuer à réessayer, ne pas prétendre que les écritures ont réussi.
Mais les montages hard peuvent suspendre des processus quand le serveur est inaccessible. Votre travail consiste donc à rendre « serveur inaccessible » rare et bref,
et à rendre le montage résilient face au chaos normal des réseaux.
Il y a une idée paraphrasée de Werner Vogels (CTO d’Amazon) qui vaut la peine d’être gardée en tête : « Tout échoue, donc concevez pour l’échec. »
Les montages NFS sont précisément l’endroit où cette philosophie cesse d’être inspirante et devient une checklist.
Faits et contexte intéressants (brefs, concrets, utiles)
- NFS précède les conteneurs de plusieurs décennies. Il est né dans les années 1980 pour partager des fichiers sur un réseau sans complexité d’état côté client.
- NFSv3 est en grande partie sans état. Cela simplifiait certains basculements, mais repoussait la complexité vers des daemons auxiliaires (rpcbind, mountd, lockd).
- NFSv4 a consolidé les canaux latéraux. v4 utilise typiquement un port bien connu (2049) et intègre verrouillage et état, ce qui améliore souvent la compatibilité avec les pare-feux et le NAT.
- « Hard mount » est le défaut historique pour une raison. Perdre des données silencieusement est pire qu’attendre ; les montages
hardprivilégient la correction plutôt que la disponibilité. - Le client NFS Linux a plusieurs couches de timeouts. Il y a le timeout par RPC (
timeo), le nombre de retransmissions (retrans) et des comportements de récupération de plus haut niveau. - Les stale file handles sont une taxe classique de NFS. Ils surviennent quand la correspondance inode/handle côté serveur change sous le client—fréquent après un basculement serveur ou des changements d’export.
- NFS sur TCP n’a pas toujours été le défaut. UDP était populaire au départ ; TCP est maintenant le choix sensé pour la fiabilité et le contrôle de congestion.
- Le DNS compte plus que vous ne le pensez. Les clients NFS peuvent mettre en cache la résolution nom→IP différemment de votre application ; un changement DNS en vol peut produire des symptômes « la moitié du monde fonctionne ».
Blague #1 : NFS, c’est comme une imprimante partagée au bureau—quand ça marche, personne ne le remarque ; quand ça ne marche pas, tout le monde a soudain des documents « business-critical » urgents.
Mode opératoire de diagnostic rapide (trouver le goulot vite)
L’objectif n’est pas de « collecter chaque métrique ». L’objectif est de décider, rapidement, si vous avez un problème de chemin réseau,
un problème serveur, un problème de sémantique de montage côté client, ou un problème d’orchestration Docker.
Voici l’ordre qui fait gagner du temps.
Première étape : confirmer que c’est NFS et pas l’application
- Sur l’hôte Docker, essayez un simple
statoulssur le chemin monté. Si ça bloque, ce n’est pas votre appli. C’est le montage. - Vérifiez
dmesgpour server not responding / timed out / stale file handle. Les messages noyau sont directs et généralement fiables.
Deuxième étape : décider « réseau vs serveur » avec un test
- Depuis le client, vérifiez la connectivité vers le port 2049 et (si vous utilisez NFSv3) rpcbind/portmapper. Si vous ne pouvez pas vous connecter, cessez de blâmer les options de montage.
- Depuis un autre hôte sur le même segment réseau, testez la même chose. Si le problème est isolé à un seul client, suspectez un pare-feu local, une exhaustion de conntrack, un MTU, ou une mauvaise route.
Troisième étape : vérifier la version du protocole et les options de montage
- Vérifiez si vous êtes en NFSv3 ou NFSv4. Beaucoup de timeouts « aléatoires » sont en réalité des problèmes rpcbind/mountd de NFSv3 dans les réseaux modernes.
- Confirmez
hard,timeo,retrans,tcp, et si vous avez utiliséintr(comportement obsolète) ou d’autres flags legacy.
Quatrième étape : inspecter les logs et la saturation côté serveur
- La moyenne de charge serveur n’est pas suffisante. Regardez les threads NFS, la latence disque, et les pertes réseau.
- Si le serveur est un appliance NAS, identifiez s’il est CPU-bound (chiffrement, checksum) ou I/O-bound (disques, rebuild, suppression de snapshot).
Si vous faites ces quatre phases, vous pouvez généralement nommer la classe de panne en moins de dix minutes. La partie longue, c’est la politique.
Options de montage qui améliorent la stabilité (faites ça, pas des intuitions)
Les « meilleures » options de montage dépendent de si vous privilégiez la correction ou la disponibilité quand le réseau se comporte mal.
Pour la plupart des systèmes de production avec écritures d’état, je penche vers la correction : montages hard,
timeouts conservateurs, et choix de protocole qui réduisent les éléments mobiles.
Base : ce que je déploierais pour des volumes NFS Docker polyvalents
Utilisez NFSv4.1+ quand vous le pouvez. Utilisez TCP. Évitez les options qui « font disparaître » les erreurs en renvoyant un succès prématurément.
La stabilité tient surtout à un comportement de panne prévisible.
- Préférer :
vers=4.1(ou 4.2 si supporté),proto=tcp,hard,timeo=600,retrans=2,noatime - Considérer :
nconnect=4(client Linux) pour le débit et une certaine résilience,rsize/wsizeuniquement si vous avez des preuves - Éviter par défaut :
soft,nolock(sauf si vous comprenez vraiment les besoins de verrouillage), des réglages agressifs detimeo, et UDP
Hard vs soft : explicitez le compromis
hard signifie que les appels système peuvent bloquer jusqu’à ce que le serveur réponde, potentiellement indéfiniment. Cela vous protège contre la perte silencieuse de données.
Cela signifie aussi que votre processus peut se bloquer quand le serveur est inaccessible. C’est à la fois un avantage et une responsabilité.
soft signifie que le noyau renvoie une erreur après des retries. C’est tentant car ça « débloque » vos conteneurs.
Ça encourage aussi les écritures partielles, les sorties corrompues et des applications qui ne gèrent pas EIO correctement (la plupart ne le font pas).
Si vous choisissez soft, faites-le pour des charges en lecture seule ou de type cache, et traitez les erreurs comme attendues.
Pour les bases de données, queues et tout ce qui a des garanties de durabilité : n’en utilisez pas.
Choisir NFSv4 quand vous le pouvez, surtout sur les plateformes conteneurisées
NFSv3 nécessite rpcbind et mountd pour la négociation initiale du montage, plus lockd/statd pour le verrouillage. Ce sont des dépendances et des ports supplémentaires.
Dans des réseaux complexes—pare-feux, réseaux overlay, NAT, security groups—ce sont autant de façons de tomber en panne.
NFSv4 consolide une grande partie de ça sur le port 2049 et un protocole avec état. Cet état peut introduire ses propres problèmes,
mais dans des fermes de conteneurs réelles il réduit en général les échecs de montage « aléatoires ».
timeo et retrans : arrêtez de les traiter comme des nombres magiques
timeo est le timeout de base RPC (en dixièmes de seconde pour de nombreux montages). Le client recule ensuite.
retrans est le nombre de fois pour réessayer un RPC avant d’enregistrer un événement « not responding » (pour soft) ou de continuer à réessayer (pour hard).
Une posture raisonnable de stabilité :
- Ne pas trop descendre. Des timeouts trop petits amplifient la gigue transitoire en pannes.
- Ne pas aller trop haut sans réflexion. Des timeouts énormes peuvent masquer une vraie panne trop longtemps et retarder les comportements de basculement en amont.
- Baisser retrans, timeo modéré fonctionne souvent : échouer « assez vite » au niveau RPC, mais quand même réessayer de façon prévisible au niveau montage.
nconnect : un outil moderne à manipuler avec précaution
nconnect crée plusieurs connexions TCP vers le serveur NFS pour un seul montage. Cela peut améliorer le débit et réduire le head-of-line blocking.
Ça peut aussi augmenter la charge serveur, exposer des limites firewall/conntrack, et rendre le debug plus « amusant » car il y a plus d’un flux.
Utilisez-le quand vous avez des preuves d’une saturation mono-connexion, et après avoir validé la capacité serveur et les tables d’état réseau.
Si votre problème est des timeouts dus à de la perte de paquets ou une surcharge serveur, nconnect peut empirer les choses.
Options de verrouillage : ne désactivez pas les verrous pour arrêter les timeouts
nolock est un « fix » courant qui échange des timeouts contre des bugs de correction. Il peut aider pour certains problèmes lockd de NFSv3,
mais il casse aussi les applications qui comptent sur les verrous POSIX ou des patterns de verrouillage coopératif.
Dans des flottes de conteneurs, vous avez rarement la mémoire institutionnelle pour savoir qui dépend des verrous. Donc ne faites pas ça à la légère.
Mise en cache d’attributs et cohérence : choisissez votre poison consciemment
Des options comme actimeo, acregmin, acregmax, acdirmin, acdirmax et nocto impactent la rapidité avec laquelle les clients remarquent les changements.
Une mise en cache agressive peut réduire le trafic métadonnées et améliorer les performances.
Elle peut aussi faire croire à votre appli qu’un fichier n’existe pas (encore) ou qu’il est toujours en ancienne version.
Pour des charges en écriture partagée, gardez la mise en cache conservatrice.
Pour des assets majoritairement en lecture, vous pouvez augmenter la mise en cache, mais vérifiez que votre modèle de déploiement ne déclenchera pas de « visibilité retardée ».
Quand envisager bg, automount et l’ordonnancement systemd
Beaucoup de « timeouts » NFS Docker ne surviennent pas à l’exécution ; ce sont des problèmes d’ordre au démarrage.
Votre hôte démarre, Docker démarre, les conteneurs démarrent, puis la pile réseau finit de négocier les routes.
Les montages NFS qui se produisent pendant cette fenêtre se comportent mal.
Une solution pratique est d’utiliser des unités automount systemd ou au moins de s’assurer que les montages requièrent network-online.
Docker démarre volontiers des conteneurs et les bloque sur les E/S ; vous voulez que le montage soit prêt avant que les workloads en dépendent.
Blague #2 : La façon la plus facile de réduire les timeouts NFS est d’arrêter de les appeler « timeouts » et de commencer à les appeler « opportunités de carrière futures ».
Patrons de configuration Docker qui ne vous sabordent pas
Patron 1 : driver local Docker avec options NFS (correct, mais vérifiez ce qui a été monté)
Le driver local de Docker peut monter NFS en utilisant type=nfs et o=....
C’est courant dans Compose et Swarm.
Le piège : les gens supposent que Docker « fait quelque chose d’intelligent ». Il ne le fait pas. Il transmet les options à l’helper de montage.
Si l’helper de montage revient à une autre version ou ignore une option, vous pouvez ne pas le remarquer.
Patron 2 : pré-monter sur l’hôte puis bind-monter dans les conteneurs (souvent plus prévisible)
Si vous pré-montez via /etc/fstab ou des unités mount systemd, vous pouvez contrôler l’ordonnancement, les retries, et observer le montage directement.
Docker se contente ensuite de bind-monter un chemin local. Cela réduit la « magie Docker », ce qui est généralement bon pour dormir tranquille.
Patron 3 : séparer les montages par classe de workload
N’utilisez pas un export NFS et un jeu d’options pour tout.
Traitez NFS comme un service avec des SLO : métadonnées basse latence (caches CI), débit en masse (média), correction d’abord (données applicatives).
Différents montages, différentes options, différentes attentes.
Tâches pratiques : commandes, sortie et la décision que vous prenez
Ce sont les actions de l’astreinte qui transforment « NFS est instable » en une action claire. Exécutez-les sur l’hôte Docker sauf indication contraire.
Chaque tâche inclut (1) la commande, (2) ce que signifie la sortie, (3) la décision à prendre.
Task 1: Identify which mounts are NFS and how they’re configured
cr0x@server:~$ findmnt -t nfs,nfs4 -o TARGET,SOURCE,FSTYPE,OPTIONS
TARGET SOURCE FSTYPE OPTIONS
/var/lib/docker-nfs nas01:/exports/appdata nfs4 rw,relatime,vers=4.1,rsize=1048576,wsize=1048576,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=10.10.8.21
Signification : Confirme la version NFS, le proto, et si vous êtes en hard ou soft. Montre aussi si rsize/wsize sont énormes et potentiellement non appariés.
Décision : Si vous voyez vers=3 de façon inattendue, prévoyez de passer à v4 ou auditez les ports rpcbind/mountd. Si vous voyez soft sur des workloads intensifs en écriture, changez cela.
Task 2: Confirm Docker volume configuration (what Docker thinks it asked for)
cr0x@server:~$ docker volume inspect appdata
[
{
"CreatedAt": "2026-01-01T10:12:44Z",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/appdata/_data",
"Name": "appdata",
"Options": {
"device": ":/exports/appdata",
"o": "addr=10.10.8.10,vers=4.1,proto=tcp,hard,timeo=600,retrans=2,noatime",
"type": "nfs"
},
"Scope": "local"
}
]
Signification : C’est la configuration, pas la vérité. Les options de Docker peuvent être correctes alors que le montage réel diffère.
Décision : Comparez avec findmnt. Si elles diffèrent, dépannez l’helper de montage, les valeurs par défaut et le support noyau.
Task 3: Look for kernel NFS client errors right now
cr0x@server:~$ dmesg -T | egrep -i 'nfs:|rpc:|stale|not responding|timed out' | tail -n 20
[Fri Jan 3 01:58:41 2026] nfs: server nas01 not responding, still trying
[Fri Jan 3 01:59:12 2026] nfs: server nas01 OK
Signification : « Not responding, still trying » indique un hard mount en train de réessayer pendant une perturbation.
Décision : Si ces événements correspondent aux blocages applicatifs, enquêtez sur des pertes réseau ou des blocages serveur ; ne « fixez » pas l’appli.
Task 4: Confirm the process states during a hang (is it stuck in D-state?)
cr0x@server:~$ ps -eo pid,stat,comm,wchan:40 | egrep 'D|nfs' | head
8421 D php-fpm nfs_wait_on_request
9133 D rsync nfs_wait_on_request
Signification : État D avec nfs_wait_on_request indique un I/O noyau bloqué en attente de NFS.
Décision : Considérez cela comme un incident d’infrastructure. Redémarrer des conteneurs n’aidera pas si le montage est bloqué en hard.
Task 5: Check basic TCP connectivity to the NFS server
cr0x@server:~$ nc -vz -w 2 10.10.8.10 2049
Connection to 10.10.8.10 2049 port [tcp/nfs] succeeded!
Signification : Le port 2049 est joignable maintenant.
Décision : Si cela échoue pendant l’incident, vos options de montage ne sont pas le problème principal ; corrigez le routage, les ACL, le pare-feu ou la disponibilité du serveur.
Task 6: If using NFSv3, confirm rpcbind is reachable (common hidden dependency)
cr0x@server:~$ nc -vz -w 2 10.10.8.10 111
Connection to 10.10.8.10 111 port [tcp/sunrpc] succeeded!
Signification : rpcbind/portmapper joignable. Sans cela, les montages NFSv3 peuvent échouer ou se bloquer pendant la négociation.
Décision : Si le port 111 est bloqué et que vous êtes en v3, passez à v4 ou ouvrez les ports nécessaires correctement (et documentez-les).
Task 7: Identify NFS version negotiated and server address used (catch DNS surprises)
cr0x@server:~$ nfsstat -m
/var/lib/docker-nfs from nas01:/exports/appdata
Flags: rw,hard,noatime,vers=4.1,rsize=1048576,wsize=1048576,namlen=255,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=10.10.8.21,local_lock=none
Signification : Confirme les paramètres négociés. Notez le nom du serveur vs l’IP, et tout comportement local_lock.
Décision : Si le montage utilise un nom d’hôte et que votre DNS est instable, basculez sur l’IP ou épinglez des entrées host—puis planifiez une meilleure stratégie DNS.
Task 8: Measure retransmits and RPC-level pain (is it packet loss?)
cr0x@server:~$ nfsstat -rc
Client rpc stats:
calls retrans authrefrsh
148233 912 148245
Signification : Les retransmits indiquent des RPC qui ont dû être renvoyés. Une augmentation de retrans corrèle avec perte, congestion ou blocage serveur.
Décision : Si retrans saute pendant des incidents, inspectez les pertes réseau et la charge serveur ; envisagez d’augmenter timeo modérément, pas de le diminuer.
Task 9: Check interface errors and drops (don’t guess)
cr0x@server:~$ ip -s link show dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
RX: bytes packets errors dropped missed mcast
128G 98M 0 127 0 1234
TX: bytes packets errors dropped carrier collsns
141G 92M 0 84 0 0
Signification : Des drops en RX/TX peuvent suffire à déclencher « not responding » NFS sous charge.
Décision : Si les drops augmentent, enquêtez sur les rings NIC, les mismatches MTU, la congestion du switch ou la saturation CPU de l’hôte.
Task 10: Spot MTU mismatch quickly (jumbo frames are innocent until proven guilty)
cr0x@server:~$ ping -c 3 -M do -s 8972 10.10.8.10
PING 10.10.8.10 (10.10.8.10) 8972(9000) bytes of data.
From 10.10.8.21 icmp_seq=1 Frag needed and DF set (mtu = 1500)
From 10.10.8.21 icmp_seq=2 Frag needed and DF set (mtu = 1500)
From 10.10.8.21 icmp_seq=3 Frag needed and DF set (mtu = 1500)
--- 10.10.8.10 ping statistics ---
3 packets transmitted, 0 received, +3 errors, 100% packet loss, time 2043ms
Signification : Le MTU du chemin est 1500, mais votre hôte pense 9000. Cela provoque du blackholing et des stalls « aléatoires ».
Décision : Corrigez le MTU bout en bout ou baissez à 1500. Puis réévaluez la stabilité NFS avant de toucher aux options de montage.
Task 11: Confirm the server export exists and permissions are sane (server-side view)
cr0x@server:~$ showmount -e 10.10.8.10
Export list for 10.10.8.10:
/exports/appdata 10.10.8.0/24
/exports/shared 10.10.0.0/16
Signification : Montre les exports (utile surtout pour NFSv3 ; pour v4 c’est toujours un indice utile).
Décision : Si l’export n’est pas listé ou que le sous-réseau client n’est pas autorisé, arrêtez de tuner le client et corrigez la politique d’export.
Task 12: Capture a short NFS packet trace during the event (prove loss vs server silence)
cr0x@server:~$ sudo tcpdump -i eth0 -nn host 10.10.8.10 and port 2049 -c 30
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
10:02:11.101223 IP 10.10.8.21.51344 > 10.10.8.10.2049: Flags [P.], seq 219:451, ack 1001, win 501, length 232
10:02:12.102988 IP 10.10.8.21.51344 > 10.10.8.10.2049: Flags [P.], seq 219:451, ack 1001, win 501, length 232
10:02:13.105441 IP 10.10.8.21.51344 > 10.10.8.10.2049: Flags [P.], seq 219:451, ack 1001, win 501, length 232
Signification : Retransmissions répétées sans réponses serveur indiquent serveur non-réactif ou réponses non retournées.
Décision : Si vous voyez des retransmissions client sans réponse serveur, passez à la santé serveur / chemin de retour réseau. Si vous voyez des réponses serveur mais que le client retransmet encore, suspectez un routage asymétrique ou un pare-feu d’état.
Task 13: Check Docker daemon logs for mount attempts and failures
cr0x@server:~$ journalctl -u docker --since "30 min ago" | egrep -i 'mount|nfs|volume|rpc' | tail -n 30
Jan 03 09:32:14 server dockerd[1321]: time="2026-01-03T09:32:14.112345678Z" level=error msg="error while mounting volume 'appdata': failed to mount local volume: mount :/exports/appdata:/var/lib/docker/volumes/appdata/_data, data: addr=10.10.8.10,vers=4.1,proto=tcp,hard,timeo=600,retrans=2,noatime"
Signification : Confirme que Docker n’a pas pu monter, versus l’appli qui échoue plus tard.
Décision : Si les montages échouent au démarrage des conteneurs, priorisez la préparation réseau et la joignabilité du serveur ; ne courez pas après le tuning runtime.
Task 14: Inspect systemd ordering (network-online is not the same as network)
cr0x@server:~$ systemctl status network-online.target
● network-online.target - Network is Online
Loaded: loaded (/lib/systemd/system/network-online.target; static)
Active: active since Fri 2026-01-03 09:10:03 UTC; 1h 2min ago
Signification : Si cette target n’est pas active quand les montages se produisent, votre montage NFS peut être en concurrence avec la disponibilité réseau.
Décision : Si vous observez des problèmes d’ordonnancement, déplacez les montages vers des unités systemd avec After=network-online.target et Wants=network-online.target, ou utilisez automount.
Task 15: Validate that the mount is responsive (fast sanity check)
cr0x@server:~$ time bash -c 'stat /var/lib/docker-nfs/. && ls -l /var/lib/docker-nfs >/dev/null'
real 0m0.082s
user 0m0.004s
sys 0m0.012s
Signification : Les opérations basiques de métadonnées sont rapides. Si cela prend parfois des secondes ou se bloque, vous avez de la latence intermittente ou des stalls.
Décision : Si les métadonnées sont lentes, investiguez la latence disque serveur et la saturation des threads NFS ; les options de montage ne sauveront pas un serveur qui se noie.
Trois mini-histoires d’entreprise (comment ça casse en pratique)
1) Incident causé par une mauvaise hypothèse : « Le volume est local, parce que Docker a dit ‘local’ »
Une entreprise de taille moyenne exécutait un cluster Swarm pour des services internes. Une équipe a créé un volume Docker avec le driver local et des options NFS.
Tout le monde a lu « local » et a supposé que les données vivaient sur chaque nœud. Cette hypothèse a façonné tout : exercices de panne, fenêtres de maintenance, et même la propriété des incidents.
Pendant une maintenance réseau, un switch top-of-rack a vacillé. Seuls certains nœuds ont perdu la connectivité avec le NAS pendant quelques secondes.
Les nœuds affectés avaient des volumes NFS montés en hard. Leurs conteneurs ne sont pas tombés ; ils ont juste cessé de progresser. Les health checks ont expiré.
L’orchestrateur a commencé à rescheduler, mais de nouvelles tâches sont tombées sur les mêmes nœuds dégradés car le scheduler ne connaissait pas le goulot NFS.
La réponse en astreinte était classique : redémarrer le service. Cela n’a fait que créer plus de processus bloqués. Quelqu’un a essayé de supprimer et recréer le volume.
Docker a obéi, mais le montage noyau était toujours coincé. L’hôte est devenu un musée de tâches figées.
La correction n’a pas été héroïque. Ils ont documenté que « driver local » peut être du stockage distant, ajouté une vérification pré-déploiement dans les pipelines pour vérifier le type de montage avec findmnt,
et isolé les services critiques NFS des nœuds qui ne pouvaient pas atteindre le VLAN de stockage.
Le plus grand changement a été culturel : le stockage a cessé d’être « le problème de quelqu’un d’autre » dès que les conteneurs sont entrés en jeu.
2) Optimisation qui s’est retournée contre eux : « Nous avons diminué les timeouts pour que les pannes échouent vite »
Une autre organisation avait un problème intermittent : les applications se figeaient quand NFS hiccupait. Quelqu’un a proposé un changement « simple » :
passer en soft, diminuer timeo, et augmenter retrans pour que le client abandonne rapidement et que l’appli s’en occupe.
Ça semblait raisonnable sur le papier.
En pratique, les applications n’étaient pas conçues pour gérer des EIO en plein écrit.
Un worker écrivait dans un fichier temporaire puis le renameait en place. Sous des montages soft et des timeouts bas,
l’écriture échouait parfois mais le workflow ne remontait pas toujours l’erreur. Le rename s’est produit avec du contenu partiel.
Les tâches en aval ont traité des données corrompues.
L’incident n’a pas été une coupure nette ; c’était pire. Le système est resté « up » tout en produisant des résultats faux.
Cela a déclenché une réponse au ralenti : rollback, retraitement, audit des sorties. Finalement les options de montage ont été rétablies.
Puis ils ont corrigé le vrai problème : perte de paquets intermittente due à une liaison LACP mal configurée et un mismatch MTU qui n’apparaissait qu’en charge.
La leçon inscrite dans leur runbook était douloureusement précise : « Fail fast » est excellent quand l’échec est correctement exposé.
Les montages soft ont rendu l’échec plus facile à ignorer, pas plus facile à gérer.
3) Pratique ennuyeuse mais correcte qui a sauvé la mise : pré-mount + automount + dépendances explicites
Une entreprise financière exécutait des jobs batch stateful en conteneurs, écrivant des artéfacts sur NFS.
Ils avaient une règle terne : les montages NFS sont gérés par systemd, pas par la création de volumes Docker à l’exécution.
Chaque montage avait une unité automount, un timeout défini, et une dépendance sur network-online.target.
Un matin, un cycle de reboot routinier a touché un nœud pendant que le NAS était en maintenance. Le NAS était joignable mais lent pendant quelques minutes.
Les conteneurs ont démarré, mais leurs chemins NFS ont été automountés seulement quand nécessaire. La tentative d’automount a attendu puis a réussi quand le NAS a récupéré.
Les jobs ont démarré avec un peu de retard, et personne ne s’est réveillé.
La différence n’était pas un meilleur matériel. C’était que le cycle de vie du montage n’était pas couplé au cycle de vie des conteneurs.
Docker n’a pas décidé du moment du montage, et les échecs étaient visibles au niveau système avec des logs clairs.
C’est le genre de pratique que les dirigeants ne félicitent jamais parce que rien ne s’est passé. C’est aussi la pratique qui vous garde en poste.
Erreurs fréquentes : symptôme → cause racine → correction
1) Symptom: containers « freeze » et ne veulent pas s’arrêter ; docker stop se bloque
Cause racine : montage NFS en hard bloqué ; processus en état D attendant l’I/O noyau.
Correction : restaurer la connectivité / la santé du serveur ; n’attendez pas des signaux qu’ils fonctionnent. Si vous devez récupérer un nœud, démontez après que le serveur soit revenu, ou redémarrez l’hôte en dernier recours. Prévenir par un réseau stable et des timeo/retrans raisonnables.
2) Symptom: « ça marche sur un nœud, timeouts sur un autre »
Cause racine : différences par nœud de routage/pare-feu/MTU, ou exhaustion de conntrack sur un sous-ensemble de nœuds.
Correction : comparez ip route, ip -s link et règles de pare-feu. Validez le MTU avec des pings DF. Assurez une configuration réseau identique sur toute la flotte.
3) Symptom: montages échouent au boot ou juste après le redémarrage de l’hôte
Cause racine : tentatives de montage qui rivalisent avec la disponibilité réseau ; Docker démarre les conteneurs avant que network-online soit vrai.
Correction : gérer les montages via des unités systemd avec un ordonnancement explicite, ou utiliser automount. Éviter les montages à la demande initiés par le démarrage des conteneurs.
4) Symptom: « permission denied » intermittent ou problèmes d’identité étranges
Cause racine : mismatch UID/GID, comportement root-squash, ou problèmes d’idmapping NFSv4. Les conteneurs aggravent cela car les espaces de noms utilisateurs et les utilisateurs d’images varient.
Correction : standardisez UID/GID pour les écrivains, validez les options d’export serveur, et pour NFSv4 confirmez la configuration d’idmapping. Ne masquer pas cela en mettant 0777 ; ce n’est pas de la stabilité, c’est une capitulation.
5) Symptom: fréquents « stale file handle » après un basculement NAS ou une maintenance d’export
Cause racine : la correspondance file-handle côté serveur a changé ; les clients conservent des références qui ne se résolvent plus.
Correction : évitez de déplacer/réécrire des exports sous les clients ; utilisez des chemins stables. Pour la récupération, remontez et redémarrez les workloads affectés. Pour l’architecture, préférez les méthodes HA stables supportées par votre NAS et testez le basculement avec de vrais clients.
6) Symptom: « montages aléatoires » seulement dans des réseaux sécurisés
Cause racine : ports dynamiques NFSv3 bloqués ; rpcbind/mountd/lockd non autorisés par les pare-feux / security groups.
Correction : passez à NFSv4 si possible. Si vous êtes contraint à v3, fixez les ports des daemons côté serveur et ouvrez-les intentionnellement—puis documentez-les pour que la prochaine personne ne « optimise » pas votre pare-feu.
7) Symptom: pics de latence élevés, puis récupération, qui se répètent sous charge
Cause racine : latence disque serveur (rebuild/snapshot), saturation des threads NFS, ou files réseau congestionnées.
Correction : mesurez la latence I/O côté serveur et les threads du service NFS ; corrigez le goulet. Les options client comme rsize/wsize ne sauveront pas un array saturé.
8) Symptom: passer à soft « corrige » les blocs mais introduit des problèmes de données mystérieux
Cause racine : les montages soft transforment les pannes en erreurs d’E/S ; les applications gèrent mal ces échecs partiels.
Correction : revenez à hard pour les écritures avec état, corrigez la connectivité sous-jacente, et mettez à jour les applications pour gérer les erreurs quand c’est approprié.
Checklists / plan étape par étape
Étape par étape : stabiliser un déploiement NFS Docker existant
- Inventoriez les montages avec
findmnt -t nfs,nfs4. Notezvers,proto,hard/soft,timeo,retrans, et si vous utilisez des noms d’hôtes. - Confirmez la réalité avec
nfsstat -m. Si Docker dit une chose et que le noyau en a monté une autre, faites confiance au noyau. - Décidez du protocole : préférez NFSv4.1+. Si vous êtes en v3, listez les dépendances firewall et les cas de panne que vous ne pouvez pas tolérer.
- Corrigez le réseau avant le tuning : validez le MTU bout en bout ; éliminez les drops d’interface ; vérifiez la symétrie de routage ; assurez la stabilité du port 2049.
- Choisissez la sémantique de montage :
- Écritures état :
hard,timeomodéré,retransplutôt bas, TCP. - Lecture seule / cache : envisagez
softseulement si votre appli gèreEIOet que vous acceptez « erreur plutôt que blocage ».
- Écritures état :
- Rendez les montages prédictibles : pré-montez via systemd ou utilisez automount. Évitez les montages à la demande déclenchés par le démarrage des conteneurs quand c’est possible.
- Testez la panne : débranchez le réseau serveur (en labo), redémarrez un client, faites flapper une route, et observez. Si votre test consiste à « attendre et espérer », ce n’est pas un test.
- Opérationnalisez : ajoutez des dashboards pour retransmits, drops d’interface, saturation des threads NFS serveur et latence disque. Ajoutez un runbook d’astreinte qui commence par le Mode opératoire de diagnostic rapide ci-dessus.
Une checklist courte pour les options de montage (priorité stabilité)
- Utilisez TCP :
proto=tcp - Privilégiez NFSv4.1+ :
vers=4.1(ou 4.2 si supporté) - Correction d’abord :
hard - Ne pas sur-tuner : commencez avec
timeo=600,retrans=2et ajustez seulement sur preuve - Réduire le churn métadonnées :
noatimepour les workloads typiques - Prudence avec
actimeoet semblables ; la mise en cache n’est pas une performance gratuite - Considérez
nconnectseulement après avoir mesuré la capacité serveur et firewall
FAQ
1) Dois-je utiliser NFSv3 ou NFSv4 pour les volumes Docker ?
Utilisez NFSv4.1+ sauf raison de compatibilité spécifique. Dans les réseaux riches en conteneurs, moins de daemons auxiliaires et de ports signifie généralement moins d’échecs « aléatoires » de montage.
2) soft est-il jamais acceptable ?
Oui—pour des données en lecture seule ou de type cache où une erreur d’E/S est préférable à un blocage, et où votre application est conçue pour traiter EIO comme normal. Pour des écritures avec état, c’est un piège dangereux.
3) Pourquoi docker stop se bloque quand NFS est down ?
Parce que les processus sont bloqués en I/O noyau sur un filesystem monté en hard. Les signaux ne peuvent pas interrompre un thread coincé en sommeil non interruptible. Corrigez la joignabilité du montage.
4) Que font réellement timeo et retrans ?
Ils gouvernent le comportement de retry RPC. timeo est le timeout de base pour un RPC ; retrans est le nombre de retries avant que le client n’enregistre « not responding » (et pour soft, avant d’échouer l’E/S).
5) Dois-je tuner rsize et wsize à des valeurs énormes ?
Pas par superstition. Les valeurs par défaut modernes sont souvent bonnes. Des valeurs surdimensionnées peuvent interagir mal avec le MTU, les limites serveur ou les pertes réseau. Faites le tuning seulement après avoir mesuré le débit et les retransmits.
6) Utiliser une IP au lieu d’un nom d’hôte aide-t-il ?
Ça peut aider. Si le DNS est instable, lent ou change de façon imprévue, utiliser une IP évite la résolution de nom comme dépendance de panne. Le compromis est de perdre la migration serveur facile à moins de gérer l’IP comme endpoint stable.
7) Qu’est-ce qui cause « stale file handle » et comment l’éviter ?
C’est généralement causé par des changements côté serveur qui invalident des file handles : déplacement de chemin d’export, comportement de basculement, ou changements de filesystem sous l’export. Évitez cela en gardant des exports stables et en utilisant des méthodes HA supportées par votre NAS, testées avec de vrais clients.
8) Dois-je monter via des volumes Docker ou pré-monter sur l’hôte ?
Pré-monter (mounts systemd/automount) est souvent plus prévisible et plus facile à déboguer. Le montage via volume Docker fonctionne, mais il couple le cycle de vie du montage à celui du conteneur, et ce n’est pas l’endroit où vous voulez faire reposer votre stratégie de fiabilité.
9) Et nolock pour réparer les blocs ?
Évitez-le sauf si vous êtes absolument sûr que votre workload ne dépend pas des verrous. Il peut « réparer » des problèmes liés à lockd en NFSv3 en désactivant le verrouillage, mais cela échange des pannes contre des bugs de correction.
10) Si mon serveur NFS va bien, pourquoi seuls certains clients voient des timeouts ?
Parce que « le serveur va bien » veut souvent dire « il répond au ping ». Les problèmes locaux au client comme mismatch MTU, routage asymétrique, limites conntrack et drops NIC peuvent casser sélectivement NFS tout en laissant d’autres trafics majoritairement corrects.
Conclusion : prochaines étapes pour réduire les alertes
Si vous luttez contre des timeouts de volumes NFS Docker, ne commencez pas par bidouiller timeo comme un bouton radio.
Commencez par nommer la panne : chemin réseau, saturation serveur, friction de version de protocole, ou timing d’orchestration.
Puis faites un choix délibéré sur la sémantique : montages hard correction-d’abord pour les écritures d’état, et soft très ciblé pour les données jetables.
Prochaines étapes pratiques à faire cette semaine :
- Auditez chaque hôte Docker avec
findmntetnfsstat -m; enregistrez les options réelles et la version NFS. - Standardisez sur NFSv4.1+ sur TCP sauf raison contraire.
- Corrigez MTU et compteurs de drops avant de changer le tuning des montages.
- Déplacez les montages critiques vers des montages gérés par systemd (idéalement automount) avec un ordonnancement explicite network-online.
- Rédigez un runbook basé sur le Mode opératoire de diagnostic rapide, et exercez-le une fois pendant une période calme.
Le but ultime n’est pas « NFS ne flanche jamais ». Le but est : quand ça flanche, que ça se comporte de manière prévisible, se rétablisse proprement, et ne transforme pas vos conteneurs en art moderne.