人们如何处理 Docker 容器的持久存储?
我目前正在使用这种方法:构建图像,例如为 PostgreSQL,然后启动容器
docker run --volumes-from c0dbc34fd631 -d app_name/postgres
恕我直言,这有一个缺点,我绝不能(偶然)删除容器“c0dbc34fd631”。
另一个想法是将主机卷“-v”挂载到容器中,但是,容器中的用户 ID 不一定与主机的用户 ID 匹配,然后权限可能会混乱。
注意:您也可以使用 --volumes-from my-data-container
而不是 --volumes-from 'cryptic_id'
,其中 my-data-container
是您分配给仅数据容器的名称,例如 docker run --name my-data-container ...
(请参阅接受的答案)
--name
。你有 -name
Docker 1.9.0 及以上
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
创建容器,Docker 将自动为您创建一个命名卷,它可以:
通过 docker volume ls 列出 通过 docker volume inspect volume_name 识别 备份为普通目录 通过 --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
在这里,您可以很好地了解如何安排不同的容器。
这里有一个关于卷如何工作的很好的见解。
在 this blog post 中,对所谓的container as volume pattern 进行了很好的描述,它阐明了data only container 的要点。
Docker documentation has now the DEFINITIVE description of the container as volume/s pattern.
以下是 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
这是一个很好的article from the excellent Brian Goff,它解释了为什么对容器和数据容器使用相同的图像是好的。
在 Docker v1.0 版本中,绑定主机上的文件或目录的挂载可以通过给定的命令完成:
$ docker run -v /host:/container ...
上述卷可以用作运行 Docker 的主机上的持久存储。
从 Docker Compose 1.6 开始,现在对 Docker Compose 中的数据卷的支持得到了改进。以下 compose 文件将创建一个数据图像,该图像将在父容器的重新启动(甚至删除)之间持续存在:
以下是博客公告:Compose 1.6: New Compose file for defining networks and volumes
这是一个示例撰写文件:
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).
笔记:
您还可以在卷块中指定各种驱动程序。例如,您可以为 db_data 指定 Flocker 驱动程序:volumes:db-data:driver:flocker
随着他们改进 Docker Swarm 和 Docker Compose 之间的集成(并且可能开始将 Flocker 集成到 Docker 生态系统中(我听说 Docker 已经收购了 Flocker),我认为这种方法应该会变得越来越强大。
免责声明:这种方法很有前途,我在开发环境中成功使用了它。我会担心在生产中使用它!
如果从所选答案的更新 5 中不清楚,从 Docker 1.9 开始,您可以创建可以存在而不与特定容器关联的卷,从而使“仅数据容器”模式过时。
请参阅 Data-only containers obsolete with docker 1.9.0? #17798。
我认为 Docker 维护人员意识到纯数据容器模式有点设计味道,并决定将卷作为一个单独的实体,无需关联容器即可存在。
虽然这仍然是 Docker that needs some work 的一部分,但您应该将卷放在带有 the VOLUME instruction 的 Dockerfile 中,这样您就不需要从另一个容器复制卷。
这将使您的容器之间的相互依赖程度降低,您不必担心删除一个容器会影响另一个容器。
docker rm
删除引用该卷的最后一个容器,Docker 就会销毁数据卷)
使用 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 的回答很好,并解释了使用纯数据容器的一些机制。但是作为一个最初认为数据容器很傻的人,当一个人可以将一个卷绑定到主机时(正如其他几个答案所建议的那样),但现在意识到实际上只有数据的容器非常整洁,我可以建议我自己的关于此主题的博文:Why Docker Data Containers (Volumes!) are Good
另请参阅:问题“What is the (best) way to manage permissions for Docker shared volumes?”的my answer,以获取有关如何使用数据容器来避免权限和与主机的 uid/gid 映射等问题的示例。
为了解决 OP 最初的担忧之一:不能删除数据容器。即使删除了数据容器,只要任何容器引用了该卷,即任何通过 --volumes-from
挂载该卷的容器,数据本身也不会丢失。因此,除非所有相关容器都停止并删除(可以认为这相当于意外 rm -fr /
),否则数据是安全的。您始终可以通过执行 --volumes-from
任何引用该卷的容器来重新创建数据容器。
与往常一样,请进行备份!
更新:Docker 现在有可以独立于容器管理的卷,这进一步使管理更容易。
根据您的需要,管理持久数据有几个级别:
将其存储在您的主机上使用标志 -v host-path:container-path 将容器目录数据持久保存到主机目录。通过运行安装到同一目录的备份/恢复容器(例如 tutumcloud/dockup)来进行备份/恢复。
使用标志 -v host-path:container-path 将容器目录数据持久保存到主机目录。
通过运行安装到同一目录的备份/恢复容器(例如 tutumcloud/dockup)来进行备份/恢复。
创建一个数据容器并将其卷安装到您的应用程序容器创建一个导出数据卷的容器,使用 --volumes-from 将该数据安装到您的应用程序容器中。备份/恢复与上述解决方案相同。
创建一个导出数据卷的容器,使用 --volumes-from 将该数据挂载到您的应用程序容器中。
备份/恢复与上述解决方案相同。
使用支持外部/第三方服务的 Docker 卷插件 Docker 卷插件允许您的数据源来自任何地方 - NFS、AWS(S3、EFS 和 EBS) 根据插件/服务,您可以附加单个或多个容器到一卷。根据服务的不同,备份/恢复可能会为您自动执行。虽然手动执行这可能很麻烦,但一些编排解决方案 - 例如 Rancher - 已经内置并且易于使用。 Convoy 是手动执行此操作的最简单的解决方案。
Docker 卷插件允许您的数据源来自任何地方 - NFS、AWS(S3、EFS 和 EBS)
根据插件/服务,您可以将单个或多个容器附加到单个卷。
根据服务的不同,备份/恢复可能会为您自动执行。
虽然手动执行这可能很麻烦,但一些编排解决方案 - 例如 Rancher - 已经内置并且易于使用。
Convoy 是手动执行此操作的最简单的解决方案。
如果您想移动您的卷,您还应该查看 Flocker。
从自述文件:
Flocker 是一个数据卷管理器和多主机 Docker 集群管理工具。有了它,您可以利用 Linux 上 ZFS 的强大功能,使用用于无状态应用程序的相同工具来控制数据。这意味着您可以在 Docker 中运行您的数据库、队列和键值存储,并像其他应用程序一样轻松地移动它们。
这取决于您的方案(这并不真正适合生产环境),但这是一种方法:
Creating a MySQL Docker Container
它的要点是使用主机上的目录进行数据持久性。
我最近写了一个潜在的解决方案和一个演示该技术的应用程序。我发现它在开发和生产过程中非常有效。希望它能帮助或激发一些想法。
回购: https://github.com/LevInteractive/docker-nodejs-example
文章: http://lev-interactive.com/2015/03/30/docker-load-balanced-mongodb-persistence/
我只是在主机上使用预定义的目录来为 PostgreSQL 保存数据。此外,通过这种方式可以轻松地将现有 PostgreSQL 安装迁移到 Docker 容器:https://crondev.com/persistent-postgresql-inside-docker/
我的解决方案是使用新的 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 秒处,演示者对数据库做了同样的事情:
“对于数据库,我们有一个卷,因此我们可以确保随着数据库的上升和下降,当数据库容器停止时,我们不会丢失数据。”
使用来自 Kubernetes 的 Persistent Volume Claim (PVC),它是一个 Docker 容器管理和调度工具:
为此目的使用 Kubernetes 的优点是:
您可以使用任何存储,如 NFS 或其他存储,即使节点关闭,也不需要存储。
此外,这些卷中的数据可以配置为即使在容器本身被销毁后仍保留 - 以便在必要时可以由另一个容器回收。
要保存或存储数据库数据,请确保您的 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
--volumes-from
让您共享磁盘空间--link
让您共享服务。docker volume create --name mydata
) 创建命名卷优于数据卷容器。 Docker 的人自己建议数据卷容器“are no longer considered a recommended pattern”、“named volumes should be able to replace data-only volumes in most (if not all) cases”和“no reason I can see to use data-only containers”。