1039

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

我目前正在使用这种方法:构建图像,例如为 PostgreSQL,然后启动容器

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

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

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

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

4

15 回答 15

1004

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/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 文档现在将容器定义为 volume/s模式。

以下是 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 的一篇很好的文章,解释了为什么对容器和数据容器使用相同的图像是好的。

于 2013-12-18T07:50:09.230 回答
82

In Docker release v1.0, binding a mount of a file or directory on the host machine can be done by the given command:

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

The above volume could be used as a persistent storage on the host running Docker.

于 2014-10-29T10:30:59.693 回答
38

从 Docker Compose 1.6 开始,现在对 Docker Compose 中的数据卷的支持得到了改进。以下 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),我认为这种方法应该会变得越来越强大。

免责声明:这种方法很有前途,我在开发环境中成功使用了它。我会担心在生产中使用它!

于 2016-04-15T08:15:03.010 回答
18

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

请参阅docker 1.9.0 过时的纯数据容器?#17798

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

于 2016-02-15T16:47:13.580 回答
14

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

这将使您的容器之间的相互依赖程度降低,您不必担心删除一个容器会影响另一个容器。

于 2013-09-12T19:10:35.303 回答
14

使用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:
于 2017-01-31T09:27:01.640 回答
10

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

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

为了解决 OP 最初的担忧之一:不能删除数据容器。即使数据容器被删除,只要任何容器引用了该卷,即任何通过--volumes-from. 因此,除非所有相关的容器都被停止和删除(可以认为这相当于意外rm -fr /),否则数据是安全的。您始终可以通过执行--volumes-from任何引用该卷的容器来重新创建数据容器。

与往常一样,请进行备份!

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

于 2014-11-21T15:32:41.490 回答
10

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

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

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

从自述文件:

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

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

于 2015-04-02T11:58:59.240 回答
6

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

创建 MySQL Docker 容器

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

于 2013-12-14T23:12:58.420 回答
3

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

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

于 2015-04-02T12:29:18.367 回答
2

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

于 2016-03-20T08:04:01.027 回答
0

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

version: '3.1'

services:
  php:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - 80:80
    volumes:
      - ./src:/var/www/html/
  db:
    image: mysql
    command: --default-authentication-plugin=mysql_native_password
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: example
    volumes:
      - mysql-data:/var/lib/mysql

  adminer:
    image: adminer
    restart: always
    ports:
      - 8080:8080
volumes:
  mysql-data:

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

version: '3.1'   

services:
  php:
    image: php:7.4-apache
    ports:
      - 80:80
    volumes:
      - ./src:/var/www/html/
  db:
    image: mysql
    command: --default-authentication-plugin=mysql_native_password
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: example
    volumes:
      - mysql-data:/var/lib/mysql

  adminer:
    image: adminer
    restart: always
    ports:
      - 8080:8080
volumes:

如果你想存储或保存 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 NAME
local               35c819179d883cf8a4355ae2ce391844fcaa534cb71dc9a3fd5c6a4ed862b0d4
local               133db2cc48919575fc35457d104cb126b1e7eb3792b8e69249c1cfd20826aac4
local               483d7b8fe09d9e96b483295c6e7e4a9d58443b2321e0862818159ba8cf0e1d39
local               725aa19ad0e864688788576c5f46e1f62dfc8cdf154f243d68fa186da04bc5ec
local               de265ce8fc271fc0ae49850650f9d3bf0492b6f58162698c26fce35694e6231c
local               phphelloworld_mysql-data
于 2020-11-27T19:19:08.267 回答
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

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

于 2015-12-12T13:10:16.413 回答
0

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

持久卷

为此目的使用 Kubernetes 的优点是:

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