Aller au contenu
Sylvain Joffraud l4w
Retour

Docker bind mount : la source absente crée un dossier vide

Configuration apparemment banale dans un docker-compose.yml :

volumes:
  - ./conf/app.xml:/opt/app/conf/app.xml:ro

Sur ma machine de dev, ./conf/app.xml existe (généré localement par un script de setup). Sur la CI ou un PaaS qui clone le repo, il n’est pas là — gitignored parce qu’il contient un secret. Et là Docker fait un truc subtilement mauvais.

Symptôme

Error response from daemon: failed to create task for container:
  unable to start container process: error during container init:
  error mounting "/host/path/conf/app.xml" to rootfs at "/opt/app/conf/app.xml":
  not a directory: Are you trying to mount a directory onto a file (or vice-versa)?
  Check if the specified host path exists and is the expected type

Le message dit « not a directory » mais le piège est l’inverse — c’est un dossier qui est monté sur ce qui devrait être un fichier régulier.

Cause

Quand on déclare un bind mount Docker et que le chemin source n’existe pas sur l’hôte, le daemon Docker crée silencieusement un dossier vide à ce chemin. Il suppose qu’on voulait un dossier. Si la cible côté conteneur est un fichier (parce qu’il existait dans l’image), les types ne matchent pas → l’erreur cryptique ci-dessus.

C’est documenté mais peu mis en avant. Le piège tombe systématiquement en CI/CD où le repo cloné ne contient pas le fichier généré localement.

Solution

Trois patterns propres pour ne plus se faire piéger :

1. S’assurer que le fichier existe avant compose up. Soit le commit (avec placeholder), soit le générer dans une étape pre-deploy maîtrisée.

2. Monter un dossier plutôt qu’un fichier, quand l’app le permet :

- ./conf/:/opt/app/conf/:ro

Si le dossier source manque, Docker auto-crée un dossier vide — l’app tombe alors sur une erreur plus parlante (fichier absent à l’intérieur) plutôt que sur un mount-type-mismatch.

3. Embarquer la conf dans une image custom (Dockerfile FROM + COPY). Plus de bind mount, plus de surprise. La meilleure approche quand le fichier est en pratique versionné dans le repo de l’app.

Lessons learned

Questions fréquentes

Docker me renvoie « not a directory: Are you trying to mount a directory onto a file » au démarrage du conteneur, pourquoi ?
Le message est trompeur : il vient en réalité d’un fichier source absent côté hôte. Quand le chemin source d’un bind mount n’existe pas, le daemon Docker crée un dossier vide à sa place, puis échoue car ce dossier ne correspond pas au fichier attendu dans l’image. Vérifiez que le fichier source existe bien sur l’hôte avant le docker compose up.
Pourquoi Docker crée un dossier vide à la place de mon fichier de configuration en bind mount ?
Parce que le bind mount d’un fichier n’est pas un « create if missing » : Docker suppose que le fichier est déjà présent sur l’hôte. Si la source n’existe pas, le daemon part du principe que vous vouliez un dossier et en crée un vide silencieusement. C’est documenté mais peu mis en avant.
Mon bind mount fonctionne en local mais casse en CI/CD, comment corriger ?
Ce piège tombe systématiquement quand le fichier est généré localement et gitignored (par exemple un secret), donc absent du repo cloné en CI. Trois solutions : garantir la présence du fichier avant le compose up (commit d’un placeholder ou génération pre-deploy), monter le dossier parent plutôt que le fichier, ou embarquer la conf dans une image custom avec COPY.
Comment éviter qu’un bind mount de fichier manquant fasse échouer mon pipeline Docker ?
Le plus robuste est d’embarquer la configuration dans une image custom via Dockerfile et COPY, ce qui supprime toute dépendance au filesystem hôte. Si vous devez bind-mounter un fichier, ajoutez un fail-fast en CI du type [ -f conf/app.xml ] || (echo manquant >&2; exit 1) avant le docker compose up pour obtenir une erreur claire.

Partager cet article :

Article précédent
Bind mount fantôme : git ne remplace pas un dossier
Article suivant
Harnais de tests bash pour une API PDF qu’on ne maîtrise pas