En resumen: No, su VOLUME
instrucción no es correcta.
Los archivos Docker VOLUME
especifican uno o más volúmenes dados las rutas del lado del contenedor. Pero no permite que el autor de la imagen especifique una ruta de host. En el lado del host, los volúmenes se crean con un nombre de ID muy largo dentro de la raíz de Docker. En mi máquina esto es /var/lib/docker/volumes
.
Nota: Debido a que el nombre autogenerado es extremadamente largo y no tiene sentido desde la perspectiva humana, estos volúmenes a menudo se denominan "sin nombre" o "anónimo".
Su ejemplo que usa un '.' el personaje ni siquiera se ejecutará en mi máquina, no importa si hago que el punto sea el primer o segundo argumento. Me sale este mensaje de error:
docker: Respuesta de error del daemon: error de tiempo de ejecución oci: container_linux.go: 265: el proceso de inicio del contenedor causó "process_linux.go: 368: el inicio del contenedor causó \" abrir / dev / ptmx: no existe tal archivo o directorio \ "".
Sé que lo que se ha dicho hasta este punto probablemente no sea muy valioso para alguien que intente comprenderlo VOLUME
y -v
ciertamente no proporciona una solución para lo que intenta lograr. Entonces, con suerte, los siguientes ejemplos arrojarán algo más de luz sobre estos temas.
Minitutorial: especificación de volúmenes
Dado este Dockerfile:
FROM openjdk:8u131-jdk-alpine
VOLUME vol1 vol2
(Para el resultado de este minitutorial, no hay diferencia si especificamos vol1 vol2
o /vol1 /vol2
no me preguntan por qué)
Constrúyelo:
docker build -t my-openjdk
Correr:
docker run --rm -it my-openjdk
Dentro del contenedor, ejecute ls
en la línea de comando y notará que existen dos directorios; /vol1
y /vol2
.
La ejecución del contenedor también crea dos directorios, o "volúmenes", en el lado del host.
Mientras se ejecuta el contenedor, ejecute docker volume ls
en la máquina host y verá algo como esto (he reemplazado la parte central del nombre con tres puntos por brevedad):
DRIVER VOLUME NAME
local c984...e4fc
local f670...49f0
De vuelta en el contenedor , ejecutar touch /vol1/weird-ass-file
(crea un archivo en blanco en dicha ubicación).
Este archivo ahora está disponible en la máquina host, en uno de los volúmenes sin nombre jajaja. Me tomó dos intentos porque probé por primera vez el primer volumen listado, pero finalmente encontré mi archivo en el segundo volumen listado, usando este comando en la máquina host:
sudo ls /var/lib/docker/volumes/f670...49f0/_data
Del mismo modo, puede intentar eliminar este archivo en el host y también se eliminará en el contenedor.
Nota: La _data
carpeta también se conoce como "punto de montaje".
Salga del contenedor y enumere los volúmenes en el host. Se han ido. Usamos la --rm
bandera cuando ejecutamos el contenedor y esta opción elimina efectivamente no solo el contenedor al salir, sino también los volúmenes.
Ejecute un nuevo contenedor, pero especifique un volumen usando -v
:
docker run --rm -it -v /vol3 my-openjdk
Esto agrega un tercer volumen y todo el sistema termina teniendo tres volúmenes sin nombre. El comando habría fallado si hubiéramos especificado solo -v vol3
. El argumento debe ser una ruta absoluta dentro del contenedor. En el lado del host, el nuevo tercer volumen es anónimo y reside junto con los otros dos volúmenes /var/lib/docker/volumes/
.
Se dijo anteriormente que Dockerfile
no se puede asignar a una ruta de host, lo que nos plantea un problema al intentar traer archivos desde el host al contenedor durante el tiempo de ejecución. Una -v
sintaxis diferente resuelve este problema.
Imagine que tengo una subcarpeta en el directorio de mi proyecto ./src
que deseo sincronizar /src
dentro del contenedor. Este comando hace el truco:
docker run -it -v $(pwd)/src:/src my-openjdk
Ambos lados del :
personaje esperan un camino absoluto. El lado izquierdo es una ruta absoluta en la máquina host, el lado derecho es una ruta absoluta dentro del contenedor. pwd
es un comando que "imprime el directorio actual / de trabajo". Poner el comando $()
toma el comando entre paréntesis, lo ejecuta en un subshell y devuelve la ruta absoluta a nuestro directorio de proyecto.
En conjunto, supongamos que tenemos ./src/Hello.java
en nuestra carpeta de proyecto en la máquina host con el siguiente contenido:
public class Hello {
public static void main(String... ignored) {
System.out.println("Hello, World!");
}
}
Construimos este Dockerfile:
FROM openjdk:8u131-jdk-alpine
WORKDIR /src
ENTRYPOINT javac Hello.java && java Hello
Ejecutamos este comando:
docker run -v $(pwd)/src:/src my-openjdk
Esto imprime "¡Hola, mundo!".
La mejor parte es que somos completamente libres de modificar el archivo .java con un nuevo mensaje para otra salida en una segunda ejecución, sin tener que reconstruir la imagen =)
Observaciones finales
Soy bastante nuevo en Docker, y el "tutorial" mencionado anteriormente refleja la información que obtuve de un hackathon de línea de comandos de 3 días. Estoy casi avergonzado de no haber podido proporcionar enlaces a documentación clara en inglés que respalde mis declaraciones, pero honestamente creo que esto se debe a la falta de documentación y no al esfuerzo personal. Sé que los ejemplos funcionan según lo anunciado usando mi configuración actual que es "Windows 10 -> Vagrant 2.0.0 -> Docker 17.09.0-ce".
El tutorial no resuelve el problema "cómo especificamos la ruta del contenedor en el Dockerfile y dejamos que el comando de ejecución solo especifique la ruta del host". Puede haber una manera, simplemente no la he encontrado.
Finalmente, tengo el presentimiento de que especificar VOLUME
en el Dockerfile no solo es infrecuente, sino que probablemente sea una mejor práctica para nunca usarlo VOLUME
. Por dos razones. La primera razón que ya hemos identificado: no podemos especificar la ruta del host, lo cual es bueno porque los Dockerfiles deben ser muy independientes de los detalles de una máquina host. Pero la segunda razón es que las personas podrían olvidarse de usar la --rm
opción al ejecutar el contenedor. Uno podría recordar quitar el contenedor pero olvidarse de quitar el volumen. Además, incluso con la mejor memoria humana, podría ser una tarea desalentadora descubrir cuál de todos los volúmenes anónimos es seguro eliminar.