如何处理docker中的永久性存储(例如数据库)

人们如何处理docker集装箱的持久存储? 我目前正在使用这种方法:build立图像,例如Postgres,然后启动容器

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

恕我直言,这有缺点,我不能(无意)删除容器“c0dbc34fd631”。

另一个想法是将主机卷“-v”装载到容器中,但容器内的用户标识不一定与用户标识与主机相匹配,然后权限可能会混乱。

注意:除了--volumes-from 'cryptic_id'您还可以使用--volumes-from my-data-container ,其中my-data-container是您分配给数据专用容器的名称,例如docker run --name my-data-container ... (查看接受的答案)

Docker 1.9.0及以上版本

使用卷API

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

这意味着只有数据容器模式必须放弃,以支持新的卷。

实际上,volume API只是实现什么是数据容器模式的一个更好的方法。

如果使用-v volume_name:/container/fs/path创build容器,docker会自动为您创build一个指定的卷,可以:

  1. 通过docker volume ls
  2. 通过docker volume inspect volume_name识别
  3. 作为正常的目录备份
  4. 像以前一样通过--volumes-from连接--volumes-from

新卷api添加了一个有用的命令,可以让您识别悬挂卷:

 docker volume ls -f dangling=true 

然后通过它的名字删除它:

 docker volume rm <volume name> 

作为@mpugach在评论中强调,你可以摆脱所有的悬挂卷一个很好的衬垫:

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

Docker 1.8.x及以下版本

似乎最适合生产的方法是使用仅数据容器

只有数据容器运行在准系统映像上,实际上除了暴露数据卷外什么也不做。

然后,您可以运行任何其他容器以访问数据容器卷:

 docker run --volumes-from data-container some-other-container command-to-execute 
  • 在这里你可以很好的了解如何安排不同的容器
  • 这里有一个很好的见解如何卷工作

在这篇博客文章中,我们将所谓的容器作为容量模式进行了很好的描述,这个模式阐明了只有数据容器的要点。

现在,Docker文档已经将容器定义为volume / s模式。

以下是Docker 1.8.x及以下版本的备份/恢复过程

备份:

 sudo docker run --rm --volumes-from DATA -v $(pwd):/backup busybox tar cvf /backup/backup.tar /data 
  • –rm:退出时取出容器
  • – 来自DATA的卷:附加到由DATA容器共享的卷
  • -v $(pwd):/ backup:将当前目录绑定到容器中; 把tar文件写入
  • busybox:一个小而简单的图像 – 有利于快速维护
  • tar cvf /backup/backup.tar / data:为/ data目录下的所有文件创build一个未压缩的tar文件

恢复:

 # 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 

这里有一篇很好的文章,来自杰出的Brian Goff,解释了为什么在一个容器和一个数据容器中使用相同的图像。

Docker发行版v1.0中 ,通过给定的命令可以在主机上绑定文件或目录的挂载:

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

上面的卷可以用作运行docker的主机上的永久性存储。

从docker-compose 1.6开始,Docker Compose现在已经改进了对数据卷的支持。 下面的组合文件将创build一个数据镜像,它将在父容器重新启动(甚至删除)之间持续存在:

这里是博客公告: https : //blog.docker.com/2016/02/compose-1-6/

这是一个撰写文件的例子:

 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: 

据我所知:这将创build一个数据卷容器( db_data ),它将在重新启动之间持续。

如果运行: docker volume ls您应该看到列出的卷:

 local mypthonapp_db-data ... 

你可以得到更多关于数据量的细节:

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

一些testing:

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

笔记:

  • 您还可以在volumes块中指定各种驱动程序。 例如:你可以为db_data指定flocker驱动程序:

     volumes: db-data: driver: flocker 
  • 当他们改进Docker Swarm和Docker Compose之间的集成(并且可能开始将Flocker集成到Docker生态系统中(我听说Docker已经收购了Flocker的传言)时,我认为这种方法应该变得越来越强大。

免责声明:这种方法是有希望的,我在开发环境中成功地使用它。 我会担心在生产中使用它!

如果从所选答案的更新5中不清楚,从Docker 1.9开始,可以创build可以存在而不与特定容器关联的卷,从而使“仅数据容器”模式过时。

请参阅https://github.com/docker/docker/issues/17798

我认为Docker维护人员意识到只有数据的容器模式有一点点的devise气味,并且决定将卷创build为一个独立的实体,可以在没有关联的容器的情况下存在。

虽然这仍然是需要一些工作的docker的一部分,但您应该使用VOLUME指令将该卷放在Dockerfile中,这样就不需要从另一个容器复制卷。 这将使你的容器相互依赖,你不必担心删除一个影响另一个的容器。

@ tommasop的答案是好的,并解释了一些使用纯数据容器的机制。 但是,正如有人最初认为数据容器是愚蠢的,当一个人可以绑定一个卷的主机(如其他答案所build议的),但现在意识到,事实上,只有数据的容器是非常整洁,我可以build议我自己博客文章在这个主题: https : //medium.com/@ramangupta/why-docker-data-containers-are-good-589b3c6c749e

另请参阅:有关如何使用数据容器避免像主机的权限和uid / gid映射的问题的示例, 我对“ 什么是pipe理docker共享卷权限的(最佳)方法 ”的回答 。

为了解决OP的一个原始问题:数据容器不能被删除。 即使数据容器被删除,数据本身也不会丢失,只要任何容器引用该卷,即任何通过--volumes-from装入卷的容器。 因此,除非所有相关容器都被停止和删除(可以认为这相当于一个意外的rm -fr / ),否则数据是安全的。 您始终可以通过--volumes-from具有对该卷的引用的任何容器中执行--volumes-from来重新创build数据容器。

一如既往,做备份!

更新:Docker现在具有可以独立于容器进行pipe理的卷,这进一步简化了pipe理。

如果你想移动你的卷,你也应该看看https://github.com/clusterhq/flocker

从README:

Flocker是一个数据卷pipe理器和多主机Docker集群pipe理工具。 有了它,您可以使用您在无状态应用程序中使用的相同工具,通过利用Linux上ZFS的强大function来控制数据。 这意味着您可以在Docker中运行您的数据库,队列和键值存储,并像其他应用程序一样轻松地移动它们。

取决于你的情况(这不是真的适合产品环境),但这是一种方法: http : //txt.fliglio.com/2013/11/creating-a-mysql-docker-container/

这个要点是,使用主机上的一个目录来保存数据。

当使用docker-compose ,只需附加一个数据卷即

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

我最近写了一个潜在的解决scheme和一个应用程序来演示这个技术。 我发现它在开发和生产过程中非常高效。 希望它有助于或引发一些想法。

回购: https //github.com/LevInteractive/docker-nodejs-example
文章: http : //lev-interactive.com/2015/03/30/docker-load-balanced-mongodb-persistence/

根据您的需要,有几个pipe理持久性数据的级别:

  • 将其存储在主机上
    • 使用flag -v host-path:container-path将容器目录数据保存到主机目录
    • 备份/恢复通过运行备份/恢复容器(如tutumcloud / dockup)来安装到相同的目录
  • 创build一个数据容器,并将其挂载到你的应用容器
    • 创build一个导出数据卷的容器,使用--volumes-from将这些数据装载到你的应用程序容器中
    • 备份/恢复与上述解决scheme相同
  • 使用支持外部/第三方服务的docker卷插件
    • Docker卷插件允许您的数据源来自任何地方 – NFS,AWS(S3,EFS,EBS)
    • 根据插件/服务,您可以将单个或多个容器附加到单个卷
    • 根据服务的不同,备份/恢复可能会自动执行
    • 虽然手动操作可能会很麻烦,但是一些编排解决scheme(如Rancher )却可以将其烘焙并简单易用
    • Convoy是手动执行此操作的最简单的解决scheme

我只是在主机上使用预定义的目录来保存Postgres的数据。 另外,通过这种方式,可以轻松地将现有的Postgres安装迁移到Docker容器: https : //crondev.com/persistent-postgresql-inside-docker/

我的解决scheme是使用新的docker cp ,它现在能够从容器中复制数据,不pipe它是否在运行,并且共享主机卷到完全相同的位置,数据库应用程序创build它的db文件容器。 这种双重解决scheme在没有数据专用容器的情况下工作,直接从原始数据库容器。

所以我的systemd初始化脚本把备份数据库的工作放到主机上的一个存档中。 我在文件名中放置了一个时间戳,从不重写文件。

这是在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' 

在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' 

另外,我将主机上的一个文件夹作为一个卷暴露在与数据库存储位置完全相同的位置:

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

它在我的虚拟机上工作得很好(我为自己构build了一个LEMP堆栈): https : //github.com/DJviolin/LEMP

但是当你的生活实际上依赖于它时,我不知道它是否是一个“防弹”的解决scheme(例如:在任何可能的毫秒内都有交易的网上商店)?

在这个官方的Docker主题video20:20,主持人与db做同样的事情:

https://www.youtube.com/watch?v=klzLdzpPcQw

“对于数据库我们有一个卷,所以我们可以确保,当数据库上下移动时,当数据库容器停止时,我们不会丢失数据。”

使用来自Kubernetes的持久性音量声明,这是一个docker工具容器pipe理和排程工具

http://kubernetes.io/docs/user-guide/persistent-volumes/

为此目的使用Kubernetes的好处是

  • 你可以使用像NFS或其他存储的任何存储,甚至当节点closures时,存储也不需要。
  • 而且,这种体积中的数据可以configuration成即使在容器本身被破坏之后也能被保留下来,以便在需要时可以通过另一个容器来回收。