Comment monter un seul fichier dans un volume

259

J'essaie de docker une application php. Dans le dockerfile, je télécharge l'archive, l'extrait, etc.

Tout fonctionne bien, cependant, si une nouvelle version est publiée et que je mets à jour le dockerfile, je dois réinstaller l'application, car le config.php est écrasé.

J'ai donc pensé pouvoir monter le fichier en tant que volume, comme je le fais avec la base de données.

Je l'ai essayé de deux manières, avec un volume et un chemin direct.

docker-compose:

version: '2'
services:
  app:
    build: src
    ports:
      - "8080:80"
    depends_on:
      - mysql
    volumes:
      -  app-conf:/var/www/html/upload
      -  app-conf:/var/www/html/config.php
    environment:
      DB_TYPE: mysql
      DB_MANAGER: MysqlManager

  mysql:
    image: mysql:5.6
    container_name: mysql
    volumes:
      - mysqldata:/var/lib/mysql
    ports:
      - 3306:3306
    environment:
      MYSQL_ROOT_PASSWORD:
      MYSQL_DATABASE:
      MYSQL_USER:
      MYSQL_PASSWORD:

volumes:
  mysqldata:
  app-conf:

Ce qui entraîne l'erreur:

Et je l'ai essayé avec un chemin donné, comme un volume monté.

/src/docker/myapp/upload:/var/www/html/upload
/src/docker/myapp/upload:/var/www/html/config.php

Cependant, les deux façons ne fonctionnent pas. Avec le volume monté, je vois que le téléchargement est créé.

Mais échoue ensuite avec

/var/www/html/config.php \\ "a causé \\" pas un répertoire \\ "\" "

Si je l'essaye avec

/src/docker/myapp/upload/config.php:/var/www/html/config.php

Docker crée le dossier de téléchargement, puis un dossier config.php. Pas un fichier.

Ou existe-t-il un autre moyen de conserver la configuration?

Jakub Juszczak
la source
Dans mon cas, je me contente de "toucher" un fichier vide avant de créer le conteneur / volume. Si le fichier n'existait pas, il a créé un répertoire.
FreeSoftwareServers

Réponses:

313

TL; DR / Avis:

Si vous rencontrez un répertoire en cours de création à la place du fichier que vous essayez de monter, vous avez probablement échoué à fournir un chemin d'accès valide et absolu . Il s'agit d'une erreur courante avec un mode de défaillance silencieux et déroutant.

Les volumes de fichiers se font de cette façon dans docker (exemple de chemin absolu (peut utiliser des variables env), et vous devez mentionner le nom du fichier):

    volumes:
      - /src/docker/myapp/upload:/var/www/html/upload
      - /src/docker/myapp/upload/config.php:/var/www/html/config.php

Vous pouvez également faire:

    volumes:
      - ${PWD}/upload:/var/www/html/upload
      - ${PWD}/upload/config.php:/var/www/html/config.php

Si vous lancez le docker-compose depuis le /src/docker/myappdossier

BlackStork
la source
81
Comme je l'ai dit, si j'essaie /src/docker/myapp/upload/config.php:/var/www/html/config.php Docker crée le dossier de téléchargement puis un dossier config.php. Pas un fichier.
Jakub Juszczak
9
Dans votre article, vous avez écrit différemment. Si le fichier est là, il doit être monté en tant que fichier.
BlackStork
16
Pour que cela fonctionne, j'ai dû fournir un chemin absolu. Le conseil d'utilisation de PWD a beaucoup aidé ici, merci!
Steve Smith
4
Pour moi, c'est créer un dossier plutôt que les fichiers, mais je pense que parce que ce fichier est copié plus tard dans ce chemin, y a-t-il quand même un report de la liaison?
eKelvin
18
si /src/docker/myapp/upload/config.php n'existe pas dans le docker hôte va créer un dossier ... Ce que je fais est de créer un script qui crée un fichier vide avant d'exécuter le docker run - serait idéal si je peux demander à docker de le faire pour moi via les arguments de la ligne cmd.
cancerbero
78

Je souffrais d'un problème similaire. J'essayais d'importer mon fichier de configuration dans mon conteneur afin de pouvoir le corriger à chaque fois que je besoin sans reconstruire l'image.

Je veux dire que je pensais que la commande ci-dessous serait $(pwd)/config.pymappée de l'hôte Docker vers /root/app/config.pyle conteneur sous forme de fichier.

docker run -v $(pwd)/config.py:/root/app/config.py my_docker_image

Cependant, il a toujours créé un répertoire nommé config.py, pas un fichier.

en cherchant un indice, j'ai trouvé la raison (d' ici )

Si vous utilisez -v ou --volume pour monter un fichier ou un répertoire qui n'existe pas encore sur l'hôte Docker, -v créera le point de terminaison pour vous. Il est toujours créé sous forme de répertoire .

Par conséquent, il est toujours créé en tant que répertoire car mon hôte docker n'en a pas $(pwd)/config.py.

Même si je crée config.py dans l'hôte docker. $(pwd)/config.pyjuste écraser /root/app/config.pyne pas exporter /root/app/config.py.

SangminKim
la source
16
Je viens d'ajouter un touch path/to/filedans le Dockerfileafin que quand je monterai ce serait toujours un fichier (pas un répertoire créé)
shadi
8
le côté gauche :doit être plein chemin. Cela fonctionne de cette façon
sdkks
Le touchétait la réponse, faites - le dans Dockerfile puis monter votre volume docker-Compose fonctionnera correctement sans créer un répertoire
ctrlbrk
27

Utilisez mount ( --mount) au lieu de volume ( -v)

Plus d'informations: https://docs.docker.com/storage/bind-mounts/

Exemple:

Assurez-vous que /tmp/a.txt existe sur l'hôte docker

docker run -it --mount type=bind,source=/tmp/a.txt,target=/root/a.txt alpine sh
Subbu M
la source
Merci Subbu, @Jakub Juszczak, cela devrait être la réponse acceptée, c'est la seule réponse qui réponde à la question, et cela a fonctionné pour moi
neokyle
2
Cela ne répond pas vraiment à la question. les volumes fonctionneront également (car le problème est en chemin absolu). La seule différence entre --mountet -vest le comportement lorsque la partie hôte du volume n'existe pas encore. Selon votre lien:> Si vous utilisez -v ou --volume pour lier-monter un fichier ou un répertoire qui n'existe pas encore sur l'hôte Docker, -v crée le point de terminaison pour vous. Il est toujours créé sous forme de répertoire.
Le parrain
2
Je ne sais pas comment traduire cela en un docker-compose. 'Un peu d'aide?
msanford
@msanford J'ai ajouté un exemple de composition de docker à la réponse.
sebisnow
10

Pour toute personne utilisant un conteneur Windows comme moi, sachez que vous NE POUVEZ PAS lier ou monter des fichiers uniques à l'aide du conteneur Windows.

Les exemples suivants échoueront lors de l'utilisation de conteneurs Windows, car la destination d'un volume ou d'un montage de liaison à l'intérieur du conteneur doit être l'un des: un répertoire inexistant ou vide; ou un lecteur autre que C :. De plus, la source d'un montage de liaison doit être un répertoire local, pas un fichier .

net use z: \\remotemachine\share

docker run -v z:\foo:c:\dest ...

docker run -v \\uncpath\to\directory:c:\dest ...

docker run -v c:\foo\somefile.txt:c:\dest ...

docker run -v c:\foo:c: ...

docker run -v c:\foo:c:\existing-directory-with-contents ...

C'est difficile à repérer mais c'est là

Lien vers le problème Github concernant le mappage de fichiers dans un conteneur Windows

Justin Lessard
la source
7

Depuis la version 3.2 du fichier docker-compose, vous pouvez spécifier un montage de volume de type "bind" (au lieu du type par défaut "volume") qui vous permet de monter un seul fichier dans le conteneur. Recherchez «bind mount» dans les documents de volume de docker-compose: https://docs.docker.com/compose/compose-file/#volumes

Dans mon cas, j'essayais de monter un seul fichier ".secrets" dans mon application qui contenait des secrets pour le développement local et les tests uniquement. En production, mon application récupère plutôt ces secrets auprès d'AWS.

Si j'ai monté ce fichier en tant que volume en utilisant la syntaxe abrégée:

volumes:
 - ./.secrets:/data/app/.secrets

Docker créerait un « .secrets » répertoire intérieur du conteneur au lieu de mappage au fichier extérieur du conteneur. Mon code soulèverait alors une erreur comme "IsADirectoryError: [Errno 21] Est un répertoire: '.secrets'".

J'ai corrigé cela en utilisant à la place la syntaxe à long terme, en spécifiant mon fichier secret à l'aide d'un montage de volume "bind" en lecture seule:

volumes:
 - type: bind
   source: ./.secrets
   target: /data/app/.secrets
   read_only: true

Docker monte maintenant correctement mon fichier .secrets dans le conteneur, créant un fichier à l'intérieur du conteneur au lieu d'un répertoire. J'espère que d'autres trouveront cet exemple utile!

Carlton Duffett
la source
Merci Monsieur! C'était la solution dont j'avais besoin pour pouvoir monter mon fichier WordPress wp-config.php (et arrêter sa création en tant que répertoire)
Jono
6

Vous pouvez également utiliser un chemin relatif vers votre docker-compose.ymlfichier comme celui-ci (testé sur l'hôte Windows, conteneur Linux):

 volumes:
      - ./test.conf:/fluentd/etc/test.conf
Daniel
la source
1
J'ai testé cela sur Mac avec version: '3.7'spécifié dans le docker-compose.ymlfichier avec la version 1.24.1 de docker-compose, build 4667896b, et cela a fonctionné.
Acumenus
6
J'obtiens toujours un répertoire au lieu d'un fichier.
chovy
0

Pour moi, le problème était que j'avais un lien symbolique brisé sur le fichier que j'essayais de monter dans le conteneur

jla
la source
0

J'ai eu le même problème sur Windows, Docker 18.06.1-ce-win73 (19507).

Supprimer et rajouter le lecteur partagé via le panneau des paramètres Docker et tout a de nouveau fonctionné.

bassin
la source
0

Dans Windows, si vous avez besoin de la variable env $ {PWD} dans votre docker-compose.yml, vous pouvez créer un fichier .env dans le même répertoire que votre fichier docker-compose.yml puis insérer manuellement l'emplacement de votre dossier.

CMD (pwd_var.bat):

echo PWD=%cd% >> .env

Powershell (pwd_var.ps1):

$PSDefaultParameterValues['Out-File:Encoding'] = 'utf8'; echo "PWD=$(get-location).path" >> .env

Il existe d'autres fonctionnalités intéressantes pour les variables .env de docker-compose: https://docs.docker.com/compose/reference/envvars/ en particulier pour la COMPOSE_CONVERT_WINDOWS_PATHSvariable env qui permet à docker compose d'accepter le chemin Windows avec baskslash "\".

Lorsque vous souhaitez partager un fichier sur Windows, le fichier doit exister avant de le partager avec le conteneur.

CallMarl
la source
Vous ne pouvez pas utiliser PowerShell avec docker, cela crée un blocage de fournisseur et nuit à la communauté ...
Matej 'Yin' Gagyi
0

Peut-être que cela aide quelqu'un.

J'ai eu ce problème et j'ai tout essayé. Les liaisons de volume semblaient bien et même si je montais le répertoire (pas les fichiers), j'avais les noms de fichiers dans le répertoire monté correctement mais montés en tant que dirs.

J'ai essayé de réactiver les lecteurs partagés et Docker s'est plaint que le pare-feu est actif.

Après avoir désactivé le pare-feu, tout fonctionnait bien.

Josef Sábl
la source
Merci pour ça! Votre message m'a fait réaliser que mon selinux était prêt à être appliqué et que cela causait tous mes problèmes. Je ne sais pas pourquoi vous étiez-bas a voté _ (ツ) _ / ¯
Octavian
0

Vous pouvez monter des fichiers ou des répertoires / dossiers, tout dépend du fichier ou du répertoire source. Et vous devez également fournir un chemin d'accès complet ou si vous n'êtes pas sûr de pouvoir utiliser PWD. Voici un exemple de travail simple.

Dans cet exemple, je monte un fichier env-commandes qui existe déjà dans mon répertoire de travail

$ docker run  --rm -it -v ${PWD}/env-commands:/env-commands aravindgv/eosdt:1.0.5 /bin/bash -c "cat /env-commands"
Aravind GV
la source
-1

J'ai le même problème sur mon Windows 8.1

Il s'est avéré que cela était dû à la sensibilité à la casse du chemin. J'ai appelé à docker-compose uppartir du répertoire cd /c/users/alex/et à l'intérieur du conteneur, un fichier a été transformé en répertoire.

Mais quand je l'ai fait cd /c/Users/alex/(pas les utilisateurs capitalisés) et appelé à docker-compose uppartir de là, cela a fonctionné.

Dans mon système, le répertoire des utilisateurs et le répertoire d'Alex sont en majuscules, bien qu'il semble que seuls le répertoire des utilisateurs soit important.

Alex Velickiy
la source