Cómo montar volúmenes de host en contenedores Docker en Dockerfile durante la compilación

Resuelto xpt asked hace 9 años • 15 respuestas

Desde 2014, cuando se hizo esta pregunta, han sucedido muchas situaciones y muchas cosas han cambiado. Hoy volveré a abordar el tema y editaré esta pregunta por duodécima vez para reflejar los últimos cambios . La pregunta puede parecer larga, pero está organizada en orden cronológico inverso, por lo que los últimos cambios están en la parte superior y no dude en dejar de leer en cualquier momento.

La pregunta que quería resolver era: cómo montar volúmenes de host en contenedores Docker en Dockerfile durante la compilación, es decir, tener la docker run -v /export:/exportcapacidad durante docker build.

Una de las razones detrás de esto, para mí, es que cuando construyo cosas en Docker, no quiero que esos apt-get installcachés () estén bloqueados en una única ventana acoplable, sino compartirlos/reutilizarlos.

Esa fue la razón principal por la que hice esta pregunta. Y una razón más a la que me enfrento hoy es intentar hacer uso de un enorme repositorio privado del host que, de lo contrario, tengo que hacer git clonedesde un repositorio privado dentro de la ventana acoplable usando mi clave ssh privada, lo cual no sé cómo y no lo he hecho. investigado todavía.

Última actualización:

El Buildkit en la respuesta de @BMitch

Con esa RUN --mountsintaxis, también puede vincular directorios de montaje de solo lectura desde el contexto de compilación...

ahora se ha integrado en la ventana acoplable (que pensé que era una herramienta de terceros), siempre que la suya sea superior a 18.09. El mío es 20.10.7 ahora: https://docs.docker.com/develop/develop-images/build_enhancements/

Para habilitar las compilaciones de BuildKit

La forma más sencilla desde una nueva instalación de Docker es configurar la variable de entorno DOCKER_BUILDKIT=1 al invocar el comando Docker Build, como por ejemplo:

$ DOCKER_BUILDKIT=1 docker build .

De lo contrario, obtendrás:

the --mount option requires BuildKit. Refer to https://docs.docker.com/go/buildkit/ to learn how to build images with BuildKit enabled

Por lo tanto, será la solución perfecta para mi segundo caso de uso, como se explicó anteriormente.

Actualización al 7 de mayo de 2019:

Antes de Docker v18.09, la respuesta correcta debería ser la que comienza con:

Hay una forma de montar un volumen durante una compilación, pero no implica Dockerfiles.

Sin embargo, esa fue una respuesta mal expresada, organizada y respaldada. Cuando estaba reinstalando mi ventana acoplable, me topé con el siguiente artículo:

Dockerizar un servicio apt-cacher-ng
https://docs.docker.com/engine/examples/apt-cacher-ng/

Esa es la solución de Docker a esta/mi pregunta, no directa sino indirectamente. Es la forma ortodoxa que Docker nos sugiere que hagamos. Y admito que es mejor que el que intentaba preguntar aquí.

Otra forma es la respuesta recientemente aceptada , por ejemplo, Buildkit en v18.09.

Elige el que más te convenga.


Fue: Había una solución: rocker, que no era de Docker, pero ahora que rocker está descontinuado, vuelvo a responder a "No es posible" .


Actualización anterior: entonces la respuesta es "No es posible". Puedo aceptarlo como respuesta porque sé que el tema se ha discutido ampliamente en https://github.com/docker/docker/issues/3156 . Puedo entender que la portabilidad es una cuestión primordial para los desarrolladores de Docker; pero como usuario de Docker, debo decir que estoy muy decepcionado por 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 haya > 1 GB de datos del árbol de Portage en ninguna de las capas una vez que se haya creado la imagen. podría tener algunos contenedores bonitos y compactos si no fuera por el gigantesco árbol de transporte que tiene que aparecer en la imagen durante la instalación ". Sí, puedo usar wget o curl para descargar lo que necesite, pero el hecho de que sea simplemente una consideración de portabilidad ahora me obliga a descargar > 1 GB del árbol de Portage cada vez que construyo una imagen base de Gentoo, no es eficiente ni fácil de usar. Además, el repositorio de paquetes SIEMPRE estará en /usr/portage, por lo tanto SIEMPRE PORTÁTIL en Gentoo. Una vez más, respeto la decisión, pero mientras tanto permítanme expresar mi decepción. 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 Docker Remote API". Mi ventana acoplable 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 el host en contenedores Docker, mediante el 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
xpt avatar Sep 26 '14 09:09 xpt
Aceptado

No es posible utilizar las VOLUMEinstrucciones para indicarle a Docker qué montar. Eso afectaría seriamente la portabilidad. Esta instrucción le dice a Docker que el contenido de esos directorios no va en imágenes y se puede acceder a él desde otros contenedores utilizando el --volumes-fromparámetro de línea de comando. Debe ejecutar el contenedor -v /path/on/host:/path/in/containerpara acceder a los directorios desde el host.

No es posible montar volúmenes de host durante la compilación. No existe una compilación privilegiada y montar el host también degradaría seriamente la portabilidad. Quizás quieras intentar usar wget o curl para descargar lo que necesites para la compilación y ponerlo en marcha.

Andreas Steffan avatar Sep 26 '2014 06:09 Andreas Steffan

Primero, responder "¿por qué no VOLUMEfunciona?" Cuando define a VOLUMEen el Dockerfile, solo puede definir el destino, no el origen del volumen. Durante la compilación, solo obtendrás un volumen anónimo. Ese volumen anónimo se montará en cada RUNcomando, se completará previamente con el contenido de la imagen y luego se descartará al final del RUNcomando. Solo se guardan los cambios en el contenedor, no los cambios en el volumen.


Desde que se hizo esta pregunta, se han lanzado algunas funciones que pueden ayudar. La primera son las compilaciones de varias etapas que le permiten crear una primera etapa ineficiente en cuanto a espacio en disco y copiar solo la salida necesaria en la etapa final que envíe. Y la segunda característica es Buildkit, que está cambiando drásticamente la forma en que se crean las imágenes y se agregan nuevas capacidades a la compilación.

Para una compilación de varias etapas, tendría varias FROMlíneas, cada una de las cuales iniciaría la creación de una imagen independiente. De forma predeterminada, solo se etiqueta la última imagen, pero puede copiar archivos de etapas anteriores. El uso estándar es tener un entorno de compilación para construir un binario u otro artefacto de aplicación, y un entorno de ejecución como segunda etapa que copia ese artefacto. Podrías tener:

FROM debian:sid as builder
COPY export /export
RUN compile command here >/result.bin

FROM debian:sid
COPY --from=builder /result.bin /result.bin
CMD ["/result.bin"]

Eso daría como resultado una compilación que solo contiene el binario resultante, y no el directorio /export completo.


Buildkit dejará de ser experimental en 18.09. Es un rediseño completo del proceso de compilación, incluida la capacidad de cambiar el analizador frontal. Uno de esos cambios en el analizador implementó la RUN --mountopció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 las reinstalaciones de paquetes):

# syntax = docker/dockerfile:experimental
FROM debian:latest
RUN --mount=target=/var/lib/apt/lists,type=cache \
    --mount=target=/var/cache/apt,type=cache \
    apt-get update \
 && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
      git

Ajustaría 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: Answer is here: With that RUN --mount syntax, you can also bind mount read-only directories from the build-context. The folder must exist in the build context, and it is not mapped back to the host or the build client:

# syntax = docker/dockerfile:experimental
FROM debian:latest
RUN --mount=target=/export,type=bind,source=export \
    process export directory here...

Note that because the directory is mounted from the context, it's also mounted read-only, and you cannot push changes back to the host or client. When you build, you'll want an 18.09 or newer install and enable buildkit with export DOCKER_BUILDKIT=1.

If you get an error that the mount flag isn't supported, that indicates that you either didn't enable buildkit with the above variable, or that you didn't enable the experimental syntax with the syntax line at the top of the Dockerfile before any other lines, including comments. Note that the variable to toggle buildkit will only work if your docker install has buildkit support built in, which requires version 18.09 or newer from Docker, both on the client and server.

BMitch avatar Oct 11 '2018 14:10 BMitch