| 后端 , PostgreSQL , Docker
pg_dump
导出 PostgreSQL 数据库中的数据
在 Docker 容器中使用数据库非常方便快捷,因为我们随时可以创建或者删除一个运行数据库的容器。然而,当我们想要便捷地导出容器数据库中的数据时,麻烦就出现了。
在阅读后续内容之前,请确保您的数据库容器已经使用了 -v
参数在容器上挂载了指定的主机目录!
因为我们需要导出文件到宿主系统中,如果容器没有挂载主机中的目录,容器无法将内部文件导出到外部的宿主系统。
接下来,让我们开始吧~
首先,导出的文件需要指定导出的目录和文件名称。我希望文件名中带有导出的时间,所以我使用了 date
命令:
在命令行中运行以下指令:
date "+%Y-%m-%d_%H_%M_%S"
你会得到具有类似格式的结果:
2020-09-19_15-26-08
在得到我想要的文件名之后,接下来就指定数据导出的目录。因为我在创建容器时就已经将 PostgreSQL 数据库默认使用的 /var/lib/postgresql/data
目录挂载到了宿主系统,所以我希望将备份也导出到这个目录中。这样,我就可以很方便地在宿主系统中的挂载目录里看到导出的数据备份文件。
为了不污染数据库默认目录,我在这个默认目录里创建了一个 /backup
目录。执行以下命令创建这个目录:
mkdir /var/lib/postgresql/data/backup
如果后续的导出操作无法写入文件到这个目录,可能需要调整这个文件夹的权限(这个指令可以在宿主系统中执行,也可以在数据库容器中执行):
chmod 777 /var/lib/postgresql/data/backup
此时,完整的导出路径如下所示:
/var/lib/postgresql/data/backup/db_data_"`date "+%Y-%m-%d_%H_%M_%S"`".bak
然后,在运行 PostgreSQL 数据库的容器中执行 pg_dump
导出指定数据库(如:test_db
)中的数据:
pg_dump test_db > "/var/lib/postgresql/data/backup/db_data_"`date "+%Y-%m-%d_%H_%M_%S"`".bak"
假如最初创建 PostgreSQL 数据库容器的指令为,也就是指定了 /home/test_user/docker_files/postgres
为宿主系统中的挂载目录:
docker run --name postgres -p 5432:5432 -v /home/test_user/docker_files/postgres:/var/lib/postgresql/data -e POSTGRES_PASSWORD=my_password -d postgres:13
那么,执行以上命令之后,在宿主系统里的 /home/test_user/docker_files/postgres/backup
目录下就可以找到一个以 db_data_
开头的文件。
请注意,在执行 pg_dump
命令时,您可能因为没有指定正确的数据库用户而遭遇错误。错误可能类似于:
pg_dump: error: connection to database "test_db" failed: FATAL: role "root" does not exist
如果是这样,在执行 pg_dump
命令前,我们需要在容器中以指定的用户来访问数据库并执行导出操作。
假如,您的数据库中的用户是默认的 postgres
,那么您可以执行 su - postgres
命令来切换到 postgres
用户。然后,再执行 pg_dump
命令。
此时,您执行的命令大致是这样的:
# 以交互式的方式连接到 postgres 容器
docker exec -it postgres /bin/bash
# 切换到 postgres 用户
su - postgres
# 导出 test_db 数据库中的数据
pg_dump test_db > "/var/lib/postgresql/data/backup/db_data_"`date "+%Y-%m-%d_%H_%M_%S"`".bak"
最后,再去宿主系统里的 /home/test_user/docker_files/postgres/backup
目录,确认数据是否成功导出。
如果已经成功导出,那么恭喜您!如果没有,欢迎您给我留言。这一步到这里就结束了,但是如果我们每一次都这样导出数据,操作实在太繁琐!
有没有更便捷一些的方法呢? 请继续阅读后文~
前文中所有的操作,无非就是 用指定的数据库用户,去导出数据库容器中某个数据库里的数据到指定的目录,并以指定的文件名来命名文件
。
那么多的手动操作指令,可以结合成一句 docker 指令吗? 可以!
首先,想在宿主系统中命令 docker 容器执行某些指令,我们需要使用 docker exec
命令。
docker exec -it
可以启动一个交互式的环境,但是现在并不需要手动操作。只需要 docker 容器在后台执行某些指令即可,所以 docker exec -d
命令更符合现在的需求。
然后,指定正确的数据库用户,并让 docker 以这个用户的身份对容器进行操作。例如,这里是 postgres
用户,此时命令如下所示:
docker exec -d --user postgres postgres
--user postgres
用来指定用户,后面的 postgres
是数据库容器的名称。
接下来,执行数据导出指令。在容器名称后添加 sh -c
参数,然后用双引号 "
包住需要执行的指令即可:
docker exec -d --user postgres postgres sh -c "pg_dump test_db > "/var/lib/postgresql/data/backup/db_data_"`date "+%Y-%m-%d_%H_%M_%S"`".bak""
在宿主系统中运行上述指令,您是否可以在宿主系统里的 /home/test_user/docker_files/postgres/backup
挂载目录看到最新的导出文件?
如果可以,恭喜您!如果不行,欢迎您给我留言。
Okay,数据已经导出了。如果您需要将数据发送到本地机器,请继续阅读后文~
这一步很简单,非常简单!使用 scp
命令即可将数据备份文件传输到本地机器:
scp -r 用户名@远程机器的IP地址:文件目录 本地目录
比如:
scp -r root@129.28.10.2:/home/test_user/docker_files/postgres/backup .
执行完毕后,在执行这个指令的工作目录下,您就会发现一个 backup
目录。里面就是远程机器刚刚导出的那些数据库备份文件!
即使导出和传输任务已经达成,这个步骤还是有一点点繁琐,让我们把这个步骤再优化一下!请继续阅读后文~
首先,在本地文件系统中创建一个脚本文件,以后我们只需要在这个脚本所在的目录执行 ./backup_remote_psql.sh
,导出和传输任务即可完成!
创建脚本文件的指令:
touch backup_remote_psql.sh
# 添加可执行的权限
chmod 777 backup_remote_psql
然后,向这个脚本文件添加以下内容:
ssh root@129.28.10.2 'cd /home/test_user/docker_files/postgres/backup && rm -f *.* && docker exec -d --user postgres postgres sh -c "pg_dump test_db > "/var/lib/postgresql/data/backup/db_data_ "`date "+%Y-%m-%d_%H_%M_%S"`".bak""'
scp -r root@129.28.10.2:/home/test_user/docker_files/postgres/backup .
解释以上脚本中部分操作的含义:
ssh root@129.28.10.2
后面单引号包住的部分的内容是需要远程机器执行的一些命令,此时我们并不需要通过 ssh 执行交互式的操作;
cd /home/test_user/docker_files/postgres/backup
切换工作路径到到备份目录;
使用 &&
连接多个命令,确保前面的指令执行成功后再执行后续的命令;
rm -f *.*
删除旧的数据库备份文件,我们只需要将最新的备份传回本地机器即可;
至此,导出、传输、自动化都已经实现。如果您想定期备份数据,可以考虑使用 crontab
之类的工具实现这个需求。
PostgreSQL 是个非常强大且易用的开源数据库,它同时支持了 SQL 和 NoSQL,非常推荐使用!感谢 PostgreSQL!
Docker 真的是一个很好用的工具!你可以随意配置容器,灵活度极高、扩展性极强,你根本不用担心误删了什么东西。感谢 Docker!
使用 scp 指令传文件,简直不能再便捷了!感谢 scp!
最后,感谢下列所有参考内容的作者!!!
参考内容:
深入理解Docker Volume(一)
How to Back Up Your PostgreSQL Database
PostgreSQL Backup issue
How to run 2 commands with docker exec
Escape character in Docker command line
Connect to docker container as user other than root
How to get the current date and time in YYYYMMDDHHMMSS format in ksh88?
觉得不错?点个赞呗~
本文链接:备份远程 Docker 中 PostgreSQL 数据库里的数据到本地
转载声明:本站文章如无特别说明,皆为原创。转载请注明:Ficow Shen's Blog