Cela commence par une plainte qui semble vague et inoffensive : « Le conteneur est lent. » Puis vous regardez de plus près et c’est toujours la même situation : un volume Docker reposant sur un partage CIFS/SMB, et une application qui touche des fichiers comme si on la payait au syscall.
Sur le papier, CIFS est « juste un système de fichiers réseau ». En production, c’est un amplificateur de latence enveloppant métadonnées, mappage des permissions, limites de cache et une croyance optimiste que votre charge est surtout des lectures séquentielles. Spoiler : votre charge ne l’est pas.
Ce que « volume CIFS lent » signifie réellement
Quand les gens disent « CIFS est lent », ils compressent généralement plusieurs modes de défaillance distincts en une seule phrase grincheuse :
- Latence élevée par opération : chaque
stat(), open, close, chmod, rename devient un aller-retour réseau (ou plusieurs). - Charges lourdes en métadonnées : gestionnaires de paquets de langage, checkouts git, applications web avec beaucoup de petits fichiers, tempêtes d’import Python, autoloaders PHP, Node
node_modules, scans de classpath Java. Ce sont les prédateurs naturels de CIFS. - Sémantiques de durabilité des écritures : SMB cherche à fournir des sémantiques compatibles Windows autour des verrous et de la cohérence. Ce n’est pas gratuit.
- Contraintes du cache côté client : Linux CIFS doit souvent sacrifier agressivité de cache pour la justesse, en particulier avec un accès multi-client.
- Mappage des permissions et traduction d’identité : pas glamour, mais cela ajoute de la surcharge et provoque des réessais et des surprises.
Autre point : Docker n’accélère pas magiquement CIFS. Les conteneurs facilitent simplement l’erreur consistante de placer une base de données sur un partage réseau, puis d’être surpris quand elle se comporte comme telle.
Règle dure : si votre appli effectue beaucoup de petits I/O aléatoires ou d’appels métadonnées, CIFS dans un conteneur est une taxe de performance que vous payez à chaque requête. Votre « débit » peut sembler bon dans un test de copie de gros fichiers et être inutilisable dans des charges réelles.
Faits et historique : pourquoi SMB se comporte ainsi
Un peu de contexte aide, car SMB/CIFS n’est pas lent parce qu’il est « mauvais ». Il est lent parce qu’il fait du travail que vous n’avez pas demandé, pour des clients que vous n’avez pas invités, à travers des réseaux que vous n’aviez pas prévus.
8 faits intéressants (brefs, concrets et utiles)
- « CIFS » correspond essentiellement à l’ancien dialecte SMB (ère SMB1). La plupart des configurations modernes sont SMB2/SMB3, mais les gens disent encore « CIFS » comme si c’était une marque.
- SMB1 était bavard par conception. SMB2 a réduit drastiquement les allers-retours, mais les charges avec beaucoup de métadonnées souffrent encore parce que le client a toujours besoin de réponses.
- SMB3 a ajouté chiffrement et multichannel. Excellent pour la sécurité et la résilience, parfois moins bon pour le CPU et la latence si mal configuré.
- Les opportunistic locks (oplocks) et leases existent pour améliorer le cache, mais ils introduisent du trafic d’invalidation et des sémantiques complexes en concurrence.
- Les sémantiques Windows comptent : SMB est conçu pour préserver le verrouillage et les modes de partage Windows. Les applications Linux qui supposent un comportement POSIX peuvent déclencher des vérifications supplémentaires.
- Linux CIFS utilise le client noyau (
cifs.ko) et il s’est amélioré, mais les contraintes de correction limitent encore le caching agressif dans les scénarios multi-écrivains. - Le coût des métadonnées domine sur les liens à haute latence : même 2–5 ms de RTT peuvent rendre « des milliers de petites opérations » aussi lentes que du sirop, indépendamment de la bande passante gigabit.
- Les volumes Docker ne sont pas un miracle d’abstraction de stockage : le noyau effectue toujours le même montage/I/O. Docker facilite juste le déploiement cohérent de l’erreur.
Les vraies causes profondes (pas les mythes)
Mythe : « C’est la bande passante. Il nous faut un réseau plus rapide. »
La bande passante compte pour les lectures/écritures séquentielles larges. La douleur des volumes CIFS dans les conteneurs est généralement des IOPS et de la latence plus une amplification des métadonnées. Vous pouvez avoir un lien 10 GbE et être quand même anéanti par 3 ms de RTT et 20k stat() par requête. Votre lien s’ennuiera pendant que votre appli est à genoux.
Mythe : « C’est la surcharge Docker. »
Docker ajoute un peu de surcharge dans des cas spécifiques (overlay filesystems, user namespaces, subtilités de propagation de montage). Mais pour un bind mount ou un volume nommé reposant sur CIFS, le coût dominant est la sémantique du système de fichiers réseau. Docker est surtout un innocent tenant le sac.
Réalité n°1 : la latence rend les charges métadonnées non linéaires
Si une requête déclenche 500 opérations métadonnées et que chacune coûte un aller-retour réseau, les maths sont brutales. CIFS peut pipeline et grouper certaines opérations, mais pas assez pour sauver une charge bavarde d’elle-même.
Réalité n°2 : le cache est contraint par la correction
Linux CIFS peut cacher des attributs et des entrées de répertoire, mais si plusieurs clients peuvent modifier le même arbre, le cache devient un passif. On peut régler le cache (plus loin), mais vous échangez toujours cohérence cross-client et correction contre vitesse.
Réalité n°3 : les conteneurs cachent les discordances d’identité et de permissions
À l’intérieur d’un conteneur, UID/GID peut ne pas correspondre à ce que le serveur SMB attend. Cela entraîne des vérifications de permission, des écritures échouées et parfois des comportements de repli. Même quand ça « marche », vous pouvez vous retrouver avec des tentatives supplémentaires de chown/chmod qui martèlent les chemins métadonnées.
Réalité n°4 : la signature/chiffrement SMB peut être une taxe CPU silencieuse
La signature et le chiffrement SMB sont utiles, souvent nécessaires, et parfois coûteux. Si un côté n’a pas d’accélération AES ou si vous bridez trop les CPU du conteneur, votre « problème de stockage » est en fait « le crypto vous bouffe ».
Réalité n°5 : les sémantiques de verrouillage mordent les bases et outils de build
SQLite, de nombreux systèmes de build et certains serveurs applicatifs s’appuient sur des verroux de fichier et des patterns fsync qui vont bien sur ext4/xfs local. Sur SMB, les sémantiques peuvent être plus lentes, ou pire, subtilement différentes. C’est comme ça qu’on obtient « lent » et « étrange » dans le même ticket.
Idée paraphrasée de Werner Vogels : « Tout échoue, tout le temps — concevez pour cela. » CIFS sur réseau échouera de façons plus créatives que votre disque local.
Playbook de diagnostic rapide
Voici l’ordre que j’utilise quand quelqu’un signale « volume CIFS lent » et que je veux une réponse avant le déjeuner.
1) Prouvez que c’est le montage (pas l’appli)
- Comparez la même opération sur CIFS et sur disque local : création de fichier, tempêtes de stat, petits writes.
- Vérifiez si le ralentissement se corrèle avec des opérations métadonnées plutôt qu’avec le débit.
2) Mesurez la latence, pas seulement le débit
- Ping RTT vers le serveur.
- Recherchez des retransmissions, de la congestion, des problèmes duplex, des surprises Wi‑Fi « enterprise ».
3) Identifiez le dialecte SMB et les fonctionnalités de sécurité
- Confirmez SMB3 vs SMB2 vs un repli accidentel sur SMB1.
- Vérifiez l’état de la signature/le chiffrement ; contrôlez la saturation CPU de chaque côté.
4) Inspectez le cache et les options de montage
- Cache d’attributs (
actimeo), cache client (cache=), tailles de lecture/écriture, et si des options sont ignorées.
5) Déterminez si vous avez des écrivains multi‑clients
- Si plusieurs nœuds/conteneurs écrivent dans le même arbre, vos réglages de cache sont limités.
- Si c’est un seul écrivain, vous pouvez être plus audacieux.
6) Vérifiez le serveur et le chemin
- Le serveur SMB est‑il une machine Windows, Samba ou un appliance NAS ?
- Le stockage sous‑jacent est‑il lent (disques, RAID surchargé, disque cloud thin‑provisioned) ?
Blague #1 : Les systèmes de fichiers réseau sont comme les imprimantes de bureau — quand elles fonctionnent, personne ne remarque ; quand elles ne fonctionnent pas, tout le monde a soudainement un avis sur l’infrastructure.
Tâches pratiques : commandes, sorties, décisions
Vous trouverez ci‑dessous des tâches réelles à exécuter sur un hôte Linux Docker. Chacune inclut : commande, sortie d’exemple, ce que ça signifie et quelle décision prendre.
Task 1: Confirm the mount type and options actually in use
cr0x@server:~$ findmnt -T /var/lib/docker/volumes/appdata/_data -o TARGET,SOURCE,FSTYPE,OPTIONS
TARGET SOURCE FSTYPE OPTIONS
/var/lib/docker/volumes/appdata/_data //nas01/share cifs rw,relatime,vers=3.1.1,cache=strict,username=svc_app,uid=1000,gid=1000,actimeo=1
Ce que cela signifie : C’est un montage CIFS (SMB) avec SMB 3.1.1 et un cache strict. Le timeout du cache d’attributs est de 1 seconde.
Décision : Si la charge est riche en métadonnées et à un seul écrivain, envisagez d’augmenter actimeo et/ou de modifier cache= pour améliorer la vitesse. Si multi‑écrivain, soyez prudent.
Task 2: Verify SMB dialect and capabilities via kernel logs
cr0x@server:~$ dmesg | grep -i cifs | tail -n 5
[ 9342.112233] CIFS: VFS: \\nas01 negotiated SMB3.1.1 dialect
[ 9342.112240] CIFS: VFS: cifs_mount failed w/return code = -13
[ 9410.445566] CIFS: VFS: \\nas01 Server supports multichannel
[ 9410.445577] CIFS: VFS: \\nas01 requires packet signing
Ce que cela signifie : SMB3.1.1 a été négocié, le multichannel est supporté, et la signature est requise. Il y a eu une erreur de permission plus tôt (-13).
Décision : Assurez‑vous de ne pas basculer silencieusement sur SMB1. Enquêter également sur l’overhead de signature et sur l’erreur d’authentification précédente (peut indiquer des réessais/backoff).
Task 3: Measure basic network RTT and jitter
cr0x@server:~$ ping -c 20 nas01
PING nas01 (10.20.1.50) 56(84) bytes of data.
64 bytes from 10.20.1.50: icmp_seq=1 ttl=63 time=1.92 ms
64 bytes from 10.20.1.50: icmp_seq=2 ttl=63 time=2.08 ms
...
--- nas01 ping statistics ---
20 packets transmitted, 20 received, 0% packet loss, time 19024ms
rtt min/avg/max/mdev = 1.71/2.05/2.61/0.21 ms
Ce que cela signifie : RTT ~2 ms. C’est « acceptable » pour les humains et « coûteux » pour des milliers d’appels métadonnées.
Décision : Si votre charge est riche en métadonnées, vous avez besoin de cache, d’un changement de charge ou d’un backend de stockage différent — pas seulement plus de bande passante.
Task 4: Check for retransmits and TCP pain
cr0x@server:~$ ss -ti dst 10.20.1.50:445 | head -n 20
ESTAB 0 0 10.20.1.10:52144 10.20.1.50:445
cubic wscale:7,7 rto:204 rtt:2.3/0.4 ato:40 mss:1448 pmtu:1500 rcvmss:1448 advmss:1448 cwnd:10 bytes_acked:1289341 segs_out:10873 segs_in:10122 send 50.3Mbps lastsnd:12 lastrcv:12 lastack:12 pacing_rate 100.6Mbps retrans:0/12
Ce que cela signifie : Faible RTT, un peu d’historique de retransmissions mais actuellement zéro retransmission actives. Si vous voyez des retransmissions croissantes, votre stockage est saboté par le réseau.
Décision : Si les retransmissions sont non négligeables, corrigez le réseau avant d’ajuster SMB. Aucune option de montage ne remplace la perte de paquets.
Task 5: Quick metadata micro-benchmark (file create storm)
cr0x@server:~$ time bash -c 'd=/var/lib/docker/volumes/appdata/_data/testmeta; rm -rf "$d"; mkdir -p "$d"; for i in $(seq 1 5000); do : > "$d/f_$i"; done'
real 0m38.412s
user 0m0.311s
sys 0m5.992s
Ce que cela signifie : 5 000 petites créations ont pris 38 secondes. Ce n’est pas « un peu lent », c’est « votre appli va expirer ».
Décision : C’est un problème de latence métadonnées. Envisagez de déplacer les chemins chauds sur disque local, d’utiliser NFS bien réglé, ou d’ajouter une couche de cache locale.
Task 6: Compare the same test on local disk
cr0x@server:~$ time bash -c 'd=/tmp/testmeta; rm -rf "$d"; mkdir -p "$d"; for i in $(seq 1 5000); do : > "$d/f_$i"; done'
real 0m0.486s
user 0m0.169s
sys 0m0.301s
Ce que cela signifie : Même charge ~80× plus rapide en local. Voilà pourquoi les gens pensent « Docker est lent » alors qu’en réalité « les métadonnées distantes sont lentes ».
Décision : Ne placez pas de charges riches en métadonnées sur CIFS à moins d’accepter le coût ou de redessiner la charge.
Task 7: Inspect CIFS stats (client-side clues)
cr0x@server:~$ cat /proc/fs/cifs/Stats
Resources in use
CIFS Session: 2
Share (unique mount targets): 1
SMB Request/Response Buffer: 1 Pool size: 5
SMB Small Req/Resp Buffer: 1 Pool size: 30
Operations (MIDs): 0
Total vfs operations: 482109
Total ops: 612990
Total reconnects: 3
Ce que cela signifie : Il y a des reconnects. Même quelques reconnects peuvent créer des « pauses aléatoires » qui ressemblent à des hics applicatifs.
Décision : Si les reconnects augmentent, vérifiez la stabilité du serveur SMB, les timeouts inactifs, l’état du firewall et les interruptions réseau.
Task 8: Confirm whether SMB encryption is enabled (and costing CPU)
cr0x@server:~$ grep -iE 'Encryption|Signing|Dialect' /proc/fs/cifs/DebugData | head -n 20
Dialect: 3.1.1
Security: NTLMSSP
Signing: Enabled
SMB3 encryption: Enabled
Ce que cela signifie : Le chiffrement est activé. Excellent pour la sécurité ; potentiellement coûteux pour le CPU.
Décision : Si les CPU sont saturés pendant l’I/O, vérifiez si le chiffrement/signature est requis end‑to‑end. Si oui, assurez‑vous d’avoir des CPU modernes et évitez les charges I/O très petites.
Task 9: Watch CPU steal/saturation during I/O
cr0x@server:~$ mpstat -P ALL 1 5
Linux 6.5.0 (server) 01/03/2026 _x86_64_ (16 CPU)
12:03:10 AM CPU %usr %nice %sys %iowait %irq %soft %steal %idle
12:03:11 AM all 22.10 0.00 18.44 9.33 0.00 0.88 0.00 49.25
12:03:12 AM all 25.20 0.00 21.77 10.12 0.00 1.01 0.00 41.90
Ce que cela signifie : %sys et %iowait élevés suggèrent que le noyau fait beaucoup de travail fichier/réseau. Si %usr n’est pas élevé mais %sys l’est, l’overhead SMB est plausible.
Décision : Si le CPU est le goulot, régler les options de montage ne vous sauvera pas. Il faut modifier la charge, diminuer les petites opérations, ou changer de stockage.
Task 10: Identify the worst offenders (metadata vs data)
cr0x@server:~$ strace -f -tt -T -o /tmp/trace.txt docker exec app sh -c 'php -r "for($i=0;$i<2000;$i++){stat(\"/data/smallfile_$i\");}"'
cr0x@server:~$ tail -n 5 /tmp/trace.txt
12:04:21.553221 stat("/data/smallfile_1998", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0 <0.006842>
12:04:21.560219 stat("/data/smallfile_1999", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0 <0.006991>
Ce que cela signifie : Chaque stat() prend ~7 ms. Multipliez par des milliers et vous obtenez la tristesse accompagnée d’un numéro de ticket.
Décision : Soit augmentez le cache (si sûr), réduisez les stats (configuration de l’appli), soit déplacez ces fichiers en local.
Task 11: Benchmark SMB throughput with a big sequential write (to avoid fooling yourself)
cr0x@server:~$ dd if=/dev/zero of=/var/lib/docker/volumes/appdata/_data/dd.test bs=8M count=256 oflag=direct status=progress
2147483648 bytes (2.1 GB, 2.0 GiB) copied, 13 s, 165 MB/s
256+0 records in
256+0 records out
2147483648 bytes (2.1 GB, 2.0 GiB) copied, 13.0256 s, 165 MB/s
Ce que cela signifie : Le débit est correct. C’est le piège classique : « 165 MB/s, donc le stockage est rapide. » Pendant ce temps, votre appli meurt sur les appels métadonnées.
Décision : Arrêtez de n’utiliser que des tests de débit. Faites toujours un test métadonnées aussi.
Task 12: Check Docker mount propagation and whether you’re stacking filesystems
cr0x@server:~$ docker inspect app | grep -n '"Type"\|"Source"\|"Destination"' | head -n 20
145: "Type": "volume",
146: "Source": "/var/lib/docker/volumes/appdata/_data",
147: "Destination": "/data",
Ce que cela signifie : Le conteneur voit un volume monté à /data. Si votre conteneur utilise aussi overlayfs pour d’autres chemins, c’est normal. L’essentiel est que votre chemin chaud cible CIFS directement.
Décision : Si l’appli écrit des fichiers temporaires, redirigez les répertoires temporaires vers un stockage local (tmpfs ou volume local) et gardez CIFS pour les données froides/partagées.
Task 13: Confirm the CIFS kernel module version and loaded parameters
cr0x@server:~$ modinfo cifs | egrep 'version:|parm:|filename:' | head -n 15
filename: /lib/modules/6.5.0/kernel/fs/smb/client/cifs.ko
version: 2.45
parm: CIFSMaxBufSize:Network buffer size (int)
parm: enable_oplocks:Enable or disable oplocks (int)
parm: linux_ext:Enable Linux CIFS Extensions (int)
Ce que cela signifie : Vous utilisez le client SMB intégré au noyau. La version et les fonctionnalités varient selon la version du noyau ; les mises à jour peuvent changer le comportement.
Décision : Si vous êtes sur un noyau ancien, envisagez une mise à niveau. Les performances et la correction du client SMB se sont améliorées considérablement au fil du temps.
Task 14: Validate DNS and name resolution aren’t adding latency
cr0x@server:~$ time getent hosts nas01
10.20.1.50 nas01
real 0m0.006s
user 0m0.002s
sys 0m0.003s
Ce que cela signifie : La résolution de noms est rapide. Si ceci prend des centaines de millisecondes à cause d’un DNS cassé, les reconnects SMB et les tentatives de montage deviennent lentes et instables.
Décision : Corrigez le DNS ou utilisez des IP stables dans les définitions de montage (en gardant à l’esprit le failover).
Options de montage qui aident (et celles qui trompent)
Les options de montage ne sont pas des sorts magiques. Ce sont des compromis, généralement entre performance et cohérence. Si vous avez plusieurs clients écrivant dans le même arbre, votre enveloppe de réglage est étroite.
Commencez par des valeurs par défaut sensées
Pour des serveurs SMB modernes, utilisez SMB3 explicitement. Ne laissez pas la négociation « décider ». Quand elle « se trompe », vous passerez une semaine à benchmarker des fantômes.
cr0x@server:~$ sudo mount -t cifs //nas01/share /mnt/share \
-o vers=3.1.1,username=svc_app,uid=1000,gid=1000,serverino,rw
Options qui comptent souvent
vers=3.1.1: épinglez un dialecte moderne. Si le serveur ne peut pas le faire, vous voulez le savoir.actimeo=: timeout du cache d’attributs. Des valeurs plus grandes peuvent accélérer massivement les lectures riches en métadonnées ; peuvent aussi masquer des changements cross-client.cache=(strict,loose,none) : contrôle la politique de cache côté client. « Loose » peut être plus rapide et moins correct.rsize=,wsize=: ajustez les tailles de lecture/écriture. Aide le débit, moins utile pour les tempêtes métadonnées.noserverinovsserverino: comportement inode. Les discordances peuvent casser des applis qui comptent sur des numéros d’inode stables ; l’impact performance varie mais l’impact correctionnel est réel.
Options fréquemment mal comprises
nounix/unix: affecte les extensions Unix, les permissions et le comportement. Utilisez ces options délibérément, pas en copiant un billet de blog de 2014.soft/hard: c’est un concept NFS ; les sémantiques d’échec SMB diffèrent. Vous devez toujours penser aux timeouts et aux réessais, mais le bouton n’est pas le même.- « Augmentez simplement
wsizeet c’est réglé » : si votre problème est métadonnées, des tampons I/O plus gros ne changeront rien.
Exemple réaliste de tuning « single‑writer, mostly‑read »
Si vous avez un seul conteneur qui écrit et les autres qui lisent (ou un seul nœud), vous pouvez prendre plus de risques :
cr0x@server:~$ sudo mount -t cifs //nas01/share /mnt/share \
-o vers=3.1.1,username=svc_app,uid=1000,gid=1000,rw,cache=loose,actimeo=30
Ce que vous obtenez : Moins d’allers-retours pour les stats et les parcours d’annuaire.
Ce que vous payez : Un autre client peut ne pas voir les mises à jour immédiatement. Si vous avez plusieurs écrivains, vous venez de créer une loterie de cohérence.
Pièges spécifiques à Docker avec les volumes CIFS
Volumes nommés avec le driver local et CIFS
Un schéma courant est le driver local de Docker avec des options CIFS. C’est pratique, reproductible, et aussi facile à mal configurer.
cr0x@server:~$ docker volume create \
--driver local \
--opt type=cifs \
--opt device=//nas01/share \
--opt o=vers=3.1.1,username=svc_app,password=REDACTED,uid=1000,gid=1000,rw \
appdata
Ça marche, mais vous avez maintenant éparpillé des identifiants dans des endroits que vous pourriez regretter. Utilisez un fichier de credentials sur l’hôte quand c’est possible, et surveillez les permissions de ce fichier.
Overlayfs n’est pas le méchant, mais peut être dommage collatéral
Quand le système de fichiers du conteneur utilise overlayfs et que votre appli mélange des chemins overlay avec des montages CIFS, vous pouvez obtenir des comportements étranges : lectures rapides depuis la couche image, lectures lentes depuis les données montées, et des traces strace confuses qui vous font chasser le mauvais problème.
Espaces de noms utilisateur et discordances UID/GID
Si vous exécutez Docker avec userns‑remap ou en rootless, le mapping UID/GID CIFS peut rapidement devenir gênant. Le « uid 1000 » du conteneur peut être mappé à autre chose sur l’hôte. Alors vous obtenez des permission‑denied, des réessais en fallback et des falaises de performance qui disparaissent quand vous exécutez en root (ce qui est une autre falaise, juste différente).
Les healthchecks peuvent devenir des tests de charge accidentels
Des healthchecks qui touchent des fichiers sur CIFS toutes les quelques secondes à travers de nombreux conteneurs deviennent une bruine métadonnées continue. Multipliez par des dizaines de conteneurs et vous avez monté un petit DDoS contre votre propre NAS, doucement, poliment et en continu.
Blague #2 : Mettre une base de données sur CIFS, c’est comme tracter une voiture de course avec un chariot de supermarché — techniquement ça bouge, mais tout le monde a l’air mal à l’aise.
Trois mini-récits d’entreprise depuis le terrain
Mini-récit 1 : L’incident causé par une mauvaise hypothèse
Dans une entreprise de taille moyenne, une équipe a migré une appli legacy en conteneurs. Ils voulaient un « stockage partagé » entre deux hôtes Docker pour les uploads et les vignettes générées. Le chemin le plus rapide vers une démo était un partage CIFS depuis un serveur de fichiers Windows existant. Ça a marché. Tout le monde a applaudi. Le ticket a été clôturé avec le sourire.
Deux semaines plus tard, une campagne marketing a démarré. L’appli ne s’est pas effondrée immédiatement. Elle a commencé à expirer par vagues. Le CPU était correct. La mémoire aussi. Les graphes réseau semblaient calmes. Les logs applicatifs étaient remplis d’avertissements de requêtes lentes et d’erreurs sporadiques de fichier introuvable qui n’avaient pas de sens.
L’hypothèse erronée était subtile : « Si un fichier existe sur le partage, chaque conteneur le verra immédiatement. » En réalité, le cache d’attributs plus l’énumération de répertoire plus les écritures concurrentes produisaient des vues obsolètes. Un conteneur créait une vignette et un autre ne la voyait pas encore, donc il la régénérait. Parfois ils se heurtaient. Parfois ils écrasaient. Occasionnellement un lecteur obtenait un fichier partiellement écrit parce que l’appli supposait l’atomicité locale qui n’était pas garantie dans leur usage.
La correction n’a pas été héroïque. Ils ont arrêté de partager le chemin chaud. Les uploads atterrissaient d’abord en local, puis un job asynchrone poussait les artefacts finalisés vers le stockage partagé. Le stockage partagé est devenu un point de distribution, pas un scratchpad vivant. Les erreurs ont disparu. Les performances se sont stabilisées. La phrase postmortem fut franche : « Nous avons traité un système de fichiers réseau comme un disque local sous concurrence. »
Mini-récit 2 : L’optimisation qui s’est retournée contre eux
Ailleurs, une « astuce intelligente ». Une équipe avait un service Node.js avec d’énormes arbres de dépendances. Le démarrage était douloureusement lent car il lisait des milliers de petits fichiers depuis un volume CIFS. Quelqu’un a trouvé une suggestion de tuning : augmenter agressivement le cache. Ils ont mis cache=loose et élevé actimeo. Le cold start s’est amélioré de façon spectaculaire. Tout le monde a applaudi à nouveau. Autre salle de réunion, même applaudissement.
Puis le retour de bâton : les déploiements ont commencé à échouer d’une nouvelle manière. Le service démarrant utilisait parfois une ancienne version d’un fichier de config, même si le fichier avait été mis à jour sur le partage par le job de déploiement. Les rollouts sont devenus nondéterministes. La moitié de la flotte se comportait comme la nouvelle version, l’autre moitié comme l’ancienne. Le debugging était un cirque car « il suffit de redémarrer » résolvait parfois et parfois non.
La cause racine était prévisible rétrospectivement : ils ont troqué la cohérence pour la vitesse sans adapter le workflow. Un partage réseau utilisé pour la configuration partagée et le code vivant a besoin de garanties de fraîcheur. Un cache « loose » est essentiellement un pacte de non‑agression avec l’univers.
La solution : arrêter d’utiliser CIFS pour cet usage. Ils ont construit des images immuables contenant dépendances et valeurs par défaut, et utilisé un service de configuration pour les paramètres runtime. CIFS est resté, mais seulement pour des artefacts volumineux où la staleness du cache ne créait pas de bogues de correction.
Mini-récit 3 : La pratique ennuyeuse mais correcte qui a sauvé la mise
Une grande organisation avait des volumes CIFS en production à cause de contraintes corporatives : équipe stockage Windows, contrôles d’accès existants et des auditeurs qui aimaient le mot « SMB » parce que ça semblait familier. L’équipe SRE n’aimait pas, mais était réaliste : certains combats sont budgétaires, pas techniques.
Ils ont donc fait la chose ennuyeuse. Ils ont créé une norme : les montages CIFS étaient autorisés seulement pour les données froides et les logs append‑only, jamais pour les bases de données, jamais pour les arbres de dépendances, jamais pour le scratch de build, jamais pour des répertoires temporaires à fort turnover. Chaque charge appuyée sur CIFS nécessitait un micro‑benchmark en CI qui exécutait à la fois un test débit et un test métadonnées, avec des seuils.
Ils ont aussi ajouté des vérifications de routine : alerter sur les reconnects CIFS, suivre le CPU du serveur SMB, et mesurer la latence p99 des opérations fichiers depuis des conteneurs représentatifs. Personne n’a célébré ces dashboards. Ce n’était pas sexy. C’était correct.
Six mois plus tard, l’équipe stockage a poussé un changement qui modifiait les paramètres de signature SMB. Les performances se sont légèrement dégradées. Les dashboards l’ont détecté rapidement, et le rollback a eu lieu avant impact client. La « norme ennuyeuse » a évité un incident parce qu’elle a restreint où CIFS pouvait nuire, et le monitoring a rendu le mode d’échec évident.
Meilleures alternatives (et quand choisir chacune)
Si vous ne lisez rien d’autre : arrêtez d’utiliser CIFS comme backend de stockage par défaut pour les workloads sensibles à la performance. Utilisez‑le quand vous avez besoin de sémantiques natives Windows ou que vous y êtes contraint. Sinon, choisissez l’outil adapté à la charge.
1) Disque local (ext4/xfs) + réplication (préféré pour les bases)
Si les données appartiennent à un service (Postgres, MySQL, Elasticsearch, Redis persistence), utilisez le stockage local et gérez la réplication au niveau applicatif. Vous obtiendrez une latence prévisible, un comportement fsync correct et moins de verrous étranges.
2) NFSv4.1+ pour un stockage partagé POSIX‑like
NFS n’est pas automatiquement « plus rapide », mais il s’aligne souvent mieux avec les sémantiques Linux et les outils. Il peut mieux performer sur des charges riches en métadonnées, selon la configuration serveur/client. Il échoue aussi différemment. Parfois, c’est justement ce qu’il faut.
3) Stockage objet pour les artefacts (API compatibles S3)
Si vos conteneurs doivent lire/écrire des blobs, cessez de prétendre que c’est un système de fichiers. Utilisez le stockage objet. Vous échangez les sémantiques POSIX contre la scalabilité et une bien meilleure tenue sous concurrence. Votre appli aura peut‑être besoin d’adaptations, mais votre futur vous enverra une carte de remerciement.
4) Stockage bloc (iSCSI, Fibre Channel, volumes cloud) + un système de fichiers
Si vous avez besoin des sémantiques et de la performance d’un système de fichiers, placez le FS sur du stockage bloc et montez‑le localement. Puis partagez via des mécanismes applicatifs, pas en laissant plusieurs clients marteler le même filesystem, à moins d’utiliser intentionnellement un filesystem clusterisé.
5) Une couche de cache locale devant CIFS
Si la réalité corporate impose CIFS, mettez un cache devant. Options :
- Sync‑to‑local au démarrage (style rsync) et refresh périodique.
- Patterns write‑back pour logs/artefacts (spool local, upload asynchrone).
- Cache applicatif explicite (en mémoire, Redis, CDN pour contenu statique).
Cela fonctionne parce que vous changez la forme de l’I/O : moins d’aller‑retour réseau, moins d’opérations métadonnées, moins d’écritures synchrones.
Erreurs fréquentes : symptômes → cause → correctif
Cette section vise à prévenir les incidents répétés.
1) Symptom: “Throughput is good but the app still times out”
Cause racine : la latence métadonnées domine (tempêtes stat/open/close). Les tests gros‑fichiers trompent.
Fix : Lancez des micro‑benchmarks métadonnées ; augmentez actimeo seulement si sûr ; déplacez arbres de dépendances et fichiers temporaires sur disque local ; redesign de la charge pour réduire les appels fichiers.
2) Symptom: “Random 5–30 second freezes”
Cause racine : reconnects SMB, hiccups serveur, timeouts firewall/NAT, ou délais DNS pendant reconnect.
Fix : Vérifiez /proc/fs/cifs/Stats pour les reconnects, les retransmissions TCP, dmesg ; stabilisez le chemin réseau ; assurez les keepalives ; réduisez les timeouts inactifs ; corrigez le DNS.
3) Symptom: “Works on one host, slow on another”
Cause racine : options de montage différentes, dialecte SMB négocié différent, versions de noyau différentes, ou différences d’accélération crypto CPU.
Fix : Comparez la sortie de findmnt ; épinglez vers= ; standardisez noyau et paramètres CIFS ; vérifiez chiffrement/signature et usage CPU.
4) Symptom: “Permission denied” mixed with slowness
Cause racine : mismatch UID/GID, espaces de noms utilisateur, ou évaluation d’ACL côté serveur provoquant des échecs répétés.
Fix : Alignez les identités ; utilisez des uid=/gid= cohérents ; envisagez Samba avec extensions Unix si vous avez besoin des permissions POSIX ; évitez les tempêtes de chown au démarrage des conteneurs.
5) Symptom: “File exists, but app can’t see it yet”
Cause racine : cache client ou cache d’entrées de répertoire retardé ; problèmes de cohérence cross‑client.
Fix : Réduire l’agressivité du cache pour les chemins de config/code partagés ; n’utilisez pas CIFS comme mécanisme de coordination ; utilisez un service de configuration ou une synchronisation explicite.
6) Symptom: “Database corruption / lock errors / weird fsync behavior”
Cause racine : les sémantiques des systèmes de fichiers réseau ne correspondent pas à ce que la base attend en cas d’échec, verrouillage ou contraintes de durabilité.
Fix : Ne pas exécuter de bases de données sur CIFS. Utilisez un disque local ou un stockage clusterisé conçu pour la base en question.
7) Symptom: “CPU spikes during file copies”
Cause racine : overhead chiffrement/signature SMB, possiblement avec des I/O petits.
Fix : Confirmez chiffrement/signature ; assurez l’accélération AES‑NI/CPU ; augmentez les tailles d’I/O si possible ; envisagez une voie de stockage alternative si le CPU est le goulot.
Listes de contrôle / plan pas-à-pas
Step-by-step: stabilize a slow CIFS-backed Docker workload (practical plan)
- Identifiez le chemin chaud : quels répertoires sont sur CIFS et lesquels sont sensibles à la latence (config, deps, temp, cache, fichiers DB).
- Exécutez deux benchmarks : un débit (
dd) et un métadonnées (create/stat storm). Enregistrez les temps. - Mesurez RTT et retransmissions : si le réseau est sale, arrêtez et corrigez d’abord ça.
- Confirmez dialecte/sécurité : SMB3.1.1, et si signature/chiffrement sont activés.
- Vérifiez les reconnects : si des reconnects ont lieu, traitez‑les comme un problème de fiabilité, pas seulement de performance.
- Déplacez les répertoires temporaires en local : définissez
TMPDIR, dossiers cache appli, outputs de build sur disque local ou tmpfs. - Retirez les bases de données de CIFS : migrez vers des volumes locaux avec réplication/sauvegardes.
- Réduisez la pression sur les métadonnées : intégrez les dépendances dans les images ; évitez les installations runtime depuis CIFS ; minimisez les scans de répertoires.
- Réglez le cache seulement si sûr : si single‑writer, augmentez
actimeoet envisagezcache=loosepour les arbres en lecture. - Standardisez les définitions de montage : mêmes options partout,
vers=épinglé, identifiants gérés en sécurité. - Instrumentez la latence filesystem p95/p99 : échantillonnage strace, timings applicatifs et stats CIFS.
- Planifiez une sortie : choisissez un design de stockage alternatif pour le trimestre suivant ; ne laissez pas CIFS « temporaire » devenir immortel.
Operational checklist: when CIFS is unavoidable
- Épinglez le dialecte SMB (
vers=3.1.1ou un connu‑bon). - Documentez si le partage est single‑writer ou multi‑writer.
- Réservez CIFS aux gros fichiers et aux données froides, pas aux tempêtes métadonnées.
- Alertez sur les reconnects et les retransmissions élevées.
- Gardez les options de montage cohérentes entre hôtes.
- Testez après mises à jour du noyau ; le client SMB évolue avec le temps.
FAQ
1) Is “CIFS” the same as SMB?
Dans le langage opérationnel courant, oui. Techniquement, CIFS fait souvent référence aux dialectes SMB1 plus anciens. Sur Linux vous montez souvent avec -t cifs même en négociant SMB3.
2) Why is CIFS especially painful in containers?
Les conteneurs encouragent des schémas comme « montez un partage et exécutez tout dessus », y compris les arbres de dépendances, caches et parfois des bases de données. Les conteneurs multiplient aussi le nombre de clients concurrents et les opérations métadonnées.
3) What’s the single biggest predictor of “CIFS is slow”?
Des charges riches en métadonnées plus un RTT non négligeable. Si votre appli fait beaucoup de petits appels fichiers, vous ressentirez chaque milliseconde.
4) Can mount options actually fix it?
Elles peuvent améliorer les choses, parfois de façon spectaculaire, mais elles ne peuvent pas changer la physique. Si votre charge a besoin de latence disque locale et que vous faites des métadonnées à travers le réseau, les options ne font que choisir quel coin vous voulez sacrifier.
5) Should I use cache=loose?
Uniquement si vous comprenez le compromis de cohérence et que le partage n’est pas utilisé pour la coordination live entre écrivains. C’est un levier performance avec un prix en correction.
6) Is NFS always faster than SMB?
Non. Mais NFS s’aligne souvent mieux sur les charges Linux et peut mieux performer pour des patterns métadonnées, selon la config serveur/client et le stockage derrière.
7) What about SMB multichannel—will it speed things up?
Ça peut aider le débit et la résilience quand bien configuré côté client et serveur avec plusieurs NICs. Ça ne résoudra pas magiquement la latence métadonnées, et ça peut ajouter de la complexité.
8) Why do big file copies look fine while the app crawls?
L’I/O séquentielle peut bien streamer sur SMB. Les applis réalisent souvent des I/O mixtes avec beaucoup d’opens/stats/petits writes. Univers de performance différent.
9) Is running Postgres/MySQL on CIFS supported?
Même si « ça marche », c’est un pari sur la fiabilité et la performance. Utilisez un disque local ou un stockage conçu pour la base. CIFS est un protocole de partage de fichiers, pas un substrat pour bases de données.
10) What’s a safe pattern if I must share data across containers?
Partagez des artefacts finalisés, pas des jeux de travail vivants. Écrivez localement, puis publiez. Traitez CIFS comme une couche de distribution, pas un espace de travail transactionnel.
Étapes suivantes réalisables cette semaine
Si vous utilisez déjà des volumes CIFS dans Docker et que c’est lent, ne commencez pas par réécrire le monde. Faites ceci :
- Exécutez le micro‑benchmark métadonnées sur le montage CIFS et en local. Si l’écart est énorme, vous avez votre diagnostic.
- Déplacez le churn chaud (temp, caches, installations de dépendances, outputs de build) vers le stockage local. Cela réduit souvent la douleur d’un ordre de grandeur.
- Confirmez le dialecte SMB et les réglages de sécurité pour éviter de négocier accidentellement quelque chose d’ancien ou d’onéreux sans le savoir.
- Standardisez les options de montage et mesurez avant/après. Ne tunez pas à l’aveugle.
- Choisissez une alternative pour l’itération suivante : disque local + réplication pour les bases, NFS pour les arbres POSIX‑like partagés, stockage objet pour blobs, ou un pattern cache‑devant si CIFS est imposé.
Puis mettez‑le par écrit comme règle : CIFS est acceptable pour des données partagées froides. Ce n’est pas un répertoire personnel par défaut pour des conteneurs de production. Votre futur on‑call vous remerciera discrètement pour votre manque de créativité.