如何在Docker中处理持久性存储(例如数据库)


991

人们如何处理Docker容器的持久存储?

我当前正在使用这种方法:构建映像(例如针对PostgreSQL),然后使用以下命令启动容器

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

恕我直言,这有一个缺点,我绝对不能(偶然地)删除容器“ c0dbc34fd631”。

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

注意:例如,--volumes-from 'cryptic_id'您可以使用--volumes-from my-data-containerwhere my-data-container是分配给仅数据容器的名称,而不是docker run --name my-data-container ...(请参见接受的答案)


抱歉,我的意思是说错了,我想说的是:该映像中将来的所有实例都依赖于该容器。如果我不小心删除了那个容器,那就麻烦了。
juwalter 2013年

@AntonStrogonoff-是的,措辞错误-我的意思是说:我需要确保我永远不会删除那个(可能是)旧容器,因为那样的话,“持久”存储的引用也将消失
juwalter 2013年

应该是--name。您有-name
Shammel Lee

Answers:


985

Docker 1.9.0及更高版本

使用体积API

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

这意味着必须放弃仅数据的容器模式,而使用新的卷。

实际上,卷API只是实现数据容器模式的一种更好的方法。

如果使用-v volume_name:/container/fs/pathDocker 创建容器,则会自动为您创建一个命名卷,该卷可以:

  1. 通过列出 docker volume ls
  2. 通过识别 docker volume inspect volume_name
  3. 备份为普通目录
  4. 通过--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文档现在将容器的定义描述为卷/秒模式。

以下是Docker 1.8.x及以下版本的备份/还原过程。

备份:

sudo docker run --rm --volumes-from DATA -v $(pwd):/backup busybox tar cvf /backup/backup.tar /data
  • --rm:退出时删除容器
  • --volumes-from DATA:附加到DATA容器共享的卷
  • -v $ {pwd):/ backup:将当前目录绑定安装到容器中;将tar文件写入
  • busybox:一个简单的小图像-适合快速维护
  • tar cvf /backup/backup.tar / data:创建/ data目录中所有文件的未压缩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的一篇不错的文章,解释了为什么对容器和数据容器使用相同的图像会很好。


8
这是针对不同需求的不同工具。--volumes-from让您共享磁盘空间--link让您共享服务。
tommasop 2014年

3
作品中还有一个专门针对此类事物的项目,也许将其添加到此答案中作为观看参考?github.com/ClusterHQ/flocker
Andre

9
数据容器没有任何意义,真是个坏主意!容器仅在进程正在其中运行时才有意义,否则它只是一部分主机文件系统。您只能使用-v挂载卷,这是唯一的最佳选择。您可以控制使用的文件系统和物理磁盘。
Boynux

11
是的,从Docker 1.9开始,使用Volumes API(docker volume create --name mydata)创建命名卷比使用Data Volume Container更好。Docker上的人们自己建议,“数据卷容器” 不再被视为推荐模式,”“ 在大多数(如果不是全部)情况下命名卷应该能够替换仅数据卷 ”,以及“ 我看不到要使用的理由仅数据容器。”
Quinn Comendant '16

8
@coding,我很伤心,您感到难过,部分是因为您对答案的判断拖延了3年,部分是因为答案在历史上基本上是正确的。如果您有任何建议,请随时发表评论,以便我整合答案并帮助人们不要感到难过
tommasop 2016年

74

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

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

以上卷可用作运行Docker的主机上的持久性存储。


3
这应该是建议的答案,因为它远不如目前拥有更多选票的容量容器方法复杂
insitusec

2
我希望在使用此卷安装命令时,有一个标志来指定host-uid:container-uid和host-gid:container-gid映射。

34

从Docker Compose 1.6开始,现在改进了对Docker Compose中数据量的支持。以下撰写文件将创建一个数据映像,该映像将在父容器重启(甚至删除)之间保持不变:

这是博客公告:Compose 1.6:用于定义网络和卷的新Compose文件

这是一个示例撰写文件:

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:

据我了解:这将创建一个数据卷容器(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"
  }
]

一些测试:

# 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)),我认为这种方法应该变得越来越强大。

免责声明:这种方法很有希望,我正在开发环境中成功使用它。我现在还很担心在生产中使用它!


Flocker已被关闭github库
克里希纳

17

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

请参阅Docker 1.9.0淘汰的仅数据容器?#17798

我认为Docker维护人员意识到纯数据容器模式有点设计气味,因此决定将卷作为一个单独的实体而无需关联容器就可以存在。


13

尽管这仍然是Docker的一部分,需要做一些工作,但是您应该使用VOLUME指令将卷放入Dockerfile中,这样就无需从其他容器复制卷了。

这将使您的容器之间的依赖性降低,并且您不必担心删除一个容器会影响另一个容器。


另一面的说法是,“仅数据”容器最终成为对数据卷的最后一种引用(一旦使用删除了引用该卷的最后一个容器,Docker就会销毁数据卷docker rm
WineSoaked 2014年

2
Docker的这份官方指南另有建议:docs.docker.com/userguide/dockervolumes/… “数据卷旨在保留数据,而与容器的生命周期无关。因此,Docker永远不会在删除容器时自动删除卷,也不会容器不再引用的“垃圾收集”卷。”
亚历克斯(Alex)

12

使用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:

9

@tommasop的答案很好,并解释了使用仅数据容器的一些机制。但是,正如最初以为可以将一个卷绑定到主机上的数据容器愚蠢的人(正如其他几个答案所建议的那样),但是现在意识到实际上仅数据容器非常整洁,我可以建议我自己使用关于该主题的博客文章:为什么Docker数据容器(卷!)很好

另请参阅:对“以下问题的回答” :管理Docker共享卷权限的(最佳)方法是什么? ”的如何使用数据容器来避免诸如权限以及与主机进行uid / gid映射之类的问题的示例。

要解决OP最初关注的问题之一:不得删除数据容器。即使删除了数据容器,只要任何容器都具有对该卷的引用,即通过装载该卷的任何容器,数据本身也不会丢失--volumes-from。因此,除非所有相关容器都已停止并删除(可能认为这是偶然的rm -fr /),否则数据是安全的。您始终可以通过执行--volumes-from任何引用该卷的容器来重新创建数据容器。

与往常一样,尽管要进行备份!

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


9

根据您的需求,管理持久数据有多个级别:

  • 将其存储在您的主机上
    • 使用该标志-v host-path:container-path将容器目录数据持久保存到主机目录。
    • 通过运行安装到同一目录的备份/还原容器(例如tutumcloud / dockup)来进行备份/还原。
  • 创建一个数据容器并将其卷安装到您的应用程序容器
    • 创建一个导出数据量的容器,--volumes-from用于将数据装载到您的应用程序容器中。
    • 备份/还原与上述解决方案相同。
  • 使用支持外部/第三方服务的Docker卷插件
    • Docker卷插件可让您的数据源来自任何地方-NFS,AWS(S3,EFS和EBS)
    • 根据插件/服务的不同,您可以将单个或多个容器附加到单个卷上。
    • 根据服务的不同,备份/还原可能会自动为您完成。
    • 尽管手动执行此操作很麻烦,但是某些编排解决方案(例如Rancher)可以将其烘焙并且易于使用。
    • Convoy是手动执行此操作的最简单解决方案。

8

如果要移动音量,还应该查看Flocker

从自述文件:

Flocker是数据卷管理器和多主机Docker集群管理工具。借助它,您可以利用Linux上ZFS的强大功能,使用与无状态应用程序相同的工具来控制数据。

这意味着您可以在Docker中运行数据库,队列和键值存储,并像其他应用程序一样轻松地移动它们。


1
谢谢约翰。我在ClusterHQ工作,我只想指出我们已经超越了仅基于ZFS的存储。现在,您可以将Flocker与Amazon EBS或Google Persistent Disk等存储一起使用。下面是存储选项的完整列表:docs.clusterhq.com/en/latest/supported/...
ferrantim

1
Flocker已停止,不应使用portworx.com/…–
jesugmz

5

这取决于您的方案(这并不真正适合生产环境),但这是一种方法:

创建一个MySQL Docker容器

其主要目的是使用主机上的目录进行数据持久化。


6
但是,感谢Ben,我-用这种方法可以看到的问题之一:文件系统资源(目录,文件)将由docker / lxc容器(来宾)内部的uid拥有-一个可能与uid冲突的问题在主机上...
juwalter 2013年

1
我认为您是安全的,因为它是由root用户运行的,但是我同意这是一个hack-最多适合于本地开发人员/临时集成测试。我绝对想在这方面看到更多的模式/思考。您应该将这个问题检出/发布到docker-dev Google组
Ben schwartz 2013年

Ben,感谢您的解决方案!不过,我不会称其为hack,它似乎比容器作为卷更可靠。如果仅从容器中使用数据,您是否看到任何缺点?(在这种情况下,UID无关紧要)
johndodo 2014年



0

我的解决方案是利用new docker cp,现在它可以从容器中复制数据,而不管它是否正在运行,并将主机卷共享到数据库应用程序在容器内创建数据库文件的完全相同的位置。这种双重解决方案无需直接来自原始数据库容器的仅数据容器即可工作。

因此,我的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

它在我的VM上效果很好(我为自己构建了一个LEMP堆栈):https : //github.com/DJviolin/LEMP

但是,当您的生活实际上取决于它时(例如,在任何可能的毫秒内进行交易的网上商店),我只是不知道这是否是“防弹”解决方案?

在此官方Docker主题视频的20分20秒处,演示者对数据库执行相同的操作:

Docker入门

“对于数据库,我们有一个卷,因此可以确保在数据库容器停止运行时,随着数据库的上下移动,我们不会丢失数据。”


“ ...使用...”是什么意思?还有“ ...在任何可能的毫秒内进行交易”
彼得·莫滕森

0

使用来自Kubernetes的Persistent Volume Claim(PVC),它是Docker容器管理和调度工具:

持久卷

为此使用Kubernetes的优点是:

  • 您可以使用任何存储,例如NFS或其他存储,即使节点关闭,也不必使用该存储。
  • 此外,即使在容器本身被破坏之后,也可以将此类卷中的数据配置为保留-以便在必要时可以由另一个容器进行回收。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.