Docker ADD vs VOLUME

116

Estoy aprendiendo Docker y tengo dudas sobre cuándo y dónde usar ADDy VOLUME. Esto es lo que creo que hacen ambos:

AÑADIR

Copie archivos a la imagen en el momento de la compilación. La imagen tiene todos los archivos para que puedas implementarla con mucha facilidad. Por otro lado, tener que compilar cada vez no parece una buena idea en desarrollo porque la compilación requiere que el desarrollador ejecute un comando para reconstruir el contenedor; Además, la construcción del contenedor puede llevar mucho tiempo.

VOLUMEN

Entiendo que al usarlo docker run -vpuede montar una carpeta de host dentro de su contenedor, de esta manera puede modificar fácilmente los archivos y ver cómo reacciona la aplicación en su contenedor a los cambios. Se ve muy bien en desarrollo, pero no estoy seguro de cómo implementar mis archivos de esta manera.

Cristian garcia
fuente
3
En general, es mejor preferir COPYa ADD. Son casi iguales, pero ADDtienen algunas capacidades adicionales con URL y archivos de almacenamiento que pueden resultar sorprendentes.
Adrian Mouat
2
@jamesmstone: ese enlace (y los documentos oficiales de la ventana acoplable) recomiendan lo contrario: use COPY en lugar de ADD.
Ingeniero de software
Ups, tienes razón - ¡salud!
jamesmstone

Respuestas:

183

AÑADIR

La diferencia fundamental entre estos dos es que ADDhace que todo lo que esté agregando, ya sea una carpeta o simplemente un archivo, sea parte de su imagen . Cualquiera que use la imagen que ha creado posteriormente tendrá acceso a lo que sea ADD. Esto es cierto incluso si luego lo elimina porque Docker funciona en capas y la ADDcapa seguirá existiendo como parte de la imagen. Para ser claros, solo tiene ADDalgo en tiempo de compilación y nunca puede hacerlo ADDen tiempo de ejecución.

Algunos ejemplos de casos en los que le gustaría usar ADD:

  • Tiene algunos requisitos en un archivo requirements.txt que desea hacer referencia e instalar en su Dockerfile. A continuación, puede hacer: ADD ./requirements.txt /requirements.txtseguido deRUN pip install -r /requirements.txt
  • Desea usar el código de su aplicación como contexto en su Dockerfile, por ejemplo, si desea configurar el directorio de su aplicación como el directorio de trabajo en su imagen y hacer que el comando predeterminado en un contenedor se ejecute desde su imagen en realidad ejecute su aplicación, usted puede hacer:

    ADD ./ /usr/local/git/my_app

    WORKDIR /usr/local/git/my_app

    CMD python ./main.py

VOLUMEN

El volumen, por otro lado, solo permite que un contenedor que se ejecuta desde su imagen tenga acceso a alguna ruta en cualquier máquina local en la que se esté ejecutando el contenedor. No puede usar archivos de su VOLUMEdirectorio en su Dockerfile . No se podrá acceder a nada en su directorio de volúmenes en el momento de la compilación, pero se podrá acceder en el tiempo de ejecución .

Algunos ejemplos de casos en los que le gustaría usar VOLUME:

  • La aplicación que se ejecuta en su contenedor inicia sesión /var/log/my_app. Desea que esos registros sean accesibles en la máquina host y que no se eliminen cuando se elimine el contenedor. Puede hacer esto creando un punto de montaje en /var/log/my_appagregando VOLUME /var/log/my_appa su Dockerfile y luego ejecutando su contenedor condocker run -v /host/log/dir/my_app:/var/log/my_app some_repo/some_image:some_tag
  • Tiene algunos archivos de configuración local a los que desea que tenga acceso la aplicación en el contenedor. Quizás esos archivos de configuración sean diferentes en su máquina local vs dev vs producción. Especialmente si esos archivos de configuración son secretos, en cuyo caso definitivamente no los desea en su imagen . En ese caso, una buena estrategia es agregar VOLUME /etc/settings/my_app_settingsa su Dockerfile, ejecutar su contenedor docker run -v /host/settings/dir:/etc/settings/my_app_settings some_repo/some_image:some_tagy asegurarse de que / host / settings / dir exista en todos los entornos en los que espera que se ejecute su aplicación.
Eli
fuente
13
De lejos, la publicación más útil que encontré hasta ahora en ADD y VOLUME
Jasmeet
5
¿Qué sucede si se especifica VOLUME, pero no se proporciona durante la ejecución de la ventana acoplable (por ejemplo, falta el parámetro -v xxx)? Es el resp. ¿VOLUMEN entonces efectivamente se vuelve transitorio?
col
Dentro de un Dockerfile, los volúmenes probablemente solo estén destinados a la persistencia y / o la depuración, pero puede usar el conmutador de línea de comando de volumen para obtener una aplicación en una imagen existente (no se necesita Dockerfile) y ejecutarla así docker run -v $HOST_PATH:$CONTAINER_PATH node:latest node $CONTAINER_PATH/app.js.
Chinoto Vokro
bonito detalle de "capa"
stratovarius
27

La VOLUMEinstrucción crea un volumen de datos en su contenedor Docker en tiempo de ejecución. El directorio proporcionado como argumento VOLUMEes un directorio que pasa por alto el sistema de archivos de la unión. y se usa principalmente para datos persistentes y compartidos.

Si ejecuta docker inspect <your-container>, verá en la Mountssección que hay un Sourceque representa la ubicación del directorio en el host y un Destinationque representa la ubicación del directorio montado en el contenedor. Por ejemplo,

"Mounts": [
  {
    "Name": "fac362...80535",
    "Source": "/var/lib/docker/volumes/fac362...80535/_data",
    "Destination": "/webapp",
    "Driver": "local",
    "Mode": "",
    "RW": true,
    "Propagation": ""
  }
]

Aquí hay 3 casos de uso para docker run -v:

  1. docker run -v /data: Esto es análogo a especificar la VOLUMEinstrucción en su Dockerfile.
  2. docker run -v $host_path:$container_path: Esto le permite montar $host_pathdesde su host $container_pathen su contenedor durante el tiempo de ejecución. En desarrollo, esto es útil para compartir código fuente en su host con el contenedor. En producción, esto se puede usar para montar cosas como la información DNS del host (que se encuentra en /etc/resolv.conf) o secretos en el contenedor. Por el contrario, también puede utilizar esta técnica para escribir los registros del contenedor en carpetas específicas en el host. Ambos $host_pathy $container_pathdeben ser caminos absolutos.
  3. docker run -v my_volume:$container_path: Esto crea un volumen de datos en su contenedor $container_pathy lo nombra my_volume. Es esencialmente lo mismo que crear y nombrar un volumen usando docker volume create my_volume. Nombrar un volumen como este es útil para un volumen de datos de contenedor y un volumen de almacenamiento compartido utilizando un controlador de almacenamiento de múltiples hosts como Flocker .

Tenga en cuenta que el enfoque de montar una carpeta de host como un volumen de datos no está disponible en Dockerfile. Para citar la documentación de Docker ,

Nota: Esto no está disponible en un Dockerfile debido a la portabilidad y el propósito de compartirlo. Como el directorio de host es, por su naturaleza, dependiente del host, un directorio de host especificado en un Dockerfile probablemente no funcionaría en todos los hosts.

Ahora, si desea copiar sus archivos a contenedores en entornos que no son de desarrollo, puede usar ADDoCOPY instrucciones en su Dockerfile. Estos son los que suelo utilizar para la implementación que no es de desarrollo.

ivan.sim
fuente
3
¿Debo crear 2 archivos de Docker? ¿Uno para desarrollo y otro para implementación?
Cristian García
No lo creo. No hay nada de malo en tener la ADDinstrucción en su Dockerfile, ya que solo la ejecuta el docker buildcomando. Esto es necesario cuando otros crean su contenedor por primera vez y cuando está listo para implementarlo en otros entornos que no son de desarrollo.
ivan.sim
3
Pero, ¿no sería más eficiente crear una imagen sin los archivos y usar el -vcomando para el desarrollo, y hacer que otro archivo acoplable cree una imagen que incluya los archivos ADDpara la implementación?
Cristian García
1
Es una compensación que tienes que decidir. Elija lo que funcione para usted. ¿Cuánto tiempo ADDdura la construcción con una toma de todos modos? ¿Un par de segundos en total? Si tiene dos archivos Dockerfile y los comparte con otros (o lo publica en el registro de Docker ), ¿cuál es el predeterminado? Tendrá una sobrecarga de mantenimiento adicional para garantizar que el Dockerfile predeterminado correcto llegue a los usuarios correctos. Pero al final del día, usted decide qué funciona mejor para usted. Personalmente, me gusta asegurarme de que haya un solo Dockerfile para construir mi contenedor.
ivan.sim
11
Por cierto, creo que está bien primero ADD, luego anular ese add con -v para el desarrollo. De esa manera, no necesitará Dockerfiles separados.
Attila Szeremi