Volúmenes y persistencia de datos
1. El problema de los datos en los contenedores #
Los contenedores Docker están pensados para poder:
- Crearse.
- Detenerse.
- Reiniciarse.
- Eliminarse.
- Volverse a crear.
Esto plantea un problema importante:
¿Qué ocurre con los datos cuando eliminamos un contenedor?
Si guardamos información solamente dentro del sistema de archivos del contenedor, esa información está ligada a la vida de ese contenedor.
Por ejemplo:
1CONTENEDOR MYSQL 2 │ 3 ├── bases de datos 4 ├── tablas 5 └── registros
Si eliminamos el contenedor, podríamos perder esa información.
Para evitarlo Docker dispone de los volúmenes.
2. ¿Qué es un volumen? #
Un volumen permite guardar información de forma independiente a la vida del contenedor.
Podemos representarlo así:
1CONTENEDOR 2 │ 3 │ 4 ↓ 5 VOLUMEN 6 │ 7 ↓ 8 DATOS
Aunque el contenedor desaparezca, el volumen puede continuar existiendo.
3. ¿Para qué sirven los volúmenes? #
Los volúmenes permiten:
- Mantener datos aunque eliminemos un contenedor.
- Separar los datos del contenedor.
- Compartir información entre contenedores.
- Montar carpetas del host dentro de un contenedor.
- Facilitar copias de seguridad.
- Mantener bases de datos.
- Mantener archivos de una aplicación.
4. Contenedor sin volumen #
Imaginemos:
1CONTENEDOR 2 │ 3 └── datos.txt
Si eliminamos:
1docker rm mi-contenedor
el contenedor desaparece junto con su sistema de archivos interno.
5. Contenedor con volumen #
Con un volumen podemos tener:
1CONTENEDOR 2 │ 3 ↓ 4 VOLUMEN 5 │ 6 └── datos.txt
Si eliminamos el contenedor:
1CONTENEDOR ✗
el volumen puede seguir existiendo:
1VOLUMEN 2 │ 3 └── datos.txt
Posteriormente podremos utilizar esos datos desde otro contenedor.
6. La opción -v #
Para trabajar con volúmenes utilizaremos principalmente:
1-v
La estructura general es:
1docker run -v <origen>:<destino> <imagen>
Donde:
1origen
es la ubicación de los datos.
Y:
1destino
es el directorio que veremos dentro del contenedor.
7. Primer ejemplo con Debian #
Vamos a utilizar Debian.
Primero descargamos la imagen si todavía no la tenemos:
1docker pull debian
Comprobamos:
1docker images
8. Crear un contenedor con volumen #
Podemos arrancar Debian y crear un punto de almacenamiento asociado:
1docker run -it --name midebian -v /mivolumen:/datos debian bash
Analicemos el comando.
9. Explicación del comando #
Tenemos:
1docker run
Crea un nuevo contenedor.
1-it
Permite trabajar de forma interactiva con una terminal.
1--name midebian
Pone al contenedor el nombre:
1midebian
1-v /mivolumen:/datos
Relaciona dos ubicaciones:
1/mivolumen 2 ↓ 3 /datos
Dentro del contenedor trabajaremos con:
1/datos
1debian
es la imagen utilizada.
1bash
abre una shell.
10. Trabajar con el volumen #
Una vez dentro del contenedor podemos acceder al directorio:
1cd /datos
Creamos un fichero:
1touch hola.txt
Comprobamos:
1ls
Deberíamos obtener:
1hola.txt
11. Crear más información #
Podemos crear:
1echo "Curso Docker" > curso.txt
Comprobamos:
1ls
y:
1cat curso.txt
Obtendremos:
1Curso Docker
12. Salir del contenedor #
Podemos salir:
1exit
El contenedor quedará detenido.
Comprobamos:
1docker ps -a
13. Los datos siguen existiendo #
Podemos volver a arrancar:
1docker start midebian
Y conectarnos:
1docker attach midebian
Accedemos:
1cd /datos
Comprobamos:
1ls
Los archivos deberían seguir estando disponibles.
14. Volúmenes gestionados por Docker #
Docker dispone de comandos específicos para gestionar volúmenes.
Para verlos utilizamos:
1docker volume ls
Este comando muestra los volúmenes disponibles.
Podemos obtener una salida similar a:
1DRIVER VOLUME NAME 2local volumen1 3local volumen2
15. Consultar información de un volumen #
Podemos utilizar:
1docker volume inspect <volumen>
Por ejemplo:
1docker volume inspect volumen1
Docker mostrará información como:
- Nombre.
- Driver.
- Punto de montaje.
- Opciones.
- Ubicación utilizada por Docker.
16. Crear un volumen explícitamente #
También podemos crear primero el volumen.
Utilizamos:
1docker volume create mivolumen
Después comprobamos:
1docker volume ls
Debería aparecer:
1mivolumen
17. Utilizar un volumen con nombre #
Una forma muy cómoda de trabajar es utilizar:
1docker run -it --name midebian -v mivolumen:/datos debian bash
Aquí:
1mivolumen
es un volumen gestionado por Docker.
Y:
1/datos
es el directorio dentro del contenedor.
18. Crear un fichero dentro del volumen #
Dentro del contenedor:
1cd /datos
Creamos:
1touch alumno.txt
Después:
1ls
Obtendremos:
1alumno.txt
19. Eliminar el contenedor #
Salimos:
1exit
Comprobamos:
1docker ps -a
Eliminamos:
1docker rm midebian
El contenedor desaparecerá.
Pero podemos comprobar:
1docker volume ls
El volumen:
1mivolumen
continúa existiendo.
20. Reutilizar el volumen #
Creamos un nuevo contenedor:
1docker run -it --name debian2 -v mivolumen:/datos debian bash
Dentro:
1cd /datos
Ejecutamos:
1ls
Deberíamos encontrar:
1alumno.txt
Esto demuestra que el volumen tiene una vida independiente del contenedor.
21. Esquema #
Inicialmente:
1CONTENEDOR midebian 2 │ 3 ↓ 4 mivolumen 5 │ 6 └── alumno.txt
Eliminamos:
1CONTENEDOR midebian ✗
Pero permanece:
1mivolumen 2 │ 3 └── alumno.txt
Creamos otro contenedor:
1CONTENEDOR debian2 2 │ 3 ↓ 4 mivolumen 5 │ 6 └── alumno.txt
22. Eliminar un volumen #
Para eliminar un volumen utilizamos:
1docker volume rm <nombre_volumen>
Por ejemplo:
1docker volume rm mivolumen
23. El volumen no debe estar en uso #
Antes de eliminarlo debemos asegurarnos de que no esté asociado a un contenedor que lo esté utilizando.
Por ejemplo, si:
1debian2
está utilizando:
1mivolumen
primero debemos eliminar el contenedor:
1docker stop debian2
1docker rm debian2
Después:
1docker volume rm mivolumen
24. Comprobar los volúmenes #
Después ejecutamos:
1docker volume ls
El volumen eliminado ya no debería aparecer.
25. Montar una carpeta del ordenador #
Otra posibilidad muy interesante es montar directamente un directorio de nuestro ordenador dentro del contenedor.
Esto permite tener:
1CARPETA DEL HOST 2 │ 3 ↓ 4CARPETA DEL CONTENEDOR
Por ejemplo:
1C:\servidor 2 ↓ 3/datos
26. Bind mount #
Cuando asociamos directamente una carpeta concreta del ordenador con una carpeta del contenedor estamos realizando un montaje de directorio.
Por ejemplo:
1docker run -it -v C:/docker/datos:/datos debian bash
Esto significa:
1WINDOWS 2 3C:/docker/datos 4 │ 5 ↓ 6CONTENEDOR 7 8/datos
27. Ejemplo en Windows #
Creamos en nuestro ordenador:
1C:\docker\datos
Después ejecutamos:
1docker run -it --name midebian -v C:/docker/datos:/datos debian bash
Dentro del contenedor accedemos:
1cd /datos
Creamos:
1touch prueba.txt
Salimos:
1exit
Ahora podemos abrir:
1C:\docker\datos
en Windows.
Deberíamos encontrar:
1prueba.txt
28. Los cambios funcionan en ambos sentidos #
El montaje conecta ambos directorios.
Si desde el contenedor creamos:
1touch /datos/docker.txt
aparecerá en:
1C:\docker\datos
Si desde Windows creamos:
1alumno.txt
dentro de:
1C:\docker\datos
el contenedor también podrá verlo:
1ls /datos
29. Ejemplo en Linux o macOS #
Podríamos tener:
1/Users/usuario/docker/datos
Y montar:
1docker run -it --name midebian -v /Users/usuario/docker/datos:/datos debian bash
Dentro:
1cd /datos
Todo lo que almacenemos ahí estará físicamente accesible desde la carpeta del equipo anfitrión.
30. Diferencia entre volumen y carpeta del host #
Podemos trabajar principalmente de dos formas.
Volumen gestionado por Docker #
1docker volume create datos
Después:
1docker run -v datos:/datos debian
Docker administra dónde se guarda físicamente la información.
Carpeta concreta del host #
1docker run -v C:/docker/datos:/datos debian
Nosotros elegimos exactamente dónde se encuentran los archivos.
31. ¿Cuándo utilizar cada uno? #
Volúmenes Docker #
Son útiles cuando:
- Docker debe gestionar el almacenamiento.
- Queremos persistencia.
- Queremos compartir datos entre contenedores.
- No necesitamos acceder constantemente a los archivos desde el host.
Carpeta del host #
Resulta útil cuando:
- Queremos editar archivos desde nuestro ordenador.
- Estamos desarrollando una aplicación.
- Queremos montar una página web.
- Queremos compartir código con el contenedor.
32. Ejemplo con Nginx #
Supongamos que tenemos una carpeta:
1C:\servidor_nginx
Dentro creamos:
1index.html
Podemos ejecutar:
1docker run --name miserver -d -p 83:80 -v C:/servidor_nginx:/usr/share/nginx/html nginx
Esto monta:
1C:/servidor_nginx 2 ↓ 3/usr/share/nginx/html
La segunda ruta es el directorio donde Nginx sirve normalmente las páginas web.
33. Probar el servidor #
Accedemos desde el navegador:
1http://localhost:83
Nginx mostrará el:
1index.html
que tenemos en:
1C:\servidor_nginx
34. Modificar la web sin entrar en el contenedor #
Esta es una de las principales ventajas del montaje.
Podemos editar en Windows:
1C:\servidor_nginx\index.html
Guardamos.
Refrescamos:
1http://localhost:83
Y podremos ver directamente los cambios.
No es necesario:
- Entrar al contenedor.
- Instalar un editor.
- Copiar el fichero manualmente.
35. Ejemplo relacionado con lo visto anteriormente #
Podemos utilizar:
1docker run --name miserver3 -dp 83:80 -v C:/servidor_nginx:/usr/share/nginx/html nginx
En este comando tenemos:
1--name miserver3
Nombre del contenedor.
1-d
Ejecución en segundo plano.
1-p 83:80
Puerto 83 del host conectado al puerto 80 del contenedor.
1-v C:/servidor_nginx:/usr/share/nginx/html
Montaje de la carpeta web.
1nginx
Imagen utilizada.
36. Montaje de solo lectura #
También podemos montar un directorio como solo lectura.
Utilizamos:
1:ro
Por ejemplo:
1docker run -d \ 2 -p 80:80 \ 3 -v C:/servidor_nginx:/usr/share/nginx/html:ro \ 4 nginx
ro significa:
1read only
El contenedor podrá leer los archivos, pero no modificarlos desde ese montaje.
37. Ejemplo de solo lectura #
Tenemos:
1HOST 2C:/servidor_nginx 3 │ 4 │ lectura 5 ↓ 6CONTENEDOR 7/usr/share/nginx/html
Esto puede resultar útil para evitar modificaciones accidentales de los archivos desde el contenedor.
38. Ejemplo con MySQL #
Los volúmenes son especialmente importantes en bases de datos.
Sin persistencia tendríamos:
1MYSQL 2 │ 3 └── datos dentro del contenedor
Si eliminamos el contenedor podríamos perder esos datos.
Una solución es utilizar un volumen.
Primero creamos:
1docker volume create mysql-datos
Después:
1docker run -d \ 2 --name mysql \ 3 -p 3306:3306 \ 4 -e MYSQL_ROOT_PASSWORD=Ad1234 \ 5 -v mysql-datos:/var/lib/mysql \ 6 mysql
39. Directorio de datos de MySQL #
En este ejemplo montamos:
1mysql-datos 2 ↓ 3/var/lib/mysql
De esta forma los datos de MySQL quedan asociados al volumen.
40. Probar la persistencia con MySQL #
Accedemos:
1docker exec -it mysql mysql -uroot -p
Creamos:
1CREATE DATABASE cebem;
Comprobamos:
1SHOW DATABASES;
Salimos:
1exit;
41. Eliminar el contenedor MySQL #
Detenemos:
1docker stop mysql
Eliminamos:
1docker rm mysql
Comprobamos:
1docker ps -a
El contenedor ya no existe.
42. El volumen continúa existiendo #
Ejecutamos:
1docker volume ls
Deberíamos seguir viendo:
1mysql-datos
43. Crear otro MySQL utilizando el mismo volumen #
Ejecutamos:
1docker run -d \ 2 --name mysql2 \ 3 -p 3306:3306 \ 4 -e MYSQL_ROOT_PASSWORD=Ad1234 \ 5 -v mysql-datos:/var/lib/mysql \ 6 mysql
Después:
1docker exec -it mysql2 mysql -uroot -p
Ejecutamos:
1SHOW DATABASES;
La base de datos:
1cebem
debería seguir disponible.
44. Compartir un volumen #
Un mismo volumen puede permitir compartir datos entre diferentes contenedores.
Por ejemplo:
1CONTENEDOR 1 2 │ 3 ↓ 4 VOLUMEN 5 ↑ 6 │ 7CONTENEDOR 2
Ambos pueden acceder a información almacenada en el mismo volumen, según cómo configuremos el montaje.