【问题标题】:Persisting a single, static, large Postgres database beyond removal of the db cluster?除了删除数据库集群之外,还保留一个静态的大型 Postgres 数据库吗?
【发布时间】:2025-12-02 11:20:05
【问题描述】:

我有一个应用程序,用于本地开发,有多个 Docker 容器(在 Docker Compose 下组织)。其中一个容器是 Postgres 10 实例,基于官方 postgres:10 图像。该实例将其数据目录挂载为 Docker 卷,该卷在容器运行中持久保存数据。到目前为止一切都很好。

作为测试 postgres 集群的创建和初始化的一部分,我经常需要删除保存数据的 Docker 卷。 (官方的 postgres 镜像运行 cluster init if-and-only-如果在容器启动时发现数据目录为空。)这也可以。

但是!我现在有一种情况,为了测试和使用第三方 Postgres 扩展,我需要从 Postgres 备份转储文件将大约 6GB(完全静态)地理编码查找数据加载到集群上的数据库中。当然可以在容器启动时从本地挂载点加载数据,并且生成的(非常大的)表将在容器重新启动后保留在包含整个集群的卷中。

不幸的是,它们无法在 docker 卷被移除后幸存下来,这同样需要以一定的频率发生。 我正在寻找一种方法来加快或避免重建保存地理编码数据的单个数据库。

我曾经或目前正在考虑的方法:

  1. 在同一容器上使用单独的 Docker 卷为仅包含地理编码器数据库的单独 Postgres 表空间创建持久存储。这似乎是行不通的,因为虽然我可以肯定地设置它,但官方 PG 文档说表空间和集群是密不可分的,因此集群其余部分的丢失会导致额外的表空间无法使用。我很想错了,因为这似乎是最简单的解决方案。
  2. 创建一个运行 Postgres 的完全独立的容器,该容器安装一个卷来保存一个仅包含地理编码数据的单独集群。大概我需要对外部数据包装器(或一些我目前不知道的更神秘的 postgres 管理技巧)做一些笨拙的事情,以使数据可以从应用程序代码无缝访问。

所以,我的问题是:有没有人知道一种方法可以从 dockerized Postgres 集群中持久化单个数据库,而不使用转储和重新加载策略?

【问题讨论】:

  • 就我个人而言,我可能会制作一个“postgres + 扩展”docker 镜像并运行它。您可以为映像挂载 6gb 数据卷的副本,并让它从那时起发生变异。
  • 数据不会发生变异——它完全是静态的。集群的所有其他部分都有可能根据集群初始化期间发生的情况而发生变化,但是无论随后发生什么,这个大型数据库都将是相同的。这就是为什么我希望能够只保留一个数据库但能够以其他方式破坏主数据目录。

标签: postgresql docker docker-volume postgresql-10 tablespace


【解决方案1】:

如果您想加快速度,则可以将数据库转储转换为数据目录(将转储导入干净的 postgres 容器,停止它并创建数据目录的 tarball,然后将其上传到某处)。现在当你需要创建一个新的 postgres 容器时,使用初始化脚本来停止数据库,下载并解压你的 tarball 到数据目录并再次启动数据库,这样你就可以跳过整个数据库恢复过程。

注意:data tarball 必须与 postgres 主要版本匹配,因此容器从它启动没有问题。

如果您想进一步加快速度,请创建一个自定义 postgres 映像,并捆绑 tarball 和 init 脚本,这样每次启动时它都会擦除空集群并复制您自己的。

您甚至可以更改入口点以使用您的自定义脚本并加载数据库数据,然后调用 docker-entrypoint.sh,这样就无需删除可能的空集群。

这只有在您每次想运行测试时都可以更换整个集群时才有效,否则您将无法导入数据库转储。

【讨论】:

  • 归档数据目录并没有帮助,因为它还将包含 Postgres 集群的所有其他部分。这些是我需要清除的部分,以便我可以强制容器从我的 initdb.d 脚本重建集群。
  • 是的,我的回答假设您可以准备一个数据目录,其中只有数据库上的地理编码数据而没有其他内容,这意味着事先转换您的数据库转储。 Postgres 并不真正支持为单个数据库导入部分表空间。