备份/恢复一个运行在Docker中的PostgreSQL数据库

365

我正在尝试按照Docker网站上的说明备份/还原PostgreSQL数据库,但数据没有被还原。

数据库镜像使用的卷为:

VOLUME  ["/etc/postgresql", "/var/log/postgresql", "/var/lib/postgresql"]

并且CMD是:

CMD ["/usr/lib/postgresql/9.3/bin/postgres", "-D", "/var/lib/postgresql/9.3/main", "-c", "config_file=/etc/postgresql/9.3/main/postgresql.conf"]

我使用以下命令创建数据库容器:

docker run -it --name "$DB_CONTAINER_NAME" -d "$DB_IMAGE_NAME"

然后我连接另一个容器手动插入一些数据:

docker run -it --rm --link "$DB_CONTAINER_NAME":db "$DB_IMAGE_NAME" sh -c 'exec bash'
psql -d test -h $DB_PORT_5432_TCP_ADDR
# insert some data in the db
<CTRL-D>
<CTRL-D>

然后创建tar存档:

$ sudo docker run --volumes-from "$DB_CONTAINER_NAME" --rm -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /etc/postgresql /var/log/postgresql /var/lib/postgresql

现在我删除了用于数据库的容器,并创建了另一个具有相同名称的容器,然后尝试恢复之前插入的数据:

$ sudo docker run --volumes-from "$DB_CONTAINER_NAME" --rm -v $(pwd):/backup ubuntu tar xvf /backup/backup.tar 

但是表是空的,为什么数据没有被正确恢复?


1
https://dev59.com/k10b5IYBdhLWcg3wENmK#59215489 - Omid Raha
15个回答

921

备份您的数据库

docker exec -t your-db-container pg_dumpall -c -U postgres > dump_`date +%d-%m-%Y"_"%H_%M_%S`.sql

恢复你的数据库

cat your_dump.sql | docker exec -i your-db-container psql -U postgres

4
没错,这是使用PostgreSQL的方法,但我认为在使用Docker时应始终优先考虑Docker的方式。 - Carl Levasseur
90
为了节省磁盘空间,您可能希望将转储数据传输到gzip进行压缩:docker exec -t your-db-container pg_dumpall -c -U postgres | gzip > /var/data/postgres/backups/dump_date +%d-%m-%Y""%H%M_%S.gz - Tarion
3
恢复数据之前,请先解压缩数据。如果想将其作为一行代码执行,则需使用解压缩命令替换cat your_dump.sql,并将其输出结果通过管道传递给docker exec,而不是直接传递cat的结果。 - Tarion
20
对于那些无法弄清如何使日期格式化的人:docker exec -t 你的数据库容器 pg_dumpall -c -U postgres | gzip > ./tmp/dump_$(date +"%Y-%m-%d_%H_%M_%S").gz 该命令将数据库导出并以压缩文件形式保存到./tmp/目录下,文件名包含当前日期和时间。 - 9_Dave_9
29
在恢复数据库时,如果你的数据库名称不是 postgres,请确保在恢复命令中添加 -d 你的数据库名称。注意不要改变原意。 - J86
显示剩余13条评论

112

备份数据库

生成 SQL:

  • docker exec -t your-db-container pg_dumpall -c -U your-db-user > dump_$(date +%Y-%m-%d_%H_%M_%S).sql

为了减小 SQL 文件的大小,你可以生成压缩文件:

  • docker exec -t your-db-container pg_dumpall -c -U your-db-user | gzip > ./dump_$(date +"%Y-%m-%d_%H_%M_%S").gz

恢复数据库

  • cat your_dump.sql | docker exec -i your-db-container psql -U your-db-user -d your-db-name

如果你需要恢复一个压缩的 SQL 文件:

  • gunzip < your_dump.sql.gz | docker exec -i your-db-container psql -U your-db-user -d your-db-name

注:这是我的经验总结以及来自其他地方的资料。我刚开始做贡献,欢迎提供反馈。


使用“cat your_dump.sql | ....”来恢复数据库,我认为性能非常低,我错了吗? - EmiliOrtega
你在gz之前忘记了一个sql扩展名:docker exec -t your-db-container pg_dumpall -c -U your-db-user | gzip > ./dump_$(date +"%Y-%m-%d_%H_%M_%S").sql.gz - reza
场景:user表有2个用户。我们进行了备份。我们注册了另一个用户,因此表中有3个条目。我们使用cat your_dump.sql | docker exec -i your-db-container psql -U your-db-user -d your-db-name恢复备份。结果:用户表仍然有3个条目;备份没有恢复备份时的数据库状态。附注:我也是初学者,可能持有关于备份工作方式的不正确假设。 - yomajo

85

我认为您也可以使用一个postgres备份容器,该容器将在给定的时间间隔内备份您的数据库。

  pgbackups:
    container_name: Backup
    image: prodrigestivill/postgres-backup-local
    restart: always
    volumes:
      - ./backup:/backups
    links:
      - db:db
    depends_on:
      - db
    environment:
      - POSTGRES_HOST=db
      - POSTGRES_DB=${DB_NAME} 
      - POSTGRES_USER=${DB_USER}
      - POSTGRES_PASSWORD=${DB_PASSWORD}
      - POSTGRES_EXTRA_OPTS=-Z9 --schema=public --blobs
      - SCHEDULE=@every 0h30m00s
      - BACKUP_KEEP_DAYS=7
      - BACKUP_KEEP_WEEKS=4
      - BACKUP_KEEP_MONTHS=6
      - HEALTHCHECK_PORT=81

你怎么准确地运行这个命令?我是 Docker 新手。 - Jack B
1
这个能在没有停机时间的情况下工作吗?在创建备份时,容器如何处理发生的变化? - Chris1309
@AneeshPanoli 到定义在 ./backup:/backups 的 /backups 文件夹。 - atakan
3
非常有用的工具,适用于想要定期自动备份数据库的人。 - emilaz
1
如何恢复备份? - S. M. JAHANGIR
显示剩余3条评论

45

cat db.dump | docker exec ...的方式对我的备份文件(大小约为2GB)没有起作用。它花了几个小时,并最终出现了内存不足的错误。

相反,我将备份文件复制到容器中,并在其中使用pg_restore进行恢复。

假设容器id为CONTAINER_ID,数据库名为DB_NAME

# copy dump into container
docker cp local/path/to/db.dump CONTAINER_ID:/db.dump

# shell into container
docker exec -it CONTAINER_ID bash

# restore it from within
pg_restore -U postgres -d DB_NAME --no-owner -1 /db.dump

这种方法与通常的方法不同,当我在Windows上执行时,它帮助我获得了正确的编码。 (实际上,我通过运行“cat /home/db.sql | psql -U postgres -d DB_NAME -p DB_PORT”来应用转储) - YakovL
这样可以更快地工作。可以基于此编写备份脚本,构建包含脚本的镜像,并通过cronjob从主机上运行脚本。将主机卷挂载到容器上,并让备份服务器拉取每日的SQL转储文件。 - mistige
我很感激这个,因为我也曾经遇到过“cat db.dum |...”的同样问题。 - EmiliOrtega

13

好的,我已经理解了。Postgresql在启动后不会检测/var/lib/postgresql文件夹的更改,至少不会检测我想要它检测的那种更改。

第一种解决方案是直接启动一个带有bash的容器,然后手动恢复数据并手动启动服务器。

第二种解决方案是使用数据容器。之前我没有理解它的作用,现在我理解了。 这个数据容器允许在启动postgres容器之前还原数据。因此,在postgres服务器启动时,数据已经存在了。


1
Flocker或者Convoy可能有助于处理数据容器。 - Forth
37
请提供更多细节。这似乎更像是解决方案的草图,而不是一个实际的解决方案。 - nafg

13
以下命令可用于从Docker Postgres容器中提取转储:
docker exec -t <postgres-container-name> pg_dump --no-owner -U <db-username> <db-name> > file-name-to-backup-to.sql

1
注意:当我使用 pg_dump -F c(自定义格式)和 docker exec -t 选项时,我遇到了备份文件损坏的情况。我认为终端模式干扰了管道二进制输出。不要使用 docker exec -t(或 -i)。 - not2savvy

9

对我来说,最好的答案没有起作用。我一直收到这个错误:

psql: error: FATAL:  Peer authentication failed for user "postgres"

为了让其正常工作,我必须为Docker容器指定一个用户:

备份

docker exec -t --user postgres your-db-container pg_dumpall -c -U postgres > dump_`date +%d-%m-%Y"_"%H_%M_%S`.sql

还原

cat your_dump.sql | docker exec -i --user postgres your-db-container psql -U postgres

6

另一种方法(基于docker-postgresql-workflow

本地运行数据库(不在Docker中,但同样的方法也适用)来进行导出:

pg_dump -F c -h localhost mydb -U postgres export.dmp

需要导入的容器数据库:

docker run -d -v /local/path/to/postgres:/var/lib/postgresql/data postgres #ex runs container as `CONTAINERNAME` #find via `docker ps`
docker run -it --link CONTAINERNAME:postgres  --volume $PWD/:/tmp/  postgres  bash -c 'exec pg_restore -h postgres -U postgres -d mydb -F c /tmp/sonar.dmp'

1
在 Docker 容器的 Bash 中,以下命令适用:pg_dump mydb -U postgres > export.psql - Sepultura

4

在尝试使用db_dump恢复数据库时,我遇到了这个问题。我通常使用dbeaver来进行还原操作-但是收到了一个psql dump,因此必须找出一种使用docker容器进行还原的方法。

由Forth推荐并由Soviut编辑的方法对我有用:

cat your_dump.sql | docker exec -i your-db-container psql -U postgres -d dbname

(由于这是单个db dump而不是多个db,所以我包括了名称)

但是,为了使其工作,我还必须进入docker容器和项目所在的虚拟环境。在弄清楚之前,这让我感到困惑-因为我收到了以下docker错误信息。

read unix @->/var/run/docker.sock: read: connection reset by peer

这可能是由文件/var/lib/docker/network/files/local-kv.db引起的。我不知道这种说法的准确性:但是我认为我看到了这个错误,因为我没有在本地使用docker,因此没有这个文件,而Forth的答案却需要这个文件。

然后,我导航到正确的目录(与项目一起),激活虚拟环境,然后运行接受的答案。嘭,像顶部一样工作。希望这能帮助其他人!


3
(https://github.com/kelda/dksnap) 可以自动运行并通过加载转储的过程。

它会显示正在运行的容器列表,您可以选择要备份哪个容器。生成的工件是常规的Docker镜像,因此您可以使用运行它,或者将其推送到Docker注册表中进行共享。

(免责声明:我是该项目的维护者)


太好了!期待着“一个不带图形界面但可编写脚本的CLI接口。”这样我就可以在机器人框架测试中使用它 :) - Wlad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接