Pregunta original: ¿Cómo usar la instrucción VOLUME en Dockerfile?
La pregunta real que quiero resolver es: cómo montar volúmenes de host en contenedores docker en Dockerfile durante la compilación, es decir, tener la docker run -v /export:/export
capacidad durante docker build
.
La razón detrás de esto, para mí, es cuando construyo cosas en Docker, no quiero esas apt-get install
cachés ( ) encerradas en un solo docker, sino compartirlas / reutilizarlas. Esa es la razón principal por la que hago esta pregunta.
Última actualización:
Antes de docker v18.09, la respuesta correcta debería ser la que comienza con:
Hay una manera de montar un volumen durante una compilación, pero no involucra Dockerfiles.
Sin embargo, esa fue una respuesta mal planteada, organizada y respaldada. Cuando estaba reinstalando mi docker contiene, me encontré con el siguiente artículo:
Dockerize un servicio apt-cacher-ng
https://docs.docker.com/engine/examples/apt-cacher-ng/
Esa es la solución de Docker para esta / mi pregunta, no directa sino indirectamente. Es la forma ortodoxa que Docker sugiere que hagamos. Y admito que es mejor que el que estaba tratando de preguntar aquí.
Otra forma es la respuesta recién aceptada , por ejemplo, el Buildkit en v18.09.
Elige lo que más te convenga.
Era: había habido una solución: rocker, que no era de Docker, pero ahora que el rocker ha sido descontinuado, revierto la respuesta a "No es posible" nuevamente.
Actualización anterior: Entonces la respuesta es "No es posible". Puedo aceptarlo como respuesta, ya que sé que el problema se ha discutido ampliamente en https://github.com/docker/docker/issues/3156 . Puedo entender que la portabilidad es un problema primordial para el desarrollador de Docker; pero como usuario de Docker, debo decir que estoy muy decepcionado con esta característica que falta. Permítanme cerrar mi argumento con una cita de la discusión antes mencionada: " Me gustaría usar Gentoo como imagen base, pero definitivamente no quiero que> 1 GB de datos del árbol de Portage estén en ninguna de las capas una vez que la imagen ha sido construida. podría tener algunos buenos contenedores compactos si no fuera por el gigantesco árbol de portage que tiene que aparecer en la imagen durante la instalación."Sí, puedo usar wget o curl para descargar lo que necesito, pero el hecho de que solo una consideración de portabilidad me está obligando a descargar> 1 GB de árbol de Portage cada vez que construyo una imagen base de Gentoo no es eficiente ni fácil de usar. Además más aún, el repositorio de paquetes SIEMPRE estará bajo / usr / portage, por lo tanto SIEMPRE PORTÁTIL bajo Gentoo. Nuevamente, respeto la decisión, pero permítame expresar mi decepción también mientras tanto. Gracias.
Pregunta original en detalles:
De
Compartir directorios a través de volúmenes
http://docker.readthedocs.org/en/v0.7.3/use/working_with_volumes/
dice que la función de volúmenes de datos "ha estado disponible desde la versión 1 de la API remota de Docker". Mi docker es de la versión 1.2.0, pero encontré que el ejemplo dado en el artículo anterior no funciona:
# BUILD-USING: docker build -t data .
# RUN-USING: docker run -name DATA data
FROM busybox
VOLUME ["/var/volume1", "/var/volume2"]
CMD ["/usr/bin/true"]
¿Cuál es la forma correcta en Dockerfile de montar volúmenes montados en host en contenedores de docker, a través del comando VOLUME?
$ apt-cache policy lxc-docker
lxc-docker:
Installed: 1.2.0
Candidate: 1.2.0
Version table:
*** 1.2.0 0
500 https://get.docker.io/ubuntu/ docker/main amd64 Packages
100 /var/lib/dpkg/status
$ cat Dockerfile
FROM debian:sid
VOLUME ["/export"]
RUN ls -l /export
CMD ls -l /export
$ docker build -t data .
Sending build context to Docker daemon 2.56 kB
Sending build context to Docker daemon
Step 0 : FROM debian:sid
---> 77e97a48ce6a
Step 1 : VOLUME ["/export"]
---> Using cache
---> 59b69b65a074
Step 2 : RUN ls -l /export
---> Running in df43c78d74be
total 0
---> 9d29a6eb263f
Removing intermediate container df43c78d74be
Step 3 : CMD ls -l /export
---> Running in 8e4916d3e390
---> d6e7e1c52551
Removing intermediate container 8e4916d3e390
Successfully built d6e7e1c52551
$ docker run data
total 0
$ ls -l /export | wc
20 162 1131
$ docker -v
Docker version 1.2.0, build fa7b24f
VOLUME ~/host_dir ~/container_dir
. La discusión es bastante extensa, ¿hay alguna forma breve de resumir cuál es la razón?Respuestas:
Primero, para responder "¿por qué no
VOLUME
funciona?" Cuando define unVOLUME
en el Dockerfile, solo puede definir el destino, no la fuente del volumen. Durante la compilación, solo obtendrá un volumen anónimo de esto. Ese volumen anónimo se montará en cadaRUN
comando, se rellenará previamente con el contenido de la imagen y luego se descartará al final delRUN
comando. Solo se guardan los cambios en el contenedor, no los cambios en el volumen.Desde que se hizo esta pregunta, se han lanzado algunas características que pueden ayudar. Primero, las compilaciones de varias etapas que le permiten construir una primera etapa ineficiente de espacio en disco y copiar solo la salida necesaria a la etapa final que envía. Y la segunda característica es Buildkit, que está cambiando drásticamente cómo se crean las imágenes y se agregan nuevas capacidades a la construcción.
Para una compilación de varias etapas, tendría varias
FROM
líneas, cada una de las cuales comenzaría la creación de una imagen separada. Solo la última imagen está etiquetada de forma predeterminada, pero puede copiar archivos de etapas anteriores. El uso estándar es tener un entorno de compilador para construir un artefacto de aplicación binario u otro, y un entorno de tiempo de ejecución como la segunda etapa que copia sobre ese artefacto. Podrías tener:Eso daría como resultado una compilación que solo contiene el binario resultante, y no el directorio completo / exportar.
Buildkit está saliendo de experimental en 18.09. Es un rediseño completo del proceso de compilación, incluida la capacidad de cambiar el analizador frontend. Uno de esos cambios en el analizador ha implementado la
RUN --mount
opción que le permite montar un directorio de caché para sus comandos de ejecución. Por ejemplo, aquí hay uno que monta algunos de los directorios de Debian (con una reconfiguración de la imagen de Debian, esto podría acelerar la reinstalación de paquetes):Debería ajustar el directorio de caché para cualquier caché de aplicación que tenga, por ejemplo, $ HOME / .m2 para maven o /root/.cache para golang.
TL; DR: la respuesta está aquí: con esa
RUN --mount
sintaxis, también puede vincular directorios de solo lectura de montaje desde el contexto de compilación. La carpeta debe existir en el contexto de compilación y no está asignada de nuevo al host o al cliente de compilación:Tenga en cuenta que debido a que el directorio está montado desde el contexto, también está montado como de solo lectura, y no puede enviar los cambios al host o al cliente. Cuando construyas, querrás una instalación 18.09 o posterior y habilitar el kit de compilación con
export DOCKER_BUILDKIT=1
.Si recibe un error de que el indicador de montaje no es compatible, eso indica que no activó el kit de compilación con la variable anterior o que no activó la sintaxis experimental con la línea de sintaxis en la parte superior del Dockerfile antes cualquier otra línea, incluidos los comentarios. Tenga en cuenta que la variable para alternar buildkit solo funcionará si su instalación de Docker tiene incorporado el soporte de buildkit, que requiere la versión 18.09 o posterior de Docker, tanto en el cliente como en el servidor.
fuente
No es posible usar las
VOLUME
instrucciones para decirle a Docker qué montar. Eso seriamente rompería la portabilidad. Esta instrucción le dice a Docker que el contenido de esos directorios no va en imágenes y se puede acceder desde otros contenedores utilizando el--volumes-from
parámetro de línea de comando. Debe ejecutar el contenedor-v /path/on/host:/path/in/container
para acceder a los directorios desde el host.No es posible montar volúmenes de host durante la compilación. No hay una construcción privilegiada y el montaje del host también degradaría seriamente la portabilidad. Es posible que desee intentar usar wget o curl para descargar lo que necesite para la compilación y ponerlo en su lugar.
fuente
ACTUALIZACIÓN: Alguien simplemente no tomará un no como respuesta, y me gusta mucho, especialmente a esta pregunta en particular.
BUENAS NOTICIAS, ahora hay un camino:
La solución es Rocker: https://github.com/grammarly/rocker
John Yani dijo : "OMI, resuelve todos los puntos débiles de Dockerfile, lo que lo hace adecuado para el desarrollo".
Balancín
https://github.com/grammarly/rocker
Actualización: Rocker ha sido descontinuado, según el repositorio oficial del proyecto en Github
fuente
MOUNT ~/code/docker-app-dev/new-editor/:/src/
y mi comando de construcción Rocker es esterocker build -f Dockerfile .
. ¿Qué estoy haciendo mal?~
es un metacarácter de shell Bourne.Rocker build
no permitedocker run
opciones de línea de comandos, por lo que actualmente no permite cosas como--privileged
.Hay una manera de montar un volumen durante una compilación, pero no involucra Dockerfiles.
La técnica sería crear un contenedor a partir de la base que quisiera usar (montar sus volúmenes en el contenedor con la
-v
opción), ejecutar un script de shell para hacer su trabajo de creación de imágenes, y luego confirmar el contenedor como una imagen cuando haya terminado .Esto no solo dejará de lado el exceso de archivos que no desea (también es bueno para archivos seguros, como los archivos SSH), sino que también crea una sola imagen. Tiene inconvenientes: el comando commit no admite todas las instrucciones de Dockerfile, y no le permite retomarlo cuando lo dejó si necesita editar su script de compilación.
ACTUALIZAR:
Por ejemplo,
fuente
debian:wheezy
y el script de shell esbuild.sh
, ¿qué instrucciones específicas se usarían?A medida que ejecuta el contenedor, se crea un directorio en su host y se monta en el contenedor. Puedes averiguar con qué directorio es esto
Si desea montar un directorio desde su host dentro de su contenedor, debe usar el
-v
parámetro y especificar el directorio. En su caso, esto sería:Así que usarías la carpeta hosts dentro de tu contenedor.
fuente
Creo que puede hacer lo que quiere haciendo ejecutando la compilación a través de un comando docker que se ejecuta dentro de un contenedor docker. Ver Docker ahora puede ejecutarse dentro de Docker | Blog Docker . Se utilizó una técnica como esta, pero que en realidad accedía a la ventana acoplable externa desde un contenedor, por ejemplo, al explorar cómo crear el contenedor Docker más pequeño posible | Blog de Xebia .
Otro artículo relevante es Optimizing Docker Images | CenturyLink Labs , que explica que si termina descargando cosas durante una compilación, puede evitar que se desperdicie espacio en la imagen final descargando, compilando y eliminando la descarga todo en un solo paso de EJECUTAR.
fuente
Es feo, pero logré una apariencia de esto así:
Dockerfile:
imageBuild.sh:
Tengo una compilación de Java que descarga el universo en /root/.m2, y lo hice cada vez .
imageBuild.sh
copia el contenido de esa carpeta en el host después de la compilación y losDockerfile
copia nuevamente en la imagen para la próxima compilación.Esto es algo como cómo funcionaría un volumen (es decir, persiste entre compilaciones).
fuente
Aquí hay una versión simplificada del enfoque de 2 pasos usando build y commit, sin scripts de shell. Implica:
Con cambios relativamente menores, el paso adicional agrega solo unos segundos al tiempo de construcción.
Básicamente:
En mi caso de uso, quiero generar previamente un archivo maven toolchains.xml, pero mis muchas instalaciones JDK están en un volumen que no está disponible hasta el tiempo de ejecución. Algunas de mis imágenes no son compatibles con todos los JDKS, por lo que necesito probar la compatibilidad en el momento de la compilación y rellenar toolchains.xml condicionalmente. Tenga en cuenta que no necesito que la imagen sea portátil, no la publico en Docker Hub.
fuente
Como muchos ya han respondido, no es posible montar volúmenes de host durante la compilación. Solo me gustaría agregar una
docker-compose
forma, creo que será bueno tenerla, principalmente para uso de desarrollo / pruebaDockerfile
docker-compose.yml
Y corre tu contenedor por
docker-compose up -d --build
fuente