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

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

我目前正在使用这种方法:构建映像,例如对于PostgreSQL,然后用

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

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

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

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

308350 次浏览

虽然这仍然是Docker这需要一些工作的一部分,但您应该将卷放在DockerfileVOLUME指令中,这样您就不需要从另一个容器复制卷。

这将使您的容器减少相互依赖,您不必担心删除一个容器会影响另一个容器。

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

创建一个MySQL Docker容器

它的要点是使用主机上的目录进行数据持久性。

Docker 1.9.0及以上

使用卷接口

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

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

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

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

  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.xdocker volume prune

Docker 1.8. x及以下版本

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

仅数据容器在准系统映像上运行,实际上除了公开数据卷外什么也不做。

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

docker run --volumes-from data-container some-other-container command-to-execute
  • 这里您可以很好地了解如何排列不同的容器。
  • 这里对卷如何工作有很好的见解。

这篇博客文章中,对所谓的容器作为卷模式有一个很好的描述,它阐明了拥有纯数据容器的要点。

"="">Docker留档现在将容器的DEFINITIVE描述为卷/s模式。

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

备份:

sudo docker run --rm --volumes-from DATA -v $(pwd):/backup busybox tar cvf /backup/backup.tar /data
  • --rm:退出时删除容器
  • -v$(pwd):/备份:将当前目录绑定到容器中;将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.tardata/data/sven.txt# Compare to the original container$ sudo docker run --rm --volumes-from DATA -v `pwd`:/backup busybox ls /datasven.txt

这是一个很好的优秀的Brian Goff,解释了为什么对容器和数据容器使用相同的映像是好的。

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

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

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

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

另请参阅:我的答案到问题“管理Docker共享卷权限的(最佳)方法是什么?”,了解如何使用数据容器来避免权限和与主机的uid/gid映射等问题的示例。

解决OP最初的一个顾虑:数据容器一定不能删除。即使删除了数据容器,只要任何容器都有对该卷的引用,即通过--volumes-from挂载卷的任何容器,数据本身也不会丢失。因此,除非所有相关的容器都被停止和删除(人们可以认为这相当于意外的rm -fr /),否则数据是安全的。您可以通过--volumes-from任何有引用该卷的容器来重新创建数据容器。

一如既往,做备份!

更新:Docker现在拥有可以独立于容器管理的卷,这进一步使其更易于管理。

如果你想移动你的卷,你也应该看看Flocker

从自述:

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

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

我最近写了一篇关于潜在解决方案和演示该技术的应用程序的文章。我发现它在开发和生产过程中非常有效。希望它能帮助或激发一些想法。

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

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

因此,我的system d init脚本正在将数据库备份到主机上的存档中。我在文件名中放置了一个时间戳,以避免重写文件。

它在ExecStartPres上执行:

ExecStartPre=-/usr/bin/docker cp lanti-debian-mariadb:/var/lib/mysql /home/core/sqlExecStartPre=-/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/sqlExecStopPost=-/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: ./mariadbvolumes:- $HOME/server/mysql/:/var/lib/mysql/:rw

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

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

在这个官方Docker主题演讲视频的20分20秒处,演示者对数据库做同样的事情:

Docker入门

“对于数据库,我们有一个卷,因此我们可以确保,当数据库容器停止时,随着数据库的上升和下降,我们不会丢失数据。”

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

Docker 1.9.0中的纯数据容器过时了吗?#17798

我认为Docker维护者意识到纯数据容器模式有点设计味道,并决定使卷成为一个独立的实体,可以在没有关联容器的情况下存在。

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

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

以下是博客公告:撰写1.6:用于定义网络和卷的新撰写文件

这是一个示例撰写文件:

version: "2"
services:db:restart: on-failure:10image: postgres:9.4volumes:- "db-data:/var/lib/postgresql/data"web:restart: on-failure:10build: .command: gunicorn mypythonapp.wsgi:application -b :8000 --reloadvolumes:- .:/codeports:- "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 containersdocker-compose up -d
# .. input some data into the databasedocker-compose run --rm web python manage.py migratedocker-compose run --rm web python manage.py createsuperuser...
# Stop and remove the containers:docker-compose stopdocker-compose rm -f
# Start it back up againdocker-compose up -d
# Verify the data is still there...(it is)
# Stop and remove with the -v (volumes) tag:
docker-compose stopdocker=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
  • As they improve the integration between Docker Swarm and Docker Compose (and possibly start integrating Flocker into the Docker eco-system (I heard a rumor that Docker has bought Flocker), I think this approach should become increasingly powerful.

Disclaimer: This approach is promising, and I'm using it successfully in a development environment. I would be apprehensive to use this in production just yet!

使用库伯内特斯的持久卷索赔(PVC),这是一个Docker容器管理和调度工具:

持久卷

为此目的使用库伯内特斯的优点是:

  • 您可以使用任何存储,如NFS或其他存储,即使节点关闭,存储也不需要。
  • 此外,这些卷中的数据可以配置为即使在容器本身被销毁后也可以保留-以便在必要时可以由另一个容器回收。

使用Docker编写时,只需附加一个命名卷,例如:

version: '2'services:db:image: mysql:5.6volumes:- db_data:/var/lib/mysql:rwenvironment:MYSQL_ROOT_PASSWORD: rootvolumes:db_data:

管理持久化数据有多个级别,具体取决于您的需求:

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

要保存或存储数据库数据,请确保您的docker-compose.yml看起来像如果您想使用Dockerfile

version: '3.1'
services:php:build:context: .dockerfile: Dockerfileports:- 80:80volumes:- ./src:/var/www/html/db:image: mysqlcommand: --default-authentication-plugin=mysql_native_passwordrestart: alwaysenvironment:MYSQL_ROOT_PASSWORD: examplevolumes:- mysql-data:/var/lib/mysql
adminer:image: adminerrestart: alwaysports:- 8080:8080volumes:mysql-data:

你的docker-compose.yml看起来像如果您想使用映像而不是Dockerfile

version: '3.1'
services:php:image: php:7.4-apacheports:- 80:80volumes:- ./src:/var/www/html/db:image: mysqlcommand: --default-authentication-plugin=mysql_native_passwordrestart: alwaysenvironment:MYSQL_ROOT_PASSWORD: examplevolumes:- mysql-data:/var/lib/mysql
adminer:image: adminerrestart: alwaysports:- 8080:8080volumes:

如果你想存储或保存mysql的数据,那么一定要记住在docker-compose.yml中添加两行

volumes:- mysql-data:/var/lib/mysql

volumes:mysql-data:

之后使用此命令

docker-compose up -d

现在您的数据将持久化,即使使用此命令也不会删除

docker-compose down

额外:-但如果您想删除所有数据,那么您将使用

docker-compose down -v

另外,您可以使用此命令检查您的数据库数据列表

docker volume ls
DRIVER              VOLUME NAMElocal               35c819179d883cf8a4355ae2ce391844fcaa534cb71dc9a3fd5c6a4ed862b0d4local               133db2cc48919575fc35457d104cb126b1e7eb3792b8e69249c1cfd20826aac4local               483d7b8fe09d9e96b483295c6e7e4a9d58443b2321e0862818159ba8cf0e1d39local               725aa19ad0e864688788576c5f46e1f62dfc8cdf154f243d68fa186da04bc5eclocal               de265ce8fc271fc0ae49850650f9d3bf0492b6f58162698c26fce35694e6231clocal               phphelloworld_mysql-data