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

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

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

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

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

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

注意:除了--volumes-from 'cryptic_id'还可以使用--volumes-from my-data-container ,其中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

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

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

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

  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 文档现在将容器的定义描述为卷 / 秒模式。

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

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

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

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

从 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 ),该容器将在重启之间保持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)),我认为这种方法应该变得越来越强大。

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

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

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

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

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

这样可以减少容器之间的相互依存关系,而您不必担心删除一个容器会影响另一个容器。

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

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

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

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

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

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

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

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

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

从自述文件:

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

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

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

创建一个 MySQL Docker 容器

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