Cómo lidiar con el almacenamiento persistente (por ejemplo, bases de datos) en Docker

993

¿Cómo manejan las personas el almacenamiento persistente de sus contenedores Docker?

Actualmente estoy usando este enfoque: compile la imagen, por ejemplo, para PostgreSQL, y luego inicie el contenedor con

docker run --volumes-from c0dbc34fd631 -d app_name/postgres

En mi humilde opinión, eso tiene el inconveniente de que nunca (por accidente) debo eliminar el contenedor "c0dbc34fd631".

Otra idea sería montar los volúmenes de host "-v" en el contenedor, sin embargo, el ID de usuario dentro del contenedor no coincide necesariamente con el ID de usuario del host, y luego los permisos pueden estar en mal estado.

Nota: en lugar de --volumes-from 'cryptic_id', también puede usar --volumes-from my-data-containerwhere my-data-containeres un nombre que asignó a un contenedor de solo datos, por ejemplo docker run --name my-data-container ...(consulte la respuesta aceptada)

juwalter
fuente
Lo siento, lo expresé mal, quería decir: todas mis instancias futuras de esa imagen dependen de ese contenedor. Si borro ese contenedor por accidente, estoy en problemas.
juwalter
@AntonStrogonoff - sí, error de fraseo - quise decir: necesito asegurarme de que nunca borraré ese (posiblemente) contenedor viejo, porque entonces la referencia del almacenamiento "persistente" también desaparecería
juwalter
debería ser --name. tienes-name
Shammel Lee

Respuestas:

986

Docker 1.9.0 y superior

Usar volumen API

docker volume create --name hello
docker run -d -v hello:/container/path/for/volume container_image my_command

Esto significa que el patrón de contenedor de solo datos debe abandonarse en favor de los nuevos volúmenes.

En realidad, la API de volumen es solo una mejor manera de lograr lo que era el patrón del contenedor de datos.

Si crea un contenedor con un -v volume_name:/container/fs/pathDocker, creará automáticamente un volumen con nombre para usted que puede:

  1. Estar en la lista a través de docker volume ls
  2. Ser identificado a través de docker volume inspect volume_name
  3. Copia de seguridad como un directorio normal
  4. Copia de seguridad como antes a través de una --volumes-fromconexión

La nueva API de volumen agrega un comando útil que le permite identificar volúmenes colgantes:

docker volume ls -f dangling=true

Y luego eliminarlo a través de su nombre:

docker volume rm <volume name>

Como @mpugach subraya en los comentarios, puedes deshacerte de todos los volúmenes colgantes con una buena frase:

docker volume rm $(docker volume ls -f dangling=true -q)
# Or using 1.13.x
docker volume prune

Docker 1.8.xy debajo

El enfoque que parece funcionar mejor para la producción es utilizar un contenedor de solo datos .

El contenedor de solo datos se ejecuta en una imagen básica y, en realidad, no hace nada excepto exponer un volumen de datos.

Luego puede ejecutar cualquier otro contenedor para tener acceso a los volúmenes del contenedor de datos:

docker run --volumes-from data-container some-other-container command-to-execute
  • Aquí puede obtener una buena imagen de cómo organizar los diferentes contenedores.
  • Aquí hay una buena idea de cómo funcionan los volúmenes.

En esta publicación de blog hay una buena descripción del llamado contenedor como patrón de volumen que aclara el punto principal de tener contenedores de datos solamente .

La documentación de Docker tiene ahora la descripción DEFINITIVA del contenedor como patrón de volumen / s .

El siguiente es el procedimiento de copia de seguridad / restauración para Docker 1.8.xy a continuación.

APOYO:

sudo docker run --rm --volumes-from DATA -v $(pwd):/backup busybox tar cvf /backup/backup.tar /data
  • --rm: retira el contenedor cuando sale
  • --volumes-from DATA: adjuntar a los volúmenes compartidos por el contenedor DATA
  • -v $ (pwd): / backup: bind monta el directorio actual en el contenedor; para escribir el archivo tar en
  • busybox: una imagen pequeña y simple, buena para un mantenimiento rápido
  • tar cvf /backup/backup.tar / data: crea un archivo tar sin comprimir de todos los archivos en el directorio / data

RESTAURAR:

# Create a new data container
$ sudo docker run -v /data -name DATA2 busybox true
# untar the backup files into the new container᾿s data volume
$ sudo docker run --rm --volumes-from DATA2 -v $(pwd):/backup busybox tar xvf /backup/backup.tar
data/
data/sven.txt
# Compare to the original container
$ sudo docker run --rm --volumes-from DATA -v `pwd`:/backup busybox ls /data
sven.txt

Aquí hay un buen artículo del excelente Brian Goff que explica por qué es bueno usar la misma imagen para un contenedor y un contenedor de datos.

tommasop
fuente
8
Es una herramienta diferente para una necesidad diferente. --volumes-fromle permite compartir espacio en disco, le --linkpermite compartir servicios.
tommasop
3
Hay otro proyecto en las obras específicamente destinado a este tipo de cosas, ¿tal vez agregarlo a esta respuesta como referencia para ver? github.com/ClusterHQ/flocker
Andre
99
¡Los contenedores de datos no tienen ningún significado y son realmente una mala idea! Contenedor solo significa algo cuando se está ejecutando un proceso, de lo contrario, es solo una pieza del sistema de archivos host. Puede montar un volumen con -v, que es la única y mejor opción. Usted tiene control sobre el sistema de archivos y el disco físico que usa.
Boynux
11
Sí, a partir de Docker 1.9, la creación de volúmenes con nombre con la API de volúmenes ( docker volume create --name mydata) es preferible a un contenedor de volumen de datos. La gente de Docker sugiere que los Contenedores de Volumen de Datos " ya no se consideran un patrón recomendado ", "los volúmenes con nombre deberían poder reemplazar los volúmenes de solo datos en la mayoría (si no todos) los casos " y " no hay razón para que pueda usar contenedores de solo datos ".
Quinn Commandado
8
@coding, estoy triste de que estés triste, en parte porque juzgas las respuestas con un retraso de 3 años y en parte porque la respuesta es sustancialmente correcta en toda su historia. Si tiene algún consejo, siéntase libre de comentar para que pueda integrar la respuesta y ayudar a las personas a no estar tristes
tommasop
75

En Docker versión v1.0 , el comando dado puede vincular el montaje de un archivo o directorio en la máquina host:

$ docker run -v /host:/container ...

El volumen anterior podría usarse como un almacenamiento persistente en el host que ejecuta Docker.

amitmula
fuente
3
Esta debe ser la respuesta recomendada ya que es mucho menos complejo que el enfoque de volumen-contenedor que tiene más votos en el momento
insitusec
2
Desearía que hubiera una bandera para especificar un mapeo host-uid: container-uid y host-gid: container-gid al usar este comando de montaje de volumen.
rampion
35

A partir de Docker Compose 1.6, ahora hay soporte mejorado para volúmenes de datos en Docker Compose. El siguiente archivo de composición creará una imagen de datos que persistirá entre los reinicios (o incluso la eliminación) de los contenedores principales:

Aquí está el anuncio del blog: Compose 1.6: Nuevo archivo Compose para definir redes y volúmenes

Aquí hay un ejemplo de archivo de composición:

version: "2"

services:
  db:
    restart: on-failure:10
    image: postgres:9.4
    volumes:
      - "db-data:/var/lib/postgresql/data"
  web:
    restart: on-failure:10
    build: .
    command: gunicorn mypythonapp.wsgi:application -b :8000 --reload
    volumes:
      - .:/code
    ports:
      - "8000:8000"
    links:
      - db

volumes:
  db-data:

Hasta donde puedo entender: Esto creará un contenedor de volumen de datos ( db_data) que persistirá entre reinicios.

Si ejecuta: docker volume lsdebería ver su volumen en la lista:

local               mypthonapp_db-data
...

Puede obtener más detalles sobre el volumen de datos:

docker volume inspect mypthonapp_db-data
[
  {
    "Name": "mypthonapp_db-data",
    "Driver": "local",
    "Mountpoint": "/mnt/sda1/var/lib/docker/volumes/mypthonapp_db-data/_data"
  }
]

Algunas pruebas:

# Start the containers
docker-compose up -d

# .. input some data into the database
docker-compose run --rm web python manage.py migrate
docker-compose run --rm web python manage.py createsuperuser
...

# Stop and remove the containers:
docker-compose stop
docker-compose rm -f

# Start it back up again
docker-compose up -d

# Verify the data is still there
...
(it is)

# Stop and remove with the -v (volumes) tag:

docker-compose stop
docker=compose rm -f -v

# Up again ..
docker-compose up -d

# Check the data is still there:
...
(it is).

Notas:

  • También puede especificar varios controladores en el volumes bloque. Por ejemplo, puede especificar el controlador Flocker para db_data:

    volumes:
      db-data:
        driver: flocker
    
  • A medida que mejoran la integración entre Docker Swarm y Docker Compose (y posiblemente comienzan a integrar Flocker en el ecosistema Docker (escuché un rumor de que Docker ha comprado Flocker), creo que este enfoque debería ser cada vez más poderoso.

Descargo de responsabilidad: este enfoque es prometedor, y lo estoy usando con éxito en un entorno de desarrollo. ¡Todavía estaría preocupado por usar esto en producción!

tostadas38coza
fuente
Flocker ha sido cerrado y no hay mucha actividad en el repositorio de Github
Krishna
17

En caso de que no esté claro en la actualización 5 de la respuesta seleccionada, a partir de Docker 1.9, puede crear volúmenes que puedan existir sin estar asociados con un contenedor específico, por lo que el patrón "contenedor de solo datos" queda obsoleto.

¿Ver contenedores de datos obsoletos con Docker 1.9.0? # 17798 .

Creo que los mantenedores de Docker se dieron cuenta de que el patrón del contenedor de solo datos era un poco un olor a diseño y decidieron hacer de los volúmenes una entidad separada que pueda existir sin un contenedor asociado.

ben_frankly
fuente
13

Si bien esto sigue siendo parte de Docker que necesita algo de trabajo , debe colocar el volumen en el Dockerfile con la instrucción VOLUME para que no necesite copiar los volúmenes de otro contenedor.

Eso hará que sus contenedores sean menos interdependientes y no tenga que preocuparse por la eliminación de un contenedor que afecte a otro.

Tim Dorr
fuente
El otro lado del argumento es que los contenedores "solo de datos" terminan siendo la referencia de último recurso para el volumen de datos (Docker destruye los volúmenes de datos una vez que se elimina el último contenedor que hace referencia a ese volumen docker rm)
WineSoaked
2
Esta guía oficial de Docker sugiere lo contrario: docs.docker.com/userguide/dockervolumes/… "Los volúmenes de datos están diseñados para persistir datos, independientemente del ciclo de vida del contenedor. Por lo tanto, Docker nunca eliminará automáticamente los volúmenes cuando retire un contenedor, ni lo hará. Volúmenes de "recolección de basura" a los que ya no hace referencia un contenedor ".
Alex
12

Cuando use Docker Compose , simplemente adjunte un volumen con nombre, por ejemplo:

version: '2'
services:
  db:
    image: mysql:5.6
    volumes:
      - db_data:/var/lib/mysql:rw
    environment:
      MYSQL_ROOT_PASSWORD: root
volumes:
  db_data:
Zar Pino
fuente
9

La respuesta de @ tommasop es buena y explica algunas de las mecánicas del uso de contenedores de solo datos. Pero como alguien que inicialmente pensó que los contenedores de datos eran tontos cuando uno podía enlazar, montar un volumen en el host (como lo sugieren varias otras respuestas), pero ahora se da cuenta de que, de hecho, los contenedores solo de datos son bastante limpios, puedo sugerir mi propio publicación de blog sobre este tema: ¿Por qué los contenedores de datos de Docker (volúmenes) son buenos?

Ver también: mi respuesta a la pregunta " ¿Cuál es la (mejor) forma de administrar los permisos para los volúmenes compartidos de Docker? " Para ver un ejemplo de cómo usar contenedores de datos para evitar problemas como permisos y mapeo uid / gid con el host.

Para abordar una de las preocupaciones originales del OP: que el contenedor de datos no debe eliminarse. Incluso si se elimina el contenedor de datos, los datos en sí no se perderán siempre que cualquier contenedor tenga una referencia a ese volumen, es decir, cualquier contenedor que haya montado el volumen a través de--volumes-from . Por lo tanto, a menos que se detengan y eliminen todos los contenedores relacionados (uno podría considerar esto como el equivalente de un accidente rm -fr /), los datos están seguros. Siempre puede volver a crear el contenedor de datos haciendo --volumes-fromcualquier contenedor que tenga una referencia a ese volumen.

¡Como siempre, haga copias de seguridad!

ACTUALIZACIÓN: Docker ahora tiene volúmenes que se pueden administrar independientemente de los contenedores, lo que hace que sea más fácil de administrar.

Raman
fuente
9

Existen varios niveles de administración de datos persistentes, según sus necesidades:

  • Almacénelo en su host
    • Usa la bandera -v host-path:container-path para conservar los datos del directorio del contenedor en un directorio del host.
    • Las copias de seguridad / restauraciones se realizan ejecutando un contenedor de copia de seguridad / restauración (como tutumcloud / dockup) montado en el mismo directorio.
  • Cree un contenedor de datos y monte sus volúmenes en el contenedor de su aplicación
    • Cree un contenedor que exporte un volumen de datos, use --volumes-from para montar esos datos en el contenedor de su aplicación.
    • Copia de seguridad / restauración igual que la solución anterior.
  • Use un complemento de volumen de Docker que respalde un servicio externo / de terceros
    • Los complementos de volumen de Docker permiten que su fuente de datos provenga de cualquier lugar: NFS, AWS (S3, EFS y EBS)
    • Dependiendo del complemento / servicio, puede adjuntar contenedores únicos o múltiples a un solo volumen.
    • Dependiendo del servicio, las copias de seguridad / restauraciones pueden ser automatizadas para usted.
    • Si bien esto puede ser engorroso de hacer manualmente, algunas soluciones de orquestación, como Rancher , lo tienen listo y fácil de usar.
    • Convoy es la solución más fácil para hacerlo manualmente.
Will Stern
fuente
8

Si desea mover sus volúmenes, también debe mirar Flocker .

Desde el archivo Léame:

Flocker es un administrador de volumen de datos y una herramienta de administración de clúster Docker de host múltiple. Con él, puede controlar sus datos utilizando las mismas herramientas que utiliza para sus aplicaciones sin estado aprovechando el poder de ZFS en Linux.

Esto significa que puede ejecutar sus bases de datos, colas y almacenes de valores clave en Docker y moverlos tan fácilmente como el resto de su aplicación.

Johann Romefort
fuente
1
Gracias Johann Trabajo en ClusterHQ y solo quería señalar que nos hemos movido más allá del almacenamiento basado en ZFS. Ahora puede usar Flocker con almacenamiento como Amazon EBS o Google Persistent Disk. Aquí hay una lista completa de opciones de almacenamiento: docs.clusterhq.com/en/latest/supported/…
ferrantim
1
Flocker ha cesado y no debe usarse portworx.com/…
jesugmz
5

Depende de su escenario (esto no es realmente adecuado para un entorno de producción), pero aquí hay una manera:

Crear un contenedor Docker de MySQL

Lo esencial es usar un directorio en su host para la persistencia de datos.

ben schwartz
fuente
66
Sin embargo, gracias Ben, uno de los problemas que puedo ver con este enfoque: el recurso del sistema de archivos (directorio, archivos) sería propiedad de un uid desde el contenedor docker / lxc (invitado), uno que posiblemente podría chocar con un uid en el host ...
juwalter
1
Creo que es bastante seguro, ya que se ejecuta desde la raíz, pero estoy de acuerdo en que es un hackeo, adecuado para las pruebas de integración efímera / dev local en el mejor de los casos. Esta es definitivamente un área que me gustaría ver surgir más patrones / pensamiento. Debería consultar / publicar esta pregunta en el grupo de docker-dev google
ben schwartz
Ben, gracias por esta solución! Sin embargo, no lo llamaría un truco, parece mucho más confiable que el contenedor como volumen . ¿Ve algún inconveniente en caso de que los datos se utilicen únicamente desde el contenedor? (UID no importa en este caso)
johndodo
0

Mi solución es usar el nuevo docker cp , que ahora puede copiar datos de los contenedores, sin importar si se está ejecutando o no, y compartir un volumen de host en la misma ubicación exacta donde la aplicación de base de datos está creando sus archivos de base de datos dentro del contenedor . Esta solución doble funciona sin un contenedor de solo datos, directamente desde el contenedor de la base de datos original.

Entonces, mi script de inicio systemd está tomando el trabajo de hacer una copia de seguridad de la base de datos en un archivo en el host. Coloqué una marca de tiempo en el nombre del archivo para nunca reescribir un archivo.

Lo está haciendo en ExecStartPre:

ExecStartPre=-/usr/bin/docker cp lanti-debian-mariadb:/var/lib/mysql /home/core/sql
ExecStartPre=-/bin/bash -c '/usr/bin/tar -zcvf /home/core/sql/sqlbackup_$$(date +%%Y-%%m-%%d_%%H-%%M-%%S)_ExecStartPre.tar.gz /home/core/sql/mysql --remove-files'

Y también está haciendo lo mismo en ExecStopPost:

ExecStopPost=-/usr/bin/docker cp lanti-debian-mariadb:/var/lib/mysql /home/core/sql
ExecStopPost=-/bin/bash -c 'tar -zcvf /home/core/sql/sqlbackup_$$(date +%%Y-%%m-%%d_%%H-%%M-%%S)_ExecStopPost.tar.gz /home/core/sql/mysql --remove-files'

Además, expuse una carpeta del host como volumen a la misma ubicación exacta donde se almacena la base de datos:

mariadb:
  build: ./mariadb
  volumes:
    - $HOME/server/mysql/:/var/lib/mysql/:rw

Funciona muy bien en mi VM (estoy construyendo una pila LEMP para mí): https://github.com/DJviolin/LEMP

Pero no sé si es una solución "a prueba de balas" cuando su vida realmente depende de ello (por ejemplo, una tienda web con transacciones en cualquier milisegundo posible).

A los 20 minutos y 20 segundos de este video oficial de Docker, el presentador hace lo mismo con la base de datos:

Comenzando con Docker

"Para la base de datos tenemos un volumen, por lo que podemos asegurarnos de que, a medida que la base de datos sube y baja, no perdemos datos cuando el contenedor de la base de datos se detiene".

Lanti
fuente
¿Qué quieres decir con "... usa ..." ? ¿Y "... transacciones en cualquier milisegundo posible" ?
Peter Mortensen
0

Utilice el reclamo de volumen persistente (PVC) de Kubernetes, que es una herramienta de programación y administración de contenedores Docker:

Volúmenes persistentes

Las ventajas de usar Kubernetes para este propósito son que:

  • Puede usar cualquier almacenamiento como NFS u otro almacenamiento e incluso cuando el nodo está inactivo, el almacenamiento no necesita serlo.
  • Además, los datos en dichos volúmenes pueden configurarse para ser retenidos incluso después de que el contenedor mismo sea destruido, de modo que pueda ser recuperado, si es necesario, por otro contenedor.
Santanu Dey
fuente