Cómo montar un solo archivo en un volumen

257

Estoy tratando de dockerizar una aplicación php. En el dockerfile descargo el archivo, lo extraigo, etc.

Todo funciona bien, sin embargo, si se lanza una nueva versión y actualizo el dockerfile, tengo que reinstalar la aplicación, porque se sobrescribe el config.php.

Así que pensé que podía montar el archivo como un volumen, como hago con la base de datos.

Lo intenté de dos maneras, con un volumen y una ruta directa.

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:

Lo que da como resultado el error:

Y lo probé con una ruta determinada, como un volumen montado.

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

Sin embargo, ambas formas no funcionan. Con el volumen montado veo que se crea la carga.

Pero luego falla con

/var/www/html/config.php \\ "causó \\" no un directorio \\ "\" "

Si lo intento con

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

Docker crea la carpeta de carga y luego una carpeta config.php. No es un archivo

¿O hay otra forma de persistir la configuración?

Jakub Juszczak
fuente
En mi caso, lo simple para "tocar" un archivo vacío antes de crear el contenedor / volumen. Si el archivo no existía, creaba un directorio.
FreeSoftwareServers

Respuestas:

312

TL; DR / Aviso:

Si experimenta que se está creando un directorio en lugar del archivo que está intentando montar, probablemente no haya podido proporcionar una ruta válida y absoluta . Este es un error común con un modo de falla silencioso y confuso.

Los volúmenes de archivos se realizan de esta manera en Docker (ejemplo de ruta absoluta (puede usar variables env), y debe mencionar el nombre del archivo):

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

También puedes hacer:

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

Si disparas el docker-compose desde la /src/docker/myappcarpeta

Cigüeña Negra
fuente
81
Como dije, si intento /src/docker/myapp/upload/config.php:/var/www/html/config.php Docker crea la carpeta de carga y luego una carpeta config.php. No es un archivo
Jakub Juszczak
99
En tu publicación escribiste de manera diferente. Si el archivo está allí, debe montarse como archivo.
BlackStork
16
Para que esto funcione, tuve que proporcionar un camino absoluto. La sugerencia usando PWD ayudó mucho aquí, ¡gracias!
Steve Smith
44
Para mí es crear una carpeta en lugar de los archivos, pero creo que debido a que ese archivo se copia más adelante en esa ruta, ¿hay alguna forma de posponer el enlace?
eKelvin
18
si /src/docker/myapp/upload/config.php no existe en el host docker creará una carpeta ... Lo que estoy haciendo es crear un script que cree un archivo vacío antes de ejecutar Docker Run, sería ideal si puedo indicarle a Docker que lo haga por mí a través de cmd line args.
cancerbero
78

Había estado sufriendo un problema similar. Intenté importar mi archivo de configuración a mi contenedor para poder arreglarlo cada vez que lo necesito sin reconstruir la imagen.

Quiero decir, pensé que el siguiente comando se asignaría $(pwd)/config.pydesde el host Docker al /root/app/config.pycontenedor como un archivo.

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

Sin embargo, siempre creaba un directorio llamado config.py, no un archivo.

Mientras buscaba una pista, encontré la razón (desde aquí )

Si usa -v o --volume para enlazar y montar un archivo o directorio que aún no existe en el host Docker, -v creará el punto final para usted. Siempre se crea como un directorio .

Por lo tanto, siempre se crea como un directorio porque mi host docker no tiene $(pwd)/config.py.

Incluso si creo config.py en docker host. $(pwd)/config.pysimplemente overwirte /root/app/config.pyno exportando /root/app/config.py.

SangminKim
fuente
16
Acabo de agregar un touch path/to/fileen el Dockerfilepara que cuando lo monte todavía sea un archivo (no un directorio creado)
shadi
8
lado izquierdo de :tiene que ser camino completo. Funciona de esta manera
sdkks
La touchrespuesta fue la siguiente: hazlo en Dockerfile y luego tu montaje de volumen compuesto por docker funcionará correctamente sin crear un directorio
ctrlbrk
27

Use mount ( --mount) en lugar de volume ( -v)

Más información: https://docs.docker.com/storage/bind-mounts/

Ejemplo:

Asegúrese de que /tmp/a.txt exista en el host de Docker

docker run -it --mount type=bind,source=/tmp/a.txt,target=/root/a.txt alpine sh
Subbu M
fuente
Gracias Subbu, @Jakub Juszczak esta debe ser la respuesta aceptada, es la única respuesta que responde a la pregunta en absoluto, y que trabajó para mí
neokyle
2
Esto realmente no responde la pregunta. los volúmenes también funcionarán (porque el problema está en la ruta absoluta). La única diferencia entre --mounty -ves el comportamiento cuando la parte del volumen del host aún no existe. Según su enlace:> Si usa -v o --volume para enlazar-montar un archivo o directorio que aún no existe en el host Docker, -v crea el punto final para usted. Siempre se crea como un directorio.
El padrino
2
No sé cómo traducir esto en un docker-compose. '¿Un poco de ayuda?
msanford
@msanford Agregué un ejemplo de docker-compose a la respuesta.
sebisnow
10

Para cualquiera que use el contenedor de Windows como yo, sepa que NO PUEDE enlazar o montar archivos individuales usando el contenedor de Windows.

Los siguientes ejemplos fallarán al usar contenedores basados ​​en Windows, ya que el destino de un volumen o montaje de enlace dentro del contenedor debe ser uno de: un directorio vacío o no existente; o una unidad que no sea C :. Además, la fuente de un montaje de enlace debe ser un directorio local, no un archivo .

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 ...

Es difícil de detectar, pero está ahí.

Enlace al problema de Github con respecto a la asignación de archivos en el contenedor de Windows

Justin Lessard
fuente
7

A partir de la versión 3.2 del archivo docker-compose, puede especificar un montaje de volumen de tipo "bind" (en lugar del tipo predeterminado "volumen") que le permite montar un solo archivo en el contenedor. Busque "montaje de enlace" en los documentos de volumen docker-compose: https://docs.docker.com/compose/compose-file/#volumes

En mi caso, estaba tratando de montar un solo archivo ".secrets" en mi aplicación que contenía secretos para el desarrollo local y las pruebas solamente. En producción, mi aplicación obtiene estos secretos de AWS.

Si monté este archivo como un volumen usando la sintaxis abreviada:

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

Docker crearía un directorio ".secrets" dentro del contenedor en lugar de asignarlo al archivo fuera del contenedor. Mi código generaría un error como "IsADirectoryError: [Errno 21] Es un directorio: '.secrets'".

Solucioné esto usando la sintaxis de mano larga en su lugar, especificando mi archivo de secretos usando un montaje de volumen de "lectura" de solo lectura:

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

Ahora Docker monta correctamente mi archivo .secrets en el contenedor, creando un archivo dentro del contenedor en lugar de un directorio. ¡Espero que otros encuentren útil este ejemplo!

Carlton Duffett
fuente
¡Gracias Señor! Esa fue la solución que necesitaba para poder montar mi archivo wp-config.php de WordPress (y evitar que se creara como un directorio)
Jono
6

También puede usar una ruta relativa a su docker-compose.ymlarchivo como esta (probado en el host de Windows, contenedor de Linux):

 volumes:
      - ./test.conf:/fluentd/etc/test.conf
Daniel
fuente
1
Probé esto en Mac con lo version: '3.7'especificado en el docker-compose.ymlarchivo con docker-compose versión 1.24.1, compilación 4667896b, y funcionó.
Acumenus
66
Todavía obtengo un directorio en lugar de un archivo.
chovy
0

Para mí, el problema era que tenía un enlace simbólico roto en el archivo que estaba tratando de montar en el contenedor

jla
fuente
0

Yo tenía el mismo problema en Windows, Docker 18.06.1-ce-win73 (19507).

Al quitar y volver a agregar la unidad compartida a través del panel de configuración de Docker, todo volvió a funcionar.

Piscina
fuente
0

En Windows, si necesita la variable env $ {PWD} env en su docker-compose.yml, puede crear un archivo .env en el mismo directorio que su archivo docker-compose.yml y luego insertar manualmente la ubicación de su carpeta.

CMD (pwd_var.bat):

echo PWD=%cd% >> .env

Powershell (pwd_var.ps1):

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

Hay más características buenas para las variables .env de docker-compose: https://docs.docker.com/compose/reference/envvars/ especialmente para la COMPOSE_CONVERT_WINDOWS_PATHSvariable env que permite que docker compose acepte la ruta de Windows con baskslash "\".

Cuando desee compartir un archivo en Windows, el archivo debe existir antes de compartirlo con el contenedor.

CallMarl
fuente
No puede usar PowerShell con Docker, crea un bloqueo de proveedor y perjudica a la comunidad ...
Matej 'Yin' Gagyi
0

Quizás esto ayude a alguien.

Tuve este problema y probé todo. Los enlaces de volumen se veían bien e incluso si monté el directorio (no los archivos), tenía los nombres de los archivos en el directorio montado correctamente pero los monté como directorios.

Intenté volver a habilitar las unidades compartidas y Docker se quejó de que el firewall está activo.

Después de deshabilitar el firewall, todo funcionaba bien.

Josef Sábl
fuente
¡Gracias por eso! Su publicación me hizo darme cuenta de que mi selinux estaba configurado para hacer cumplir y eso estaba causando todos mis problemas. No sé por qué te votaron ¯_ (ツ) _ / ¯
Octavian
0

Puede montar archivos o directorios / carpetas, todo depende del archivo o directorio fuente. Y también debe proporcionar una ruta completa o si no está seguro de poder usar PWD. Aquí hay un ejemplo de trabajo simple.

En este ejemplo, estoy montando el archivo env-command que ya existe en mi directorio de trabajo

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

Tengo el mismo problema en mi Windows 8.1

Resultó que se debió a la sensibilidad de mayúsculas y minúsculas de la ruta. Llamé docker-compose updesde el directorio cd /c/users/alex/y dentro del contenedor un archivo se convirtió en directorio.

Pero cuando lo hice cd /c/Users/alex/(no Usuarios en mayúscula) y llamé docker-compose updesde allí, funcionó.

En mi sistema, tanto el directorio de usuarios como el directorio de Alex están en mayúsculas, aunque parece que solo importa el directorio de usuarios.

Alex Velickiy
fuente