@Docker:Docker Captain @nickjanetakis 发布了一篇关于在 Docker 中备份 PostgreSQL 的精彩指南,涵盖本地存储及……

X AI KOLs Timeline 工具

摘要

Docker 分享了 Nick Janetakis 编写的一篇全面指南,介绍如何在 Docker 中备份 PostgreSQL,涵盖本地存储、S3 以及开源工具 Plakar,实现可靠的每日备份和恢复。

Docker Captain @nickjanetakis 发布了一篇关于在 Docker 中备份 PostgreSQL 的精彩指南,涵盖本地存储以及结合 S3 使用 Plakar。 了解更多:https://t.co/CGY3AbXfYL
查看原文
查看缓存全文

缓存时间: 2026/07/31 21:02

Docker Captain @nickjanetakis 发布了一篇关于在 Docker 中备份 PostgreSQL 的优秀指南,涵盖了本地存储以及如何利用 Plakar 配合 S3。

阅读更多:https://t.co/CGY3AbXfYL


如何在 Docker 中备份 PostgreSQL(本地、S3 和 Plakar)— Nick Janetakis

来源:https://nickjanetakis.com/blog/how-to-back-up-postgresql-in-docker-local-s3-and-plakar 更新于 2026 年 7 月 21 日,收录于#deployment (https://nickjanetakis.com/blog/tag/deployment-tips-tricks-and-tutorials)、#docker (https://nickjanetakis.com/blog/tag/docker-tips-tricks-and-tutorials)

how-to-back-up-postgresql-in-docker-local-s3-and-plakar.jpg

我们将介绍使用和不使用 Plakar 进行备份和恢复的方法,并展示如何在这个过程中省钱。

快速跳转:

    • 我 10 多年来如何备份数据库 (https://nickjanetakis.com/blog/how-to-back-up-postgresql-in-docker-local-s3-and-plakar#how-i-backed-up-my-databases-for-10-years) - Plakar 有什么帮助? (https://nickjanetakis.com/blog/how-to-back-up-postgresql-in-docker-local-s3-and-plakar#how-does-plakar-help) - 安装 Plakar (https://nickjanetakis.com/blog/how-to-back-up-postgresql-in-docker-local-s3-and-plakar#installing-plakar) - 使用 Plakar 进行每日数据库备份 (https://nickjanetakis.com/blog/how-to-back-up-postgresql-in-docker-local-s3-and-plakar#daily-database-backups-with-plakar) - 准备好使用 AWS 和 S3 (https://nickjanetakis.com/blog/how-to-back-up-postgresql-in-docker-local-s3-and-plakar#getting-ready-with-aws-and-s3) - 将 S3 存储与 Plakar 结合使用 (https://nickjanetakis.com/blog/how-to-back-up-postgresql-in-docker-local-s3-and-plakar#using-s3-storage-with-plakar) - 演示视频 (https://nickjanetakis.com/blog/how-to-back-up-postgresql-in-docker-local-s3-and-plakar#demo-video)

更喜欢视频?这里有一个 YouTube 上的演示视频 (https://nickjanetakis.com/blog/how-to-back-up-postgresql-in-docker-local-s3-and-plakar#demo-video)。

你存储在数据库中的数据非常重要。对大多数企业来说,数据就是一切,丢失数据可能会导致公司倒闭。不用说,备份是好事。

在这篇文章中,我们将专注于为自托管的 Web 应用创建可靠的每日备份,使用 PostgreSQL,并且所有内容都在 Docker 中运行。我们也会介绍恢复,因为恢复同样重要!

  • 不使用 Postgres?没关系,将命令换成 MySQL 很容易
  • 不使用 Docker?没问题,你可以很快调整这些命令
本教程实际上相当于 7 合 1 教程:
  • 如何仅使用 Postgres 和 cron 任务执行每日备份
  • 如何将数据库备份到文件系统或 S3 存储桶
  • 如何仅使用 Postgres 从备份中恢复数据库
  • 理解免费且开源的 (https://github.com/PlakarKorp/plakar) Plakar (https://www.plakar.io/) 版本如何帮你省钱
  • 一个关于如何使用 Plakar 进行本地和 S3 存储的速成课程;Plakar 也支持除 S3 之外的其他存储引擎,稍后会详细说明!
  • 如何使用 Plakar 执行每日备份
  • 如何使用 Plakar 恢复数据库

我对使用第三方工具非常怀疑,尤其是在备份这样重要的事情上,但 Plakar 有许多有趣的功能,可以帮助降低复杂性,节省时间和金钱。

# (https://nickjanetakis.com/blog/how-to-back-up-postgresql-in-docker-local-s3-and-plakar#how-i-backed-up-my-databases-for-10-years)我 10 多年来如何备份数据库

也许你的经历与此类似?这是一个相当常见的设置。每天将数据库 dump 并 gzip 到挂载的磁盘卷或 S3 存储桶。

在运行 PostgreSQL 的 Docker 服务器上,我会配置一些基本的东西。

执行备份的脚本

在本文中,我将使用这个示例 Docker 化 Web 应用 https://github.com/nickjj/docker-flask-example,因为它包括运行 Web 服务器、PostgreSQL 等。我稍微扩展了它,将 Web 请求记录到数据库表中。

你可以随意使用任何项目,因为这里唯一适用的就是让 Postgres 运行在容器中,并且有办法向表中添加行。这些脚本不会与这个特定项目耦合。

一个预期是数据库容器已经在运行。我们将exec进入它并运行备份命令。通常这意味着你已经在某个地方通过docker compose up启动了一切。如果它还没有运行,你可以在脚本中用run替换exec

这个脚本会保存到服务器上的/usr/local/bin/pgbackup,或者如果你想在本地测试所有内容,也可以放在开发机上的任何位置。不要忘记chmod +x /usr/local/bin/pgbackup使其可执行:

`` #!/usr/bin/env bash

Create a full gzipped database backup.

Usage:

pgbackup myapp

pgbackup myapp –today

set -o errexit set -o pipefail set -o nounset

PROJECT=“{1}" FLAG="{2:-}” DATE=“”

[ “{FLAG}" = "--today" ] && DATE="-(date +%F)”

BACKUP_PATH=“{HOME}/db-backups" BACKUP_FILE="{PROJECT}{DATE}.sql.gz" BACKUP_TMP_FILE="{BACKUP_PATH}/${BACKUP_FILE}.tmp”

Ensure the temp file is deleted when this script exits.

trap ‘rm -f “${BACKUP_TMP_FILE}”’ EXIT

mkdir -p “${BACKUP_PATH}”

docker compose exec –no-tty postgres pg_dumpall –username “{PROJECT}" | gzip >"{BACKUP_TMP_FILE}” mv “{BACKUP_TMP_FILE}" "{BACKUP_PATH}/${BACKUP_FILE}” ``

上面的脚本并不是太复杂。它使用pg_dumpall创建数据库的完整 dump,并且为了保持脚本通用性,支持传入项目名称,因为你可能正在备份多个项目。

使用压缩来大幅减小文件大小。具体节省多少取决于你的数据,但将大小减半是常见的。

备份策略:

日期是可选的,因为如果你只需要 1 天的备份,你会覆盖没有日期的文件。

否则,你可以传入--today-YYYY-MM-DD将会被添加到文件名中,以防你想保留一周的备份等。

有弹性的备份:

鉴于上述情况,一个重要的步骤是先写入临时文件,然后移动到最终目标。这是因为使用 shell 的>重定向会在管道启动前立即截断文件!如果备份中途失败,我们不希望部分备份覆盖上次正常工作的备份。如果你好奇的话,tee也有同样的问题。我过去写过关于这种模式的文章 (https://nickjanetakis.com/blog/watch-out-for-data-loss-when-redirecting-to-a-file-in-a-shell-script)。

上面的方法将你的数据备份到运行该命令的同一台机器上的磁盘中。

备份路径可以是存在于不同机器上的块存储卷,也可以是网络挂载,这取决于你。这就是为什么临时文件被写入备份路径的原因。这是为了确保mv命令通过将临时文件保存在与真实文件相同的文件系统上来执行原子重命名。

改用 S3:

你可以通过将其管道传输到 AWS CLI 来直接流式传输到你的存储桶。

不需要临时文件和mv操作,因为只有在上传完成时才会创建成功的对象。如果管道中的任何部分失败,set -o errexitset -o pipefail确保脚本以错误退出:

... | gzip | aws s3 cp - "s3://your_bucket_goes_here/${BACKUP_FILE}"

这里的一个预期是你已经创建了一个名为your_bucket_goes_here的存储桶,并且运行此命令的用户已经配置了~/.aws/credentials,具有足够的访问权限来在存储桶中创建对象。

我们将在本文后面使用 Plakar 时介绍设置存储桶和用户的 AWS 密钥,但这里也可以使用相同的凭据。

自动化备份

脚本就绪后,我们可以运行每日 cron 任务。这里设置为以deploy用户身份运行,该用户也是运行 Docker 命令的用户,例如docker compose up --detach或你启动项目的任何操作。

它在服务器配置的任何时区的 6:00 运行。我将其设置为 UTC。

这将保存到/etc/cron.d/pgbackup-hello

0 6 * * * deploy /usr/local/bin/pgbackup hello

在这种情况下,“hello”是被备份的项目。

到目前为止还不错。我们有每日备份,每天覆盖彼此。

自动清理

如果你使用--today生成-YYYY-MM-DD作为文件名的一部分,那么每天都会创建一个新文件。如果你只想保留最近 7 天,那么你可以删除 deploy 用户备份目录中超过 7 天的文件。

另一个 cron 任务将保存到/etc/cron.d/delete-old-db-backups

0 8 * * * deploy /usr/bin/find /home/deploy/db-backups -type f -name "*.sql.gz" -mtime +7 -delete

上面的命令采取了额外的预防措施,只删除 gzip 压缩的 SQL dump。你可以使用-name "hello*.sql.gz"进一步限制为特定项目名称,但提供的原始方法允许用一个 cron 任务清理所有备份。

如果你使用 S3 而不是本地文件,你可以设置 S3 生命周期策略来删除超过 7 天的对象。

在创建此生命周期规则时(在存储桶的管理下)。在名称下,你可以将其范围限定为存储桶中的所有对象或进行过滤。如果你有一个专门用于备份的存储桶,可以随意选择所有对象。

然后确保勾选下面两个生命周期规则操作:

  • “Expire current versions of objects”(过期当前版本的对象)- 设置为 7 天或你想保留的备份数量
  • “Delete expired object delete markers or incomplete multipart uploads”(删除过期的对象删除标记或不完整的多段上传)- 勾选“Delete incomplete multipart uploads”(删除不完整的多段上传),时间为 1 天

上面确保旧文件以及部分/失败的上传被删除。

恢复数据

能够从备份中恢复是拼图的第二块。如果你有一个全新的数据库,比如在运行docker compose down -v清除卷之后,或者你正在新机器上进行设置,那么你就可以恢复了。

这个脚本将保存到服务器上的/usr/local/bin/pgrestore

`` #!/usr/bin/env bash

Restore a gzipped database backup.

Usage:

pgrestore myapp

pgrestore myapp YYYY-MM-DD

set -o errexit set -o pipefail set -o nounset

PROJECT=“{1}" DATE="{2:-}”

[ -n “{DATE}" ] && DATE="-{DATE}”

BACKUP_PATH=“{HOME}/db-backups" BACKUP_FILE="{PROJECT}${DATE}.sql.gz”

gunzip -c “{BACKUP_PATH}/{BACKUP_FILE}” | docker compose exec –no-tty postgres psql –username “${PROJECT}” ``

如果传入了日期,我们需要调整它,使其包含-,因为传入的将是YYYY-MM-DD。这是因为在我们的备份脚本中,我们以这种方式输出文件。

由于这是一个 gzip 压缩的文件,我们不能用< ${BACKUP_FILE}将其发送到psql,而是使用gunzip解压缩并通过管道传输到psql

这将把你的数据库恢复到备份文件中的任何状态。此时你就可以继续前行了,希望能重回正轨!

这种方法效率不高之处

每天都会执行完整的 SQL dump。虽然它确实使用压缩来节省成本,但你每天都会将整个 gzip 压缩的 SQL 文件传输到 S3,即使每天之间只有 1% 的数据发生了变化。

根据你在数据库中保存的内容和数据量,可能是几百 MB 或几 GB,但没有限制对吧?也许你有 2 TB,因为你有很多数据。

增量备份 / 恢复呢?

PostgreSQL 17+ 支持增量备份 (https://www.postgresql.org/docs/current/continuous-archiving.html)和用于恢复的 pg_combinebackup (https://www.postgresql.org/docs/current/app-pgcombinebackup.html)。这超出了本文的范围,但如果你想要更细粒度的备份,比如能够进行时间点恢复到特定时间点,那么你可以了解一下。

设置起来有点复杂,尤其是在恢复方面。然而,有一些工具,如 https://github.com/pgbackrest/pgbackrest,可以让这个过程更容易设置。

也许我下次会更详细地介绍这个,如果你想看到的话,请在下面的评论中告诉我。就个人而言,每日备份加上恢复手段,在我自己和客户的许多不同项目中,处理数百万行数据时已经非常有用了。

无论如何,了解我们上面介绍的基础知识,是引入更复杂的增量备份和恢复的很好的踏脚石,如果你决定需要的话。

# (https://nickjanetakis.com/blog/how-to-back-up-postgresql-in-docker-local-s3-and-plakar#how-does-plakar-help)Plakar 有什么帮助?

对于每日备份来说,它非常有用!

在我看来,最大的优势是它在备份之间进行数据去重。你只需要发送每天变化的内容,Plakar 在内部管理一切,所以你可以说“给我最新的快照”或“给我 3 天前的快照”。它还会生成一个文件,你可以从该文件恢复数据库。

具体示例

我们需要一些东西来比较两种解决方案。

假设你想在 S3 中保留一周的备份(7 天)。在估算成本时,我们将分别计算不使用 Plakar 和使用 Plakar 的情况。

假设你 gzip 压缩的数据库 dump 是 10 GB,每天你大约添加 100 MB 新的 gzip 压缩数据。这大约是每天增长 1%。

P.S.,即使你只想保留 1 天的备份,Plakar 仍然有价值,因为你很快就会看到 Plakar 如何让你执行增量备份,而无需每天传输整个 dump。在考虑数据传输成本时请记住这一点。

不使用 Plakar

以下是 dump 并发送到 S3 的内容:

  • 第 1 天:10.00 GB
  • 第 2 天:10.10 GB
  • 第 3 天:10.20 GB
  • 第 4 天:10.30 GB
  • 第 5 天:10.40 GB
  • 第 6 天:10.50 GB
  • 第 7 天:10.61 GB

在 7 天结束时,已经发送和存储了72.11 GB

现在假设这种情况持续一年,在这一年中,由于你的业务正在增长,你的数据库增长已从 1% 线性上升到 2%。

这里有几个数字:

  • 第 90 天:20.00 GB
  • 第 180 天:32.33 GB
  • 第 270 天:46.88 GB
  • 第 365 天:64.65 GB

这攀升得非常快。如果你把一年内发送到 S3 的所有数据加起来,大约会有 ~12.5 TB。

幸运的是,向 S3 发送数据是免费的,所以我们不必为此付费,但如果你从云提供商发送数据,他们可能会收取到 S3 或更普遍地到互联网的出站数据传输费。

如果你在 AWS 上,并且你的 EC2 实例在同一区域,这是免费的,但要小心,如果你的实例附加了 NAT 网关。你肯定想要设置一个 S3 Gateway Endpoint (https://docs.aws.amazon.com/vpc/latest/privatelink/vpc-endpoints-s3.html) 来避免 NAT 网关费用,否则费用会很高!每 GB 0.045 美元。仅这一年的 ~12.5 TB 就大约需要 563 美元。不要跳过这一点。

在第 1 年结束时,仅存储费用大约为每月 10 美元。这基于大约 ~455 GB(65 x 7)以滚动 7 天方式存储。按 S3 Standard 费率(0.023 美元(us-east-2))计算,略高于 10 美元。

此计算中使用了 S3 Standard,因为大多数 Infrequent Access 或 Glacier 选项要求最短存储天数,例如 30-90 天,这与我们的 7 天数量冲突。而且,有时你需要很长的检索时间,但如果你需要恢复生产数据,通常需要“立即”恢复。

顺便说一句,如果你将备份保存在磁盘上而不是 S3 上,那么一年后,你只需要大约 455 GB 的可用空间来存储这 7 天的备份。

长话短说,第 1 年只是开始。一开始看起来还不错,但随着时间的推移,发送到 S3 的总数据量会越来越多,存储成本也会快速增长。这就是 Plakar 的用武之地。

相似文章

初创公司的PostgreSQL生存指南

Hacker News Top

一份面向在生产环境中运行PostgreSQL的初创公司的全面指南,涵盖模式设计、查询优化、索引、迁移、连接管理,以及查询计划与分区等高级主题。

大规模并行 Postgres 备份

Hacker News Top

PlanetScale 描述了它如何通过为每个分片启动 EC2 实例、从对象存储恢复之前的备份并重放 WAL,来对分片 Postgres 数据库执行大规模并行备份,从而实现超过 50 GB/s 的 PB 级备份速度。

Postgres by Example

Hacker News Top

一份使用带注释的SQL示例的PostgreSQL实践入门,涵盖从基础到高级主题。