我一直在使用这个 Docker-image tutum/wordpress 来演示一个 Wordpress 网站。最近我发现该图像使用卷来存储 MySQL 数据。
所以问题是这样的:如果我想备份和恢复容器,我可以尝试提交一个镜像,然后删除容器,并从提交的镜像创建一个新容器。但是,如果我这样做,该卷将被删除,并且我的所有数据都将消失。
必须有一些简单的方法来备份我的容器及其卷数据,但我在任何地方都找不到它。
如果我想恢复容器,我可以尝试提交一个图像,然后删除容器,并从提交的图像创建一个新容器。但是,如果我这样做,该卷将被删除并且我的所有数据都消失了
正如 docker 用户指南所解释的,data volumes 旨在将数据保存在容器文件系统之外。这也简化了多个容器之间的数据共享。
虽然 Docker 永远不会删除卷中的数据(除非您使用 docker rm -v
删除关联的容器),但未被任何 Docker 容器引用的卷称为悬空卷。那些悬空卷很难摆脱也很难访问。
这意味着一旦使用卷的最后一个容器被删除,数据卷就会变得悬空并且其内容难以访问。
为了防止那些悬空的卷,诀窍是使用要保留的数据卷创建一个额外的 docker 容器,以便始终至少有该 docker 容器引用该卷。这样,您可以删除运行 wordpress 应用程序的 docker 容器,而不会失去访问该数据卷内容的便利性。
此类容器称为 data volume containers。
必须有一些简单的方法来备份我的容器和卷数据,但我在任何地方都找不到。
备份泊坞窗图像
要备份 docker 映像,请使用 docker save 命令,该命令将生成一个 tar 存档,以后可以使用 docker load 命令创建新的 docker 映像。
备份 docker 容器
您可以通过不同的方式备份 docker 容器
通过使用 docker commit 命令根据 docker 容器当前状态提交新的 docker 映像
通过使用 docker export 命令将 docker 容器文件系统导出为 tar 存档。您可以稍后使用 docker import 命令从该 tar 存档创建新的 docker 映像。
请注意,这些命令只会备份 docker 容器分层文件系统。这不包括数据量。
备份 docker 数据卷
要备份数据卷,您可以使用要备份的卷运行新容器并执行 tar 命令以生成卷内容的存档,如 docker user guide 中所述。
在您的特定情况下,数据卷用于存储 MySQL 服务器的数据。因此,如果要为此卷导出 tar 存档,则需要先停止 MySQL 服务器。为此,您必须停止 wordpress 容器。
备份 MySQL 数据
另一种方法是远程连接到 MySQL 服务器以使用 mysqldump 命令生成数据库转储。但是,为了使其工作,您的 MySQL 服务器必须配置为接受远程连接,并且还有一个允许远程连接的用户。您正在使用的 wordpress docker 映像可能不是这种情况。
编辑
Docker 最近引入了 Docker volume plugins,它允许将卷的处理委托给供应商实现的插件。
docker run
命令具有 -v
选项的新行为。现在可以向它传递一个卷名。以这种方式创建的卷被 命名 并且以后易于引用,从而缓解了 悬空卷 的问题。
编辑 2
Docker 引入了 docker volume prune
命令来轻松删除所有悬空卷。
更新 2
原始单卷备份 bash 脚本:
#!/bin/bash
# This script allows you to backup a single volume from a container
# Data in given volume is saved in the current directory in a tar archive.
CONTAINER_NAME=$1
VOLUME_PATH=$2
usage() {
echo "Usage: $0 [container name] [volume path]"
exit 1
}
if [ -z $CONTAINER_NAME ]
then
echo "Error: missing container name parameter."
usage
fi
if [ -z $VOLUME_PATH ]
then
echo "Error: missing volume path parameter."
usage
fi
sudo docker run --rm --volumes-from $CONTAINER_NAME -v $(pwd):/backup busybox tar cvf /backup/backup.tar $VOLUME_PATH
原始单卷还原 bash 脚本:
#!/bin/bash
# This script allows you to restore a single volume from a container
# Data in restored in volume with same backupped path
NEW_CONTAINER_NAME=$1
usage() {
echo "Usage: $0 [container name]"
exit 1
}
if [ -z $NEW_CONTAINER_NAME ]
then
echo "Error: missing container name parameter."
usage
fi
sudo docker run --rm --volumes-from $NEW_CONTAINER_NAME -v $(pwd):/backup busybox tar xvf /backup/backup.tar
用法可以是这样的:
$ volume_backup.sh old_container /srv/www
$ sudo docker stop old_container && sudo docker rm old_container
$ sudo docker run -d --name new_container myrepo/new_container
$ volume_restore.sh new_container
假设是:备份文件名为backup.tar,它与备份和恢复脚本位于同一目录,容器之间的卷名相同。
更新
在我看来,从容器备份卷与从数据容器备份卷没有什么不同。
卷只不过是链接到容器的路径,因此过程是相同的。
我不知道 docker-backup 是否也适用于相同的容器卷,但您可以使用:
sudo docker run --rm --volumes-from yourcontainer -v $(pwd):/backup busybox tar cvf /backup/backup.tar /data
和:
sudo docker run --rm --volumes-from yournewcontainer -v $(pwd):/backup busybox tar xvf /backup/backup.tar
结束更新
有一个不错的工具可以让你备份和恢复 docker 卷容器:
https://github.com/discordianfish/docker-backup
如果您有一个容器链接到一些容器卷,如下所示:
$ docker run --volumes-from=my-data-container --name my-server ...
您可以像这样备份所有卷:
$ docker-backup store my-server-backup.tar my-server
并像这样恢复:
$ docker-backup restore my-server-backup.tar
或者你可以按照官方的方式:
How to port data-only volumes from one host to another?
unknown shorthand flag: 'r' in -rm.
应该是 --rm
吗? (Docker 版本 18.09.5,构建 e8ff056)
如果您的项目使用 docker-compose,这里有一种备份和恢复卷的方法。
码头工人-compose.yml
基本上,您将 db-backup
和 db-restore
服务添加到您的 docker-compose.yml 文件中,并根据您的卷名称对其进行调整。在此示例中,我的卷名为 dbdata
。
version: "3"
services:
db:
image: percona:5.7
volumes:
- dbdata:/var/lib/mysql
db-backup:
image: alpine
tty: false
environment:
- TARGET=dbdata
volumes:
- ./backup:/backup
- dbdata:/volume
command: sh -c "tar -cjf /backup/$${TARGET}.tar.bz2 -C /volume ./"
db-restore:
image: alpine
environment:
- SOURCE=dbdata
volumes:
- ./backup:/backup
- dbdata:/volume
command: sh -c "rm -rf /volume/* /volume/..?* /volume/.[!.]* ; tar -C /volume/ -xjf /backup/$${SOURCE}.tar.bz2"
避免腐败
为了数据一致性,在备份或恢复之前停止你的数据库容器
docker-compose stop db
备份
要备份到默认目标 (backup/dbdata.tar.bz2
):
docker-compose run --rm db-backup
或者,如果要指定备用目标名称,请执行以下操作:
docker-compose run --rm -e TARGET=mybackup db-backup
恢复
要从 backup/dbdata.tar.bz2
恢复,请执行以下操作:
docker-compose run --rm db-restore
或使用以下命令从特定文件恢复:
docker-compose run --rm -e SOURCE=mybackup db-restore
我改编了来自 https://loomchild.net/2017/03/26/backup-restore-docker-named-volumes/ 的命令来创建这种方法。
如果您只需要备份已安装的卷,您可以从 Dockerhost 复制文件夹。
注意:如果你在 Ubuntu 上,Dockerhost 是你的本地机器。如果你在 Mac 上,Dockerhost 就是你的虚拟机。
在 Ubuntu 上
您可以在此处找到所有包含卷的文件夹:/var/lib/docker/volumes/
,以便您可以将它们复制并存档到任何您想要的位置。
在 MAC 上
这不像在 Ubuntu 上那么容易。您需要从 VM 复制文件。
这是一个脚本,说明如何将所有带有卷的文件夹从虚拟机(运行 Docker 服务器的位置)复制到本地计算机。我们假设您的 docker-machine VM 命名为 default。
docker-machine ssh default sudo cp -v -R /var/lib/docker/volumes/ /home/docker/volumes
docker-machine ssh default sudo chmod -R 777 /home/docker/volumes
docker-machine scp -R default:/home/docker/volumes ./backup_volumes
docker-machine ssh default sudo rm -r /home/docker/volumes
它将在当前目录中创建一个文件夹 ./backup_volumes 并将所有卷复制到此文件夹。
这是如何将所有已保存的卷从本地目录 (./backup_volumes) 复制到 Dockerhost 机器的脚本
docker-machine scp -r ./backup_volumes default:/home/docker
docker-machine ssh default sudo mv -f /home/docker/backup_volumes /home/docker/volumes
docker-machine ssh default sudo chmod -R 777 /home/docker/volumes
docker-machine ssh default sudo cp -v -R /home/docker/volumes /var/lib/docker/
docker-machine ssh default sudo rm -r /home/docker/volumes
现在您可以通过以下方式检查它是否有效:
docker volume ls
/var/lib/docker/volumes
?
假设您的卷名是 data_volume
。您可以使用以下命令在名为 data_image
的 docker 映像之间备份和恢复卷:
要备份:
docker run --rm --mount source=data_volume,destination=/data alpine tar -c -f- data | docker run -i --name data_container alpine tar -x -f-
docker container commit data_container data_image
docker rm data_container
恢复:
docker run --rm data_image tar -c -f- data | docker run -i --rm --mount source=data_volume,destination=/data alpine tar -x -f-
我知道这是旧的,但我意识到没有一个有据可查的解决方案将数据容器(作为备份)推送到 docker hub。我刚刚在 https://dzone.com/articles/docker-backup-your-data-volumes-to-docker-hub 上发布了一个简短示例,说明如何做到这一点
以下是底线
docker 教程建议您可以在本地备份和恢复数据卷。我们将使用这种技术,再添加几行以将此备份推送到 docker hub 中,以便将来轻松恢复到我们想要的任何位置。那么,让我们开始吧。这些是要遵循的步骤:
从名为 data-container-to-backup 的数据容器备份数据卷
docker run --rm --volumes-from data-container-backup --name tmp-backup -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /folderToBackup
将此 tar 文件展开到一个新容器中,以便我们可以将其作为其映像的一部分提交
docker run -d -v $(pwd):/backup --name data-backup ubuntu /bin/sh -c "cd / && tar xvf /backup/backup.tar"
提交并推送带有所需标签 ($VERSION) 的图像
docker commit data-backup repo/data-backup:$VERSION
docker push repo/data-backup:$VERSION
最后,让我们清理
docker rm data-backup
docker rmi $(docker images -f "dangling=true" -q)
现在我们的 repo 中有一个名为 data-backup 的图像,它只是一个带有备份文件和文件夹的文件系统。为了使用这个图像(也就是从备份中恢复),我们执行以下操作:
使用数据备份映像运行数据容器
run -v /folderToBackup --entrypoint "bin/sh" --name data-container repo/data-backup:${VERSION}
使用数据容器中的卷运行您的 whatEver 映像
docker run --volumes-from=data-container repo/whatEver
而已。
我很惊讶没有关于这项工作的文档。我希望有人觉得这很有帮助。我知道我花了一段时间才考虑到这一点。
以下命令将在安装了所有命名数据卷的容器中运行 tar,并将输出重定向到文件中:
docker run --rm `docker volume list -q | egrep -v '^.{64}$' | awk '{print "-v " $1 ":/mnt/" $1}'` alpine tar -C /mnt -cj . > data-volumes.tar.bz2
确保测试生成的存档以防出现问题:
tar -tjf data-volumes.tar.bz2
如果您只需要一个简单的存档备份,您可以试试我的小实用程序:https://github.com/loomchild/volume-backup
例子
备份:
docker run -v some_volume:/volume -v /tmp:/backup --rm loomchild/volume-backup backup archive1
将名为 some_volume
的卷归档到 /tmp/archive1.tar.bz2
归档文件
恢复:
docker run -v some_volume:/volume -v /tmp:/backup --rm loomchild/volume-backup restore archive1
将从 /tmp/archive1.tar.bz2
存档文件中擦除并恢复名为 some_volume
的卷。
更多信息:https://medium.com/@loomchild/backup-restore-docker-named-volumes-350397b8e362
/nginx-proxy/
中并且您的卷名为 db_data
,则上述示例中的 some_volume
将是 nginx-proxy_db_data
。用docker volume ls
检查这个
我创建了一个工具来编排和启动数据和 mysql 容器的备份,简称为 docker-backup。甚至还有一个ready-to-use image on the docker hub。
它主要是用 Bash 编写的,因为它主要是编排。它使用 duplicity
作为实际的备份引擎。您目前可以备份到 FTP(S) 和 Amazon S3。
配置非常简单:在 YAML 中编写一个配置文件,描述要备份的内容和位置,然后就可以了!
对于数据容器,它会自动挂载你的容器共享的卷来备份和处理它。对于 mysql 容器,它会链接它们并执行与您的容器捆绑在一起的 mysqldump 并处理结果。
我写它是因为我使用 Docker-Cloud,它与最近的 docker-engine 版本不是最新的,并且因为我想通过在我的应用程序容器中不包含任何备份过程来拥抱 Docker 方式。
如果您想要一个完整的备份,您将需要执行几个步骤:
将容器提交到映像 保存映像 通过在容器中创建卷挂载点的 tar 文件来备份容器的卷。对数据库容器也重复步骤 1-3。
请注意,仅将容器 Docker 提交到映像不包括附加到容器的卷(参考:Docker commit documentation)。
“提交操作将不包括安装在容器内的卷中包含的任何数据。”
我们可以使用图像来备份我们所有的卷。我写了一个脚本来帮助备份和恢复。此外,我将数据保存到 tar 文件压缩中,以将所有数据保存在本地磁盘上。我使用这个脚本将我的 Postgres 和 Cassandra 卷数据库保存在同一个图像中。例如,如果我们有一个用于 Postgres 的 pg_data 和一个用于 Cassandra 数据库的 cassandra_data 我们可以使用 pg_data 参数和 Cassandra 的 cassandra_data 参数调用以下脚本两次
备份脚本:
#! /bin/bash
GENERATE_IMAGE="data_image"
TEMPRORY_CONTAINER_NAME="data_container"
VOLUME_TO_BACKUP=${1}
RANDOM=$(head -200 /dev/urandom | cksum | cut -f1 -d " ")
if docker images | grep -q ${GENERATE_IMAGE}; then
docker run --rm --mount source=${VOLUME_TO_BACKUP},destination=/${VOLUME_TO_BACKUP} ${GENERATE_IMAGE} tar -c -f- ${VOLUME_TO_BACKUP} | docker run -i --name ${TEMPRORY_CONTAINER_NAME} ${GENERATE_IMAGE} tar -x -f-
else
docker run --rm --mount source=${VOLUME_TO_BACKUP},destination=/${VOLUME_TO_BACKUP} alpine tar -c -f- ${VOLUME_TO_BACKUP} | docker run -i --name ${TEMPRORY_CONTAINER_NAME} alpine tar -x -f-
fi
docker container commit ${TEMPRORY_CONTAINER_NAME} ${GENERATE_IMAGE}
docker rm ${TEMPRORY_CONTAINER_NAME}
if [ -f "$(pwd)/backup/${VOLUME_TO_BACKUP}.tar" ]; then
docker run --rm -v $(pwd)/backup:/backup ${GENERATE_IMAGE} tar cvf /backup/${VOLUME_TO_BACKUP}_${RANDOM}.tar /${VOLUME_TO_BACKUP}
else
docker run --rm -v $(pwd)/backup:/backup ${GENERATE_IMAGE} tar cvf /backup/${VOLUME_TO_BACKUP}.tar /${VOLUME_TO_BACKUP}
fi
例子:
./backup.sh cassandra_data
./backup.sh pg_data
恢复脚本:
#! /bin/bash
GENERATE_IMAGE="data_image"
TEMPRORY_CONTAINER_NAME="data_container"
VOLUME_TO_RESTORE=${1}
docker run --rm ${GENERATE_IMAGE} tar -c -f- ${VOLUME_TO_RESTORE} | docker run -i --rm --mount source=${VOLUME_TO_RESTORE},destination=/${VOLUME_TO_RESTORE} alpine tar -x -f-
例子:
./restore.sh cassandra_data
./restore.sh pg_data
问题:你想用其中的数据卷备份你的镜像容器,但是这个选项不是开箱即用的,直接而简单的方法是复制卷路径并备份 docker 镜像'重新加载并链接它两者一起。但这个解决方案似乎很笨拙,不可持续和可维护 - 您需要创建一个 cron 作业,每次都会使这个流程。
解决方案:使用 dockup - Docker 映像备份您的 Docker 容器卷并将其上传到 s3(Docker + Backup = dockup)。 dockup 将使用您的 AWS 凭证根据环境变量创建一个具有名称的新存储桶,获取配置的卷,并将被压缩、压缩、加时间戳并上传到 S3 存储桶。
脚步:
配置 docker-compose.yml 并将 env.txt 配置文件附加到它,数据应上传到专用的安全 s3 存储桶并准备好在 DRP 执行时重新加载。为了验证要配置哪些卷路径,请运行 docker inspect
“卷”:{“/etc/service-example”:{},“/service-example”:{}},
编辑配置文件env.txt的内容,放到项目路径:AWS_ACCESS_KEY_ID=
docker run --rm \ --env-file env.txt \ --volumes-from
然后验证您的 s3 存储桶是否包含相关数据
如果您有像我这样简单的案例,您可以执行以下操作:
创建一个扩展容器基本映像的 Dockerfile 我假设您的卷已映射到您的文件系统,因此您可以使用 ADD folder destination 将这些文件/文件夹添加到您的映像中完成!
例如,假设您有来自主目录上卷的数据,例如在 /home/mydata
,您可以运行以下命令:
DOCKERFILE=/home/dockerfile.bk-myimage
docker build --rm --no-cache -t $IMAGENAME:$TAG -f $DOCKERFILE /home/pirate
你的 DOCKERFILE 指向这样的文件:
FROM user/myimage
MAINTAINER Danielo Rodríguez Rivero <example@gmail.com>
WORKDIR /opt/data
ADD mydata .
其余的东西是从基本图像继承的。您现在可以将该映像推送到 docker cloud,您的用户将可以直接在其容器上使用数据
docker cp
覆盖没有卷的数据。
如果您喜欢从命令行输入奥术运算符,您会喜欢这些手动容器备份技术。请记住,有一种更快、更有效的方法来备份同样有效的容器。我在这里写了说明:https://www.morpheusdata.com/blog/2017-03-02-how-to-create-a-docker-backup-with-morpheus
第 1 步:将 Docker 主机添加到任何云 正如 Morpheus 支持站点上的教程中所述,您可以在几秒钟内将 Docker 主机添加到您选择的云中。首先在 Morpheus 主导航栏上选择 Infrastructure。在 Infrastructure 窗口顶部选择 Hosts,然后单击右上角的“+Container Hosts”按钮。
要通过 Morpheus 将 Docker 主机备份到云,请导航到 Infrastructure 屏幕并打开“+Container Hosts”菜单。
在菜单上选择容器主机类型,选择一个组,然后在五个字段中输入数据:名称、描述、可见性、选择云和输入标签(可选)。单击下一步,然后通过选择服务计划来配置主机选项。请注意,仅当您选择的计划启用了自定义选项时,卷、内存和 CPU 计数字段才可见。
您可以在此处添加和调整卷大小、设置内存大小和 CPU 数量以及选择网络。您还可以配置操作系统用户名和密码、域名和主机名,默认情况下是您之前输入的容器名称。单击下一步,然后添加任何自动化工作流(可选)。最后,检查您的设置并单击完成以保存它们。
第 2 步:将 Docker Registry 集成添加到公共或私有云 Adam Hicks 在另一个 Morpheus 教程中描述了与私有 Docker Registry 集成是多么简单。 (使用 Morpheus 使用公共 Docker API 使用 Docker 的公共集线器供应图像不需要额外的配置。)
在主导航栏的管理选项卡下选择集成,然后选择屏幕右侧的“+新集成”按钮。在出现的 Integration 窗口中,在 Type 下拉菜单中选择 Docker Repository,输入名称并添加私有注册表 API 端点。为您正在使用的注册表提供用户名和密码,然后单击保存更改按钮。
通过 Morpheus“新集成”对话框将 Docker Registry 与私有云集成。
要配置您刚刚创建的集成,请在 Create Instance 对话框中的 Type 下选择 Docker,在 Configure 选项卡下的 Docker Registry 下拉菜单中选择注册表,然后像任何 Docker 容器一样继续配置。
第 3 步:管理备份 添加 Docker 主机并集成注册表后,将为您配置的每个实例自动配置和执行备份。 Morpheus 支持提供有关查看备份、创建实例备份和创建服务器备份的说明。
我建议使用restic。这是一个易于使用的备份应用程序,可以备份到各种目标,例如本地文件系统、S3 兼容的存储服务或静态 REST 目标服务器,以提及一些选项。使用 resticker,您将拥有一个已经准备好的容器,可以使用 cron 语法进行调度:https://github.com/djmaze/resticker
对于那些想了解更多关于 restic 及其用法的人,我确实写了一篇关于该主题的博客文章系列,包括其用法示例:https://remo-hoeppli.medium.com/restic-backup-i-simple-and-beautiful-backups-bdbbc178669d
这是一种卷文件夹备份方式。如果你有 docker registry infra,这个方法非常有用。这使用 docker 注册表轻松移动 zip 文件。
#volume folder backup script. !/bin/bash
#common bash variables. set these variable before running scripts
REPO=harbor.otcysk.org:20443/levee
VFOLDER=/data/mariadb
TAG=mariadb1
#zip local folder for volume files
tar cvfz volume-backup.tar.gz $VFOLDER
#copy the zip file to volume-backup container.
#zip file must be in current folder.
docker run -d -v $(pwd):/temp --name volume-backup ubuntu \
bash -c "cd / && cp /temp/volume-backup.tar.gz ."
#commit for pushing into REPO
docker commit volume-backup $REPO/volume-backup:$TAG
#check gz files in this container
#docker run --rm -it --entrypoint bash --name check-volume-backup \
$REPO/volume-backup:$TAG
#push into REPO
docker push $REPO/volume-backup:$TAG
在另一台服务器
#pull the image in another server
docker pull $REPO/volume-backup:$TAG
#restore files in another server filesystem
docker run --rm -v $VFOLDER:$VFOLDER --name volume-backup $REPO/volume-backup:$TAG \
bash -c "cd / && tar xvfz volume-backup.tar.gz"
运行使用此卷文件夹的图像。您可以轻松制作一个同时具有一个运行映像和一个卷 zip 文件的映像。但我不推荐由于各种原因(图像大小,输入命令,..)。
Data volumes are designed to persist data, independent of the container’s life cycle. Docker therefore never automatically delete volumes when you remove a container, nor will it “garbage collect” volumes that are no longer referenced by a container.
所以只有数据的容器是遗留的mysqldump
不需要远程连接。只需将外壳放入容器中,转储它,然后使用docker cp
将其复制出来。data only container obsolete?
一点也不。仅数据容器为您提供了一个容器到docker exec data-container tar -czf snapshot.tgz /data
然后docker cp data-container:snapshot.tgz ./snapshot.tgz
等等。如果您希望容器长期存在,则使用最少的资源使其命令类似于tail -f /dev/null
它永远不会退出。