Descripción de la instrucción "VOLUMEN" en DockerFile
A continuación se muestra el contenido de mi" Dockerfile "
FROM node:boron
# Create app directory
RUN mkdir -p /usr/src/app
# change working dir to /usr/src/app
WORKDIR /usr/src/app
VOLUME . /usr/src/app
RUN npm install
EXPOSE 8080
CMD ["node" , "server" ]
En este archivo estoy esperando " VOLUMEN . /usr/src /app" instrucción para montar el contenido del directorio de trabajo actual en el host que se montará en la carpeta/usr/src / app del contenedor.
Por favor, hágamelo saber si esta es la manera correcta ?
2 answers
El tutorial oficial de docker dice:
Un volumen de datos es un directorio especialmente designado dentro de uno o más contenedores que omite el Sistema de archivos Union. Los volúmenes de datos proporcionan varias características útiles para datos persistentes o compartidos:
- Los volúmenes se inicializan cuando se crea un contenedor. Si la imagen base del contenedor contiene datos en el punto de montaje especificado,
que los datos existentes se copian en el nuevo volumen tras volumen
inicialización. (Tenga en cuenta que esto no se aplica al montar un host
directorio.)Los volúmenes de datos se pueden compartir y reutilizar entre contenedores.
Los cambios en un volumen de datos se realizan directamente.
Los cambios en un volumen de datos no se incluirán cuando actualice una imagen.
- Los volúmenes de datos persisten incluso si se elimina el propio contenedor.
Dentro de Dockerfile
puede especificar solo el destino del volumen dentro de contenedor. por ejemplo, /usr/src/app
.
Cuando ejecuta el contenedor, por ejemplo, docker run --volume=/opt:/usr/src/app my_image
puede pero no es necesario especificar el punto de montaje (/opt) en la máquina host. Si no especifica el argumento volume volume, el punto de montaje se elegirá automáticamente
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-30 12:15:59
En resumen: No, su VOLUME
instrucción no es correcta.
VOLUME
de Dockerfile especifica uno o más volúmenes dados caminos 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 similar a un 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 refieren como "sin nombre" o "anónimo".
Tu ejemplo que usa un '.'character ni siquiera se ejecutará en mi máquina, no importa si hago del punto el primer o segundo argumento. Recibo este mensaje de error:
Docker: Respuesta de error del demonio: oci runtime error: container_linux.go: 265: iniciar el proceso de contenedor causó " process_linux.go: 368: container init caused \ " open/dev / ptmx: no such file or directory\"".
Sé que lo que se ha dicho hasta este punto es probablemente no es muy valioso para alguien que intenta entender VOLUME
y -v
y ciertamente no proporciona una solución para lo que intenta lograr. Así que, con suerte, los siguientes ejemplos arrojarán algo más de luz sobre estas cuestiones.
Minitutorial: Especificando volúmenes
Dado este Dockerfile:
FROM openjdk:8u131-jdk-alpine
VOLUME vol1 vol2
(Para el resultado de este minitutorial, no importa si especificamos vol1 vol2
o /vol1 /vol2
- no me preguntes por qué)
Construir se:
docker build -t my-openjdk
Ejecutar:
docker run --rm -it my-openjdk
Dentro del contenedor, ejecute ls
y notará que existen dos directorios; /vol1
y /vol2
.
Ejecutar el 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 dos puntos para brevedad):
DRIVER VOLUME NAME
local c984..e4fc
local f670..49f0
De vuelta en el container , execute 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 lol. Me tomó dos intentos porque primero probé el primer volumen de la lista, pero finalmente encontré mi archivo en el segundo volumen de la lista, 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: El _data
la carpeta también se conoce como un "punto de montaje".
Salga del contenedor y enumere los volúmenes en el host. Se han ido. Usamos el indicador --rm
al ejecutar 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 utilizando -v
:
docker run --rm -it -v /vol3 my-openjdk
Este agrega un tercer volumen y todo el sistema termina teniendo tres volúmenes sin nombre. El comando habría se estrelló si solo especificamos -v vol3
. El argumento debe ser un camino absoluto dentro de el contenedor. En el lado del host, el nuevo tercer volumen es anónimo y reside junto con los otros dos volúmenes en /var/lib/docker/volumes/
.
Se dijo anteriormente que el Dockerfile
no puede asignar a una ruta de host, lo que plantea un problema para nosotros al intentar traer archivos desde el host al contenedor durante el tiempo de ejecución. Una sintaxis -v
diferente resuelve este problema.
Imagina que tengo una subcarpeta en el directorio de mi proyecto ./src
que deseo sincronizar con /src
dentro del contenedor. Este comando hace el truco:
docker run -it -v $(pwd)/src:/src my-openjdk
Ambos lados del carácter :
esperan una ruta absoluta. 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 en $()
toma el comando entre paréntesis, lo ejecuta en una subcapa y devuelve el absoluto ruta a nuestro directorio de proyectos.
Poniendo todo junto, 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=)
Final observaciones
Soy bastante nuevo en Docker, y el mencionado "tutorial" refleja información que recopilé de un hackathon de línea de comandos de 3 días. Estoy casi avergonzado de no haber podido proporcionar enlaces a una documentación clara similar al inglés que respalde mis declaraciones, pero honestamente creo que esto se debe a la falta de documentación y no a un esfuerzo personal. Sé que los ejemplos funcionan como se anuncian usando mi configuración actual que es "Windows 10 - > Vagrant 2.0.0 - > Docker 17.09.0-ce".
El el tutorial no resuelve el problema "cómo especificamos la ruta del contenedor en el Dockerfile y dejamos que el comando run solo especifique la ruta del host". Puede que haya una manera, pero no la he encontrado.
Finalmente, tengo la sensación de que especificar VOLUME
en el Dockerfile no es solo raro, sino que probablemente sea una buena práctica no usar nunca VOLUME
. Por dos razones. La primera razón que ya hemos identificado: No podemos especificar la ruta de host - que es una buena cosa porque Dockerfiles debe ser muy agnóstico a los detalles de una máquina host. Pero la segunda razón es que la gente puede olvidar usar la opción --rm
al ejecutar el contenedor. Uno podría recordar quitar el recipiente pero olvidar quitar el volumen. Además, incluso con lo mejor de la memoria humana, podría ser una tarea desalentadora averiguar cuál de todos los volúmenes anónimos es seguro eliminar.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-05 15:23:22