Comment gérer le stockage persistant (par exemple, les bases de données) dans Docker

993

Comment les utilisateurs gèrent-ils le stockage persistant de vos conteneurs Docker?

J'utilise actuellement cette approche: construire l'image, par exemple pour PostgreSQL, puis démarrer le conteneur avec

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

À mon humble avis, cela a l'inconvénient, que je ne dois jamais (par accident) supprimer le conteneur "c0dbc34fd631".

Une autre idée serait de monter les volumes d'hôte "-v" dans le conteneur, cependant, l' ID utilisateur dans le conteneur ne correspond pas nécessairement à l' ID utilisateur de l'hôte, puis les autorisations peuvent être gâchées.

Remarque: Au lieu de --volumes-from 'cryptic_id'vous pouvez également utiliser --volumes-from my-data-containermy-data-containerest un nom que vous avez attribué à un conteneur de données uniquement, par exemple docker run --name my-data-container ...(voir la réponse acceptée)

juwalter
la source
Désolé, j'ai mal formulé cela, je voulais dire: toutes mes futures instances de cette image dépendent de ce conteneur. Si je supprime ce conteneur par accident, j'ai des ennuis.
juwalter
@AntonStrogonoff - oui, erreur de phrasé - je voulais dire: je dois m'assurer que je ne supprimerai jamais ce (peut-être) ancien conteneur, car alors la référence au stockage "persistant" serait également disparue
juwalter
ça devrait l'être --name. vous avez-name
Shammel Lee

Réponses:

986

Docker 1.9.0 et supérieur

Utiliser l' API de volume

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

Cela signifie que le modèle de conteneur de données uniquement doit être abandonné au profit des nouveaux volumes.

En fait, l'API de volume n'est qu'un meilleur moyen de réaliser ce qui était le modèle de conteneur de données.

Si vous créez un conteneur avec un -v volume_name:/container/fs/pathDocker créera automatiquement un volume nommé pour vous qui peut:

  1. Être répertorié via le docker volume ls
  2. Être identifié par le docker volume inspect volume_name
  3. Sauvegardé en tant que répertoire normal
  4. Sauvegardé comme auparavant via une --volumes-fromconnexion

La nouvelle API de volume ajoute une commande utile qui vous permet d'identifier les volumes pendants:

docker volume ls -f dangling=true

Et puis supprimez-le par son nom:

docker volume rm <volume name>

Comme le souligne @mpugach dans les commentaires, vous pouvez vous débarrasser de tous les volumes suspendus avec un joli one-liner:

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

Docker 1.8.x et inférieur

L'approche qui semble fonctionner le mieux pour la production consiste à utiliser un conteneur de données uniquement .

Le conteneur de données uniquement est exécuté sur une image barebones et ne fait rien, sauf exposer un volume de données.

Ensuite, vous pouvez exécuter n'importe quel autre conteneur pour avoir accès aux volumes du conteneur de données:

docker run --volumes-from data-container some-other-container command-to-execute
  • Ici, vous pouvez obtenir une bonne image de la façon d'organiser les différents conteneurs.
  • Voici un bon aperçu du fonctionnement des volumes.

Dans ce billet de blog, il y a une bonne description du soi-disant conteneur en tant que modèle de volume qui clarifie le point principal d'avoir uniquement des conteneurs de données .

La documentation Docker a maintenant la description DEFINITIVE du conteneur en tant que modèle de volume / s .

Voici la procédure de sauvegarde / restauration pour Docker 1.8.x et versions antérieures.

SAUVEGARDE:

sudo docker run --rm --volumes-from DATA -v $(pwd):/backup busybox tar cvf /backup/backup.tar /data
  • --rm: retirer le conteneur à sa sortie
  • --volumes-from DATA: attache aux volumes partagés par le conteneur DATA
  • -v $ (pwd): / backup: bind monte le répertoire courant dans le conteneur; pour écrire le fichier tar dans
  • busybox: une petite image plus simple - bonne pour une maintenance rapide
  • tar cvf /backup/backup.tar / data: crée un fichier tar non compressé de tous les fichiers du répertoire / data

RESTAURER:

# 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

Voici un bel article de l'excellent Brian Goff expliquant pourquoi il est bon d'utiliser la même image pour un conteneur et un conteneur de données.

tommasop
la source
8
C'est un outil différent pour un besoin différent. --volumes-fromvous permet de partager l'espace disque --linkvous permet de partager des services.
tommasop
3
Il y a un autre projet en cours spécifiquement destiné à ce genre de chose, peut-être l'ajouter à cette réponse comme référence à regarder? github.com/ClusterHQ/flocker
Andre
9
Les conteneurs de données n'ont aucune signification et sont vraiment une mauvaise idée! Conteneur signifie seulement quelque chose quand un processus est en cours d'exécution, sinon c'est juste un morceau de système de fichiers hôte. Vous pouvez simplement monter un volume avec -v qui est la seule et meilleure option. Vous contrôlez le système de fichiers et le disque physique que vous utilisez.
Boynux
11
Oui, à partir de Docker 1.9, la création de volumes nommés avec l'API Volumes ( docker volume create --name mydata) est préférée à un conteneur de volume de données. Les gens de Docker eux-mêmes suggèrent que les conteneurs de volumes de données « ne sont plus considérés comme un modèle recommandé », «les volumes nommés devraient être en mesure de remplacer les volumes de données uniquement dans la plupart (sinon tous) les cas » et « aucune raison que je vois d'utiliser conteneurs de données uniquement . "
Quinn Comendant
8
@coding, je suis triste, vous êtes triste, en partie parce que vous jugez les réponses avec un retard de 3 ans et en partie parce que la réponse est sensiblement la bonne dans toute son histoire. Si vous avez des conseils, n'hésitez pas à commenter afin que je puisse intégrer la réponse et aider les gens à ne pas être tristes
tommasop
75

Dans Docker version v1.0 , la liaison d'un montage d'un fichier ou d'un répertoire sur la machine hôte peut être effectuée par la commande donnée:

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

Le volume ci-dessus peut être utilisé comme stockage persistant sur l'hôte exécutant Docker.

amitmula
la source
3
Cela devrait être la réponse recommandée car elle est beaucoup moins complexe que l'approche volume-conteneur qui a plus de votes pour le moment
insitusec
2
Je souhaite qu'il y ait un indicateur pour spécifier un mappage host-uid: container-uid et host-gid: container-gid lors de l'utilisation de cette commande de montage de volume.
rampion
35

Depuis Docker Compose 1.6, la prise en charge des volumes de données dans Docker Compose est désormais améliorée. Le fichier de composition suivant créera une image de données qui persistera entre les redémarrages (ou même la suppression) des conteneurs parents:

Voici l'annonce du blog: Compose 1.6: Nouveau fichier Compose pour définir les réseaux et les volumes

Voici un exemple de fichier de composition:

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:

Pour autant que je puisse comprendre: cela va créer un conteneur de volume de données (db_data ) qui persistera entre les redémarrages.

Si vous exécutez: docker volume lsvous devriez voir votre volume répertorié:

local               mypthonapp_db-data
...

Vous pouvez obtenir plus de détails sur le volume de données:

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

Quelques tests:

# 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).

Remarques:

  • Vous pouvez également spécifier différents pilotes dans le volumes bloc. Par exemple, vous pouvez spécifier le pilote Flocker pour db_data:

    volumes:
      db-data:
        driver: flocker
    
  • À mesure qu'ils améliorent l'intégration entre Docker Swarm et Docker Compose (et commencent éventuellement à intégrer Flocker dans l'écosystème Docker (j'ai entendu une rumeur selon laquelle Docker a acheté Flocker), je pense que cette approche devrait devenir de plus en plus puissante.

Avertissement: Cette approche est prometteuse et je l'utilise avec succès dans un environnement de développement. Je serais inquiet de l'utiliser pour le moment!

toast38coza
la source
Flocker a été fermé et il n'y a pas beaucoup d'activité sur le repo github
Krishna
17

Dans le cas où il ne ressort pas clairement de la mise à jour 5 de la réponse sélectionnée, à partir de Docker 1.9, vous pouvez créer des volumes qui peuvent exister sans être associés à un conteneur spécifique, rendant ainsi le modèle de "conteneur de données uniquement" obsolète.

Voir Conteneurs de données uniquement obsolètes avec Docker 1.9.0? # 17798 .

Je pense que les responsables de Docker ont réalisé que le modèle de conteneur de données uniquement était un peu une odeur de conception et ont décidé de faire des volumes une entité distincte qui peut exister sans conteneur associé.

ben_frankly
la source
13

Bien que ce soit encore une partie de Docker qui nécessite un peu de travail , vous devez mettre le volume dans le Dockerfile avec l'instruction VOLUME afin que vous n'ayez pas besoin de copier les volumes d'un autre conteneur.

Cela rendra vos conteneurs moins interdépendants et vous n'aurez pas à vous soucier de la suppression d'un conteneur affectant un autre.

Tim Dorr
la source
L'argument inverse est que les conteneurs "données uniquement" finissent par être la référence de dernier recours au volume de données (Docker détruit les volumes de données une fois que le dernier conteneur référençant ce volume est supprimé docker rm)
WineSoaked
2
Ce guide officiel de Docker suggère le contraire: docs.docker.com/userguide/dockervolumes/… "Les volumes de données sont conçus pour conserver les données, indépendamment du cycle de vie du conteneur. Docker ne supprime donc jamais automatiquement les volumes lorsque vous supprimez un conteneur, et il ne le fera pas non plus. "Garbage collect" volumes qui ne sont plus référencés par un conteneur. "
Alex
12

Lorsque vous utilisez Docker Compose , attachez simplement un volume nommé, par exemple:

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

La réponse de @ tommasop est bonne et explique certains des mécanismes d'utilisation des conteneurs de données uniquement. Mais comme quelqu'un qui pensait initialement que les conteneurs de données étaient idiots quand on pouvait simplement lier monter un volume à l'hôte (comme suggéré par plusieurs autres réponses), mais se rend maintenant compte qu'en fait, les conteneurs de données uniquement sont assez soignés, je peux suggérer le mien article de blog sur ce sujet: Pourquoi les conteneurs de données Docker (volumes!) sont bons

Voir aussi: ma réponse à la question " Quelle est la (meilleure) façon de gérer les autorisations pour les volumes partagés Docker? " Pour un exemple d'utilisation des conteneurs de données pour éviter des problèmes tels que les autorisations et le mappage uid / gid avec l'hôte.

Pour répondre à l'une des préoccupations originales du PO: le conteneur de données ne doit pas être supprimé. Même si le conteneur de données est supprimé, les données elles-mêmes ne seront pas perdues tant qu'un conteneur aura une référence à ce volume, c'est-à-dire tout conteneur qui a monté le volume via --volumes-from. Donc, à moins que tous les conteneurs associés ne soient arrêtés et supprimés (on pourrait considérer cela comme l'équivalent d'un accidentel rm -fr /), les données sont en sécurité. Vous pouvez toujours recréer le conteneur de données en faisant --volumes-fromn'importe quel conteneur qui a une référence à ce volume.

Comme toujours, faites des sauvegardes!

MISE À JOUR: Docker dispose désormais de volumes qui peuvent être gérés indépendamment des conteneurs, ce qui facilite encore la gestion.

Raman
la source
9

Il existe plusieurs niveaux de gestion des données persistantes, selon vos besoins:

  • Stockez-le sur votre hôte
    • Utilisez le drapeau -v host-path:container-path pour conserver les données du répertoire du conteneur dans un répertoire hôte.
    • Les sauvegardes / restaurations se produisent en exécutant un conteneur de sauvegarde / restauration (tel que tutumcloud / dockup) monté dans le même répertoire.
  • Créez un conteneur de données et montez ses volumes sur votre conteneur d'application
    • Créez un conteneur qui exporte un volume de données, utilisez --volumes-from pour monter ces données dans votre conteneur d'application.
    • Sauvegarde / restauration identique à la solution ci-dessus.
  • Utilisez un plug-in de volume Docker qui sauvegarde un service externe / tiers
    • Les plugins de volume Docker permettent à votre source de données de venir de n'importe où - NFS, AWS (S3, EFS et EBS)
    • Selon le plugin / service, vous pouvez attacher un ou plusieurs conteneurs à un même volume.
    • Selon le service, les sauvegardes / restaurations peuvent être automatisées pour vous.
    • Bien que cela puisse être lourd à faire manuellement, certaines solutions d'orchestration - telles que Rancher - l'ont intégré et simple à utiliser.
    • Convoy est la solution la plus simple pour le faire manuellement.
Will Stern
la source
8

Si vous souhaitez déplacer vos volumes, vous devriez également regarder Flocker .

Du README:

Flocker est un gestionnaire de volume de données et un outil de gestion de cluster Docker multi-hôtes. Avec lui, vous pouvez contrôler vos données en utilisant les mêmes outils que vous utilisez pour vos applications sans état en exploitant la puissance de ZFS sur Linux.

Cela signifie que vous pouvez exécuter vos bases de données, vos files d'attente et vos magasins de valeurs-clés dans Docker et les déplacer aussi facilement que le reste de votre application.

Johann Romefort
la source
1
Merci Johann. Je travaille chez ClusterHQ et je voulais juste noter que nous sommes allés au-delà du stockage basé sur ZFS. Vous pouvez désormais utiliser Flocker avec un stockage comme Amazon EBS ou Google Persistent Disk. Voici une liste complète des options de stockage: docs.clusterhq.com/en/latest/supported/…
ferrantim
1
Flocker a cessé et ne doit pas être utilisé portworx.com/…
jesugmz
5

Cela dépend de votre scénario (ce n'est pas vraiment adapté à un environnement de production), mais voici une façon:

Création d'un conteneur MySQL Docker

L'essentiel est d'utiliser un répertoire sur votre hôte pour la persistance des données.

ben schwartz
la source
6
Merci Ben, cependant - l'un des problèmes que je peux voir avec cette approche: la ressource du système de fichiers (répertoire, fichiers) appartiendrait à un uid à l'intérieur du conteneur docker / lxc (invité) - qui pourrait éventuellement entrer en collision avec un uid sur l'hôte ...
juwalter
1
Je pense que vous êtes assez sûr car il est géré par root, mais je conviens que c'est un hack - adapté au mieux aux tests d'intégration de développement / éphémère local. C'est certainement un domaine que j'aimerais voir émerger davantage de schémas / réflexions. Vous devriez vérifier / poster cette question au groupe google docker-dev
ben schwartz
Ben, merci pour cette solution! Je ne dirais pas que c'est un hack, il semble beaucoup plus fiable que le conteneur en tant que volume . Voyez-vous des inconvénients dans le cas où les données sont utilisées uniquement à partir du conteneur? (L'UID n'a pas d'importance dans ce cas)
johndodo
1

J'utilise simplement un répertoire prédéfini sur l'hôte pour conserver les données pour PostgreSQL. De cette façon, il est possible de migrer facilement des installations PostgreSQL existantes vers des conteneurs Docker: https://crondev.com/persistent-postgresql-inside-docker/

Alen Komljen
la source
0

Ma solution consiste à utiliser le nouveau docker cp , qui est maintenant capable de copier des données à partir de conteneurs, peu importe s'il est en cours d'exécution ou non et de partager un volume hôte au même emplacement exact où l'application de base de données crée ses fichiers de base de données à l'intérieur du conteneur . Cette double solution fonctionne sans conteneur de données uniquement, directement à partir du conteneur de base de données d'origine.

Mon script d'initialisation systemd prend donc le travail de sauvegarde de la base de données dans une archive sur l'hôte. J'ai placé un horodatage dans le nom de fichier pour ne jamais réécrire un fichier.

Il le fait sur l'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'

Et cela fait la même chose sur ExecStopPost aussi:

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'

De plus, j'ai exposé un dossier de l'hôte en tant que volume au même emplacement exact où la base de données est stockée:

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

Cela fonctionne très bien sur ma machine virtuelle (je construis une pile LEMP pour moi): https://github.com/DJviolin/LEMP

Mais je ne sais tout simplement pas s'il s'agit d'une solution "à l'épreuve des balles" alors que votre vie en dépend réellement (par exemple, une boutique en ligne avec des transactions en quelques millisecondes possibles)?

À 20 min 20 secondes de cette vidéo officielle de Docker, le présentateur fait la même chose avec la base de données:

Premiers pas avec Docker

"Pour la base de données, nous avons un volume, donc nous pouvons nous assurer que, lorsque la base de données monte et descend, nous ne perdons pas de données, lorsque le conteneur de base de données s'est arrêté."

Lanti
la source
Que voulez-vous dire par "... utiliser ..." ? Et "... les transactions dans toutes les millisecondes possibles" ?
Peter Mortensen
0

Utilisez la revendication de volume persistante (PVC) de Kubernetes, qui est un outil de gestion et de planification de conteneurs Docker:

Volumes persistants

Les avantages de l'utilisation de Kubernetes à cette fin sont les suivants:

  • Vous pouvez utiliser n'importe quel stockage comme NFS ou tout autre stockage et même lorsque le nœud est en panne, le stockage n'a pas besoin d'être.
  • De plus, les données de ces volumes peuvent être configurées pour être conservées même après la destruction du conteneur lui-même - afin de pouvoir être récupérées, si nécessaire, par un autre conteneur.
Santanu Dey
la source