1473 字
7 分钟
将 PostgreSQL 从 Docker 迁移到宿主机并供容器服务访问

一、背景#

随着服务器部署的服务越来越多,今天安装新服务时突然意识到,很多服务都依赖 PostgreSQL 数据库。

并且每个服务都拥有自己的 PostgreSQL 容器,这导致服务器上存在多个数据库实例,占用了较多的内存资源,同时也增加了后续维护和备份的成本。

因此思考了一番打算将原 Docker 中运行的 PostgreSQL 数据通过 dump 导出,然后在宿主机统一安装 PostgreSQL,让 Docker 容器中的各个服务访问宿主机的 PostgreSQL。

这样可以减少重复运行数据库带来的资源浪费,同时方便后续数据库的统一管理。

二、安装 PostgreSQL 以及相关工具#

由于 Docker 容器中的环境通常比较精简,缺少部分数据库管理工具,无法直接进行数据备份操作。

因此,先通过 PostgreSQL 官方仓库在宿主机安装 PostgreSQL 以及相关工具。

具体安装方式可以参考 PostgreSQL 官方文档:https://www.postgresql.org/download/

三、备份容器中的数据#

由于不同 PostgreSQL 镜像的内容有所区别,部分精简版镜像中可能没有安装 pg_dump 等数据库备份工具,因此需要根据实际情况选择备份方式。

方式一:容器中存在 pg_dump 工具#

首先进入 PostgreSQL 容器:

Terminal window
docker exec -it <postgres-container-name> bash

检查是否存在 pg_dump

Terminal window
which pg_dump

如果可以正常找到路径,则可以直接进行数据库备份:

Terminal window
pg_dump -U <username> -d <database_name> > backup.sql

也可以直接在宿主机执行:

Terminal window
docker exec <postgres-container-name> pg_dump -U <username> -d <database_name> > backup.sql

方式二:容器中没有 pg_dump 工具#

如果进入容器后发现没有 pg_dump

Terminal window
which pg_dump

没有返回结果,说明当前容器环境缺少 PostgreSQL 客户端工具。

这种情况下,不需要在容器内额外安装工具,可以直接使用宿主机安装的 PostgreSQL 客户端进行备份。

首先确认宿主机存在 pg_dump

Terminal window
pg_dump --version

然后通过容器端口连接 PostgreSQL:

Terminal window
pg_dump -h 127.0.0.1 -p <port> -U <username> -d <database_name> > backup.sql

如果 PostgreSQL 容器没有映射端口,也可以通过 Docker 网络连接:

Terminal window
pg_dump -h <container-ip> -p 5432 -U <username> -d <database_name> > backup.sql

备份完成后检查文件:

Terminal window
ls -lh backup.sql

确认备份文件正常生成。

四、恢复数据到宿主机 PostgreSQL#

完成数据备份后,需要将原 Docker 中的 PostgreSQL 数据恢复到宿主机安装的 PostgreSQL 中。

首先需要在宿主机 PostgreSQL 中创建对应的用户和数据库。

创建用户:

Terminal window
createuser -U postgres <username>

创建数据库:

Terminal window
createdb -U postgres -O <username> <database_name>

恢复备份:

Terminal window
psql -U <username> -d <database_name> < backup.sql

恢复完成后,可以登录 PostgreSQL 检查数据:

Terminal window
psql -U <username> -d <database_name>

查看数据库表:

Terminal window
\dt

确认数据恢复正常。

五、配置 PostgreSQL 访问权限#

由于 PostgreSQL 对客户端访问有权限控制,而迁移后 Docker 服务访问数据库的方式发生了变化。

原本 PostgreSQL 运行在 Docker 容器内部,服务之间通过 Docker 网络进行访问。

迁移到宿主机后,Docker 容器需要通过 Docker bridge 网关地址访问宿主机上的 PostgreSQL 服务。

因此需要重新配置 PostgreSQL 的监听地址以及访问权限。

5.1 获取 Docker 网桥地址#

Docker 容器访问宿主机网络,需要通过 Docker 网桥的网关地址。

如果使用普通 Docker 容器,可以通过以下命令查看:

Terminal window
docker network inspect bridge

查看输出中的:

"Gateway": "172.17.0.1"

该地址即为 Docker 容器访问宿主机的网关地址。

如果使用 Docker Compose 创建的自定义网络,可以先查看网络名称:

Terminal window
docker network ls

然后执行:

Terminal window
docker network inspect <network-name>

查看对应的 Gateway 地址。

例如:

172.18.0.1

5.2 配置 PostgreSQL 监听地址#

主要涉及两个配置文件(以Debian系为例):

  • postgresql.conf
  • pg_hba.conf

默认情况下,PostgreSQL 通常只监听本机地址:

listen_addresses = 'localhost'

这样 Docker 容器无法直接访问宿主机 PostgreSQL。

修改配置文件:

Terminal window
vim /etc/postgresql/<version>/main/postgresql.conf

找到:

listen_addresses = 'localhost'

修改为限制只监听本地地址和 Docker 网桥地址:

listen_addresses = '127.0.0.1,172.17.0.1,172.18.0.1'

5.3 配置 pg_hba.conf 允许 Docker 网络访问#

修改:

Terminal window
vim /etc/postgresql/<version>/main/pg_hba.conf

增加 Docker 网段访问规则:

host all all 172.17.0.0/16 scram-sha-256
host all all 172.18.0.0/16 scram-sha-256

5.4 重启 PostgreSQL#

修改配置后,需要重新加载配置:

Terminal window
systemctl restart postgresql

确认 PostgreSQL 是否监听 Docker 地址:

Terminal window
ss -lntp | grep 5432

正常情况下可以看到:

LISTEN 0 200 127.0.0.1:5432
LISTEN 0 200 172.17.0.1:5432
LISTEN 0 200 172.18.0.1:5432

完成以上配置后,Docker 容器已经具备访问宿主机 PostgreSQL 的基础条件。

六、仍然无法访问的问题排查#

按照上述配置完成 PostgreSQL 监听地址和访问权限设置后,服务仍然无法连接数据库。

但是通过 Docker 容器测试,可以正常 ping 通宿主机地址:

Terminal window
ping 172.18.0.1

说明:

  • Docker 网络正常
  • 容器可以访问宿主机

但是数据库连接仍然失败,因此继续排查 TCP 端口访问情况。

使用 nc 测试 PostgreSQL 端口:

Terminal window
nc -vz 172.18.0.1 5432

发现连接一直等待,没有返回结果。

这说明问题并不是 PostgreSQL 配置,而是 TCP 5432 端口访问被阻断。

检查宿主机防火墙:

Terminal window
ufw status verbose

发现 ufw 默认拒绝转发流量:

Default: deny (routed)

由于 Docker 容器访问宿主机 PostgreSQL 属于 Docker 网桥网络转发流量,因此被 ufw 拦截。

放行 Docker 网段访问 PostgreSQL:

Terminal window
ufw allow from 172.17.0.0/16 to any port 5432 proto tcp
ufw allow from 172.18.0.0/16 to any port 5432 proto tcp

由于 Docker 容器访问宿主机属于转发流量,还需要允许路由转发:

Terminal window
ufw route allow from 172.17.0.0/16 to any port 5432 proto tcp
ufw route allow from 172.18.0.0/16 to any port 5432 proto tcp

重新加载防火墙配置:

Terminal window
ufw reload

再次测试:

Terminal window
nc -vz 172.18.0.1 5432

如果返回:

172.18.0.1:5432 open

说明 Docker 容器已经可以正常访问宿主机 PostgreSQL。

将 PostgreSQL 从 Docker 迁移到宿主机并供容器服务访问
https://www.self4m.com/posts/docker-connect-host-postgresql-config/
✍️作者
Self4m
📅发布于
2026-07-11
©️许可协议
CC BY-NC-SA 4.0

商业用途必须事先获得作者授权;
非商业用途可以使用,但必须注明出处;
若有改编需采用相同许可协议发布。