3. 单实例 PostgreSQL 容器搭建:docker run 命令详解、端口映射、数据持久化卷挂载
在 Mock 依赖隔离测试环境中,PostgreSQL 实例通常以 Docker 容器形式运行。本章聚焦于单实例 PostgreSQL 容器的搭建,深入解析 docker run 命令的核心参数,重点覆盖端口映射与数据持久化卷挂载两个关键配置。掌握这些基础操作,是构建可重复、可迁移的测试数据库环境的前提。
3.1 核心命令结构
一个典型的单实例 PostgreSQL 容器启动命令如下:
docker run -d \
--name pg-test \
-e POSTGRES_USER=testuser \
-e POSTGRES_PASSWORD=testpass \
-e POSTGRES_DB=testdb \
-p 5432:5432 \
-v pgdata:/var/lib/postgresql/data \
postgres:16-alpine
该命令各参数的作用如下表所示:
| 参数 | 作用 | 测试环境推荐值 |
|---|---|---|
-d |
后台运行容器(detached 模式) | 始终使用 |
--name |
为容器指定名称,便于管理 | pg-test 或按项目命名 |
-e |
设置环境变量,传递配置到容器内 | 至少设置用户、密码、数据库名 |
-p |
端口映射:宿主机端口:容器端口 | 避免与已有服务冲突 |
-v |
卷挂载:宿主机路径或卷名:容器路径 | 使用命名卷或绑定挂载 |
postgres:16-alpine |
镜像名称与标签 | 使用 Alpine 版本减小体积 |
postgres:16-alpine 镜像。Alpine 版本体积小(约 120MB),启动快,且包含完整的 PostgreSQL 功能,适合 CI/CD 和本地开发测试。
3.2 端口映射详解
端口映射通过 -p 参数实现,格式为 宿主机IP:宿主机端口:容器端口。在测试环境中,端口映射的主要目的是让宿主机上的测试程序能够访问容器内的 PostgreSQL 服务。
常见的端口映射场景:
- 默认映射:
-p 5432:5432—— 将宿主机的 5432 端口映射到容器的 5432 端口。适用于宿主机上无其他 PostgreSQL 服务的情况。 - 自定义端口:
-p 15432:5432—— 将宿主机的 15432 端口映射到容器的 5432 端口。适用于宿主机已有 PostgreSQL 占用 5432 端口,或需要运行多个测试实例的场景。 - 绑定特定 IP:
-p 127.0.0.1:5432:5432—— 仅允许本地回环地址访问,增强安全性。在 Mock 测试环境中,通常推荐此方式,避免外部网络意外连接。
-p 5432:5432 会导致容器启动失败。建议在启动前使用 ss -tlnp | grep 5432 检查端口占用情况。
3.3 数据持久化卷挂载
PostgreSQL 的数据文件默认存储在容器内的 /var/lib/postgresql/data 目录。如果不进行卷挂载,容器删除后数据将永久丢失。在测试环境中,数据持久化卷挂载有两个核心用途:
- 数据持久化: 容器重启或重建后,测试数据依然保留。
- 性能优化: 将数据目录挂载到宿主机 SSD 或内存盘上,提升测试执行速度。
Docker 支持两种卷挂载方式:
| 挂载方式 | 语法示例 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|---|
| 命名卷 | -v pgdata:/var/lib/postgresql/data |
多容器共享数据、生产级持久化 | 由 Docker 管理,跨主机迁移方便 | 数据位置不直观,调试较麻烦 |
| 绑定挂载 | -v /host/path:/var/lib/postgresql/data |
本地开发、需要直接查看数据文件 | 数据路径透明,可直接访问 | 依赖宿主机路径,可移植性差 |
-v pg-test-data:/var/lib/postgresql/data。这样可以在不同测试会话间保持数据一致性,且清理时只需 docker volume rm pg-test-data 即可完全清除。
3.4 容器启动流程与数据初始化
下图展示了从 docker run 执行到 PostgreSQL 服务就绪的完整流程:
从流程图中可以看出:当卷挂载路径下的数据目录为空时,PostgreSQL 容器会自动执行 initdb 初始化数据库集群,并根据环境变量创建用户和数据库;如果数据目录已存在有效数据,则直接启动服务,跳过初始化步骤。这一机制使得测试数据可以在容器生命周期之外持久保留。
3.5 环境变量配置
PostgreSQL 官方镜像支持多个环境变量,用于在首次初始化时配置数据库。在 Mock 测试环境中,最常用的环境变量如下:
| 环境变量 | 默认值 | 说明 | 测试环境建议 |
|---|---|---|---|
POSTGRES_USER |
postgres |
创建超级用户 | 设置为 testuser 避免使用默认名 |
POSTGRES_PASSWORD |
无(必须设置) | 超级用户密码 | 测试环境使用简单密码如 testpass |
POSTGRES_DB |
与 POSTGRES_USER 相同 |
创建初始数据库 | 设置为 testdb 明确测试数据库 |
PGDATA |
/var/lib/postgresql/data |
数据目录路径 | 通常无需修改,保持默认 |
docker run 命令中直接明文写入密码到脚本历史记录中,建议使用 --env-file 参数从文件读取环境变量。
3.6 完整启动示例与验证
以下是一个完整的单实例 PostgreSQL 容器启动与验证流程:
# 1. 创建命名卷
docker volume create pg-test-data
# 2. 启动容器
docker run -d \
--name pg-test \
-e POSTGRES_USER=testuser \
-e POSTGRES_PASSWORD=testpass \
-e POSTGRES_DB=testdb \
-p 127.0.0.1:5432:5432 \
-v pg-test-data:/var/lib/postgresql/data \
postgres:16-alpine
# 3. 检查容器状态
docker ps --filter name=pg-test
# 4. 查看容器日志(确认初始化完成)
docker logs pg-test | tail -10
# 5. 连接测试
docker exec -it pg-test psql -U testuser -d testdb -c "SELECT version();"
# 6. 验证数据持久化(停止并删除容器后重建)
docker stop pg-test && docker rm pg-test
docker run -d \
--name pg-test-restored \
-e POSTGRES_USER=testuser \
-e POSTGRES_PASSWORD=testpass \
-e POSTGRES_DB=testdb \
-p 127.0.0.1:5432:5432 \
-v pg-test-data:/var/lib/postgresql/data \
postgres:16-alpine
docker exec -it pg-test-restored psql -U testuser -d testdb -c "SELECT version();"
上述步骤中,第 6 步验证了数据持久化的效果:即使容器被删除,只要卷 pg-test-data 未被删除,重新启动新容器并挂载同一卷后,数据依然完整可用。
3.7 常见问题与排查
- 容器启动后立即退出: 检查日志
docker logs <container_name>,常见原因包括端口冲突、卷权限问题、环境变量缺失。 - 权限错误: 如果使用绑定挂载,宿主机目录的属主和权限必须正确。PostgreSQL 容器内进程以 UID 999(postgres 用户)运行,宿主机目录需确保该 UID 有读写权限。
- 数据目录非空冲突: 如果挂载的卷中已存在数据,但数据格式与当前 PostgreSQL 版本不兼容,容器会启动失败。此时需要清理卷数据或使用兼容的镜像版本。
- 连接被拒绝: 检查端口映射是否正确,确认
pg_hba.conf配置是否允许远程连接(测试环境通常默认允许本地连接)。
docker inspect pg-test | grep -A 10 Mounts 查看卷挂载详情;使用 docker port pg-test 查看端口映射状态;使用 docker stats pg-test 监控容器资源使用。