本文从最基础的单命令启动,到生产级 Compose 编排,逐层拆解参数原理、数据持久化、账号管理、远程访问等核心知识点,新手可照抄落地,老手可查漏补缺。
0. 前言与前置准备
Docker 部署 PostgreSQL 是开发、测试、生产环境最常用的方案之一,核心优势在于:
- 环境一致性:彻底解决「我本地能跑,服务器上不行」的问题
- 秒级部署:一条命令启动实例,版本切换无成本
- 隔离性强:多版本、多实例互不干扰
- 运维简单:数据持久化、备份、迁移标准化
前置条件
- 已安装 Docker(建议 20.10+)
- 已安装 Docker Compose v2(建议 2.20+)
- 服务器 / 本地已开放对应端口(默认 5432)
本文所有命令均基于 PostgreSQL 16 最新 LTS 版本演示,兼容 12/13/14/15 全系列。
一、方案一:docker run 单命令部署
适合快速测试、临时实例、单节点快速启动场景。
1.1 最简启动命令(仅用于测试,不推荐生产)
bash
docker run -d --name postgres-test -p 5432:5432 -e POSTGRES_PASSWORD=123456 postgres:16
⚠️ 警告:此命令无数据持久化,容器删除数据全部丢失,仅适合临时测试。
1.2 生产级完整启动命令(推荐)
bash
docker run -d \
--name postgres-prod \
--restart=unless-stopped \
-p 5432:5432 \
-e POSTGRES_USER=admin \
-e POSTGRES_PASSWORD=Admin@2024 \
-e POSTGRES_DB=my_database \
-e TZ=Asia/Shanghai \
-e PGDATA=/var/lib/postgresql/data/pgdata \
-v /opt/postgres/data:/var/lib/postgresql/data \
-v /opt/postgres/conf/pg_hba.conf:/etc/postgresql/pg_hba.conf \
-v /opt/postgres/conf/postgresql.conf:/etc/postgresql/postgresql.conf \
--memory=2G \
--cpus=2 \
postgres:16 \
-c 'config_file=/etc/postgresql/postgresql.conf' \
-c 'hba_file=/etc/postgresql/pg_hba.conf'
1.3 全参数硬核拆解
| 参数 | 作用说明 | 生产建议 |
|---|---|---|
-d |
后台守护进程运行容器 | 必加 |
--name postgres-prod |
给容器指定唯一名称,方便管理 | 建议按「业务 - 版本 - 环境」命名 |
--restart=unless-stopped |
容器重启策略 | 生产必选,Docker 重启 / 宿主机重启后自动拉起 |
-p 5432:5432 |
端口映射,格式「宿主机端口:容器内部端口」 | 生产可修改宿主机端口降低攻击面,如 -p 15432:5432 |
-e POSTGRES_USER=admin |
指定初始超级用户名,默认 postgres |
生产建议自定义,不使用默认名 |
-e POSTGRES_PASSWORD=Admin@2024 |
初始超级用户密码,必填参数 | 生产必须使用强密码,包含大小写 + 数字 + 特殊字符 |
-e POSTGRES_DB=my_database |
初始自动创建的数据库名,默认和用户名一致 | 业务库可提前创建,省去后续手动建库步骤 |
-e TZ=Asia/Shanghai |
设置容器时区为东八区 | 必加,否则默认 UTC 时间,和国内差 8 小时 |
-e PGDATA=/var/lib/postgresql/data/pgdata |
指定 PostgreSQL 数据文件存储目录 | 挂载宿主机目录时建议加,避免直接挂载到 data 根目录引发权限问题 |
-v /opt/postgres/data:/var/lib/postgresql/data |
数据持久化核心,格式「宿主机目录:容器目录」 | 生产必配,将数据文件映射到宿主机,容器删除数据不丢失 |
-v 配置文件挂载 |
将 pg_hba.conf、postgresql.conf 映射到宿主机 | 生产建议,方便修改配置,不用进入容器 |
--memory=2G |
限制容器最大使用内存 | 生产建议限制,防止数据库占满宿主机资源 |
--cpus=2 |
限制容器最大使用 CPU 核数 | 按需配置,资源隔离 |
postgres:16 |
镜像名称 + 版本标签 | 生产必须指定具体版本,禁止使用 latest,避免版本漂移 |
-c 'config_file=xxx' |
启动时指定自定义配置文件路径 | 挂载外部配置文件时必加,让 PG 加载我们的配置 |
1.4 重启策略详解
--restart 有 4 种可选值,区别如下:
no:默认值,容器退出时不自动重启on-failure[:max-retries]:容器非正常退出(退出码非 0)时自动重启,可设置最大重试次数always:无论什么原因退出都自动重启,包括手动停止的容器,Docker 重启后也会自动拉起unless-stopped:最推荐生产使用,总是自动重启,但如果容器之前被手动停止了,Docker 重启后不会自动拉起
二、方案二:Docker Compose 编排部署
适合生产环境、多服务协同部署、配置需要版本化管理的场景,是企业级首选方案。
2.1 完整 docker-compose.yml 配置
创建 docker-compose.yml 文件,内容如下:
html
version: '3.8'
services:
postgres:
image: postgres:16-alpine
container_name: postgres-compose-prod
restart: unless-stopped
ports:
- "5432:5432"
environment:
POSTGRES_USER: admin # 超级用户名
POSTGRES_PASSWORD: Admin@2024 # 超级用户密码
POSTGRES_DB: my_database # 初始数据库
TZ: Asia/Shanghai # 时区
PGDATA: /var/lib/postgresql/data/pgdata # 数据目录
volumes:
# 数据持久化挂载
- ./data:/var/lib/postgresql/data
# 自定义配置文件挂载
- ./conf/postgresql.conf:/etc/postgresql/postgresql.conf
- ./conf/pg_hba.conf:/etc/postgresql/pg_hba.conf
# 初始化脚本挂载(第一次启动自动执行)
- ./init:/docker-entrypoint-initdb.d
# 资源限制
deploy:
resources:
limits:
cpus: '2'
memory: 2G
reservations:
cpus: '0.5'
memory: 512M
networks:
- pg-network
# 启动命令,指定自定义配置文件
command:
- -c
- config_file=/etc/postgresql/postgresql.conf
- -c
- hba_file=/etc/postgresql/pg_hba.conf
# 自定义网络,方便和其他服务(如pgadmin、业务服务)互通
networks:
pg-network:
driver: bridge
2.2 配置文件与初始化脚本
① 准备配置文件目录
在 docker-compose.yml 同级目录创建 conf、data、init 三个文件夹:
bash
mkdir -p conf data init
② 自定义 postgresql.conf
创建 conf/postgresql.conf,核心配置示例:
bash
# 监听地址,允许所有IP访问(配合pg_hba.conf使用)
listen_addresses = '*'
port = 5432
max_connections = 200
# 内存配置(根据宿主机内存调整,建议总内存的25%)
shared_buffers = 512MB
work_mem = 4MB
maintenance_work_mem = 128MB
# 日志配置
logging_collector = on
log_directory = 'log'
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
log_timezone = 'Asia/Shanghai'
# 时区
timezone = 'Asia/Shanghai'
datestyle = 'iso, mdy'
③ 客户端认证配置 pg_hba.conf
创建 conf/pg_hba.conf,控制哪些 IP 可以连接数据库:
bash
# TYPE DATABASE USER ADDRESS METHOD
# 本地unix套接字连接
local all all trust
# IPv4 本地回环
host all all 127.0.0.1/32 trust
# 允许所有IP用密码连接(生产建议限制IP段,如 192.168.1.0/24)
host all all 0.0.0.0/0 md5
# IPv6
host all all ::1/128 trust
⚠️ 生产环境禁止直接写
0.0.0.0/0,应限制为具体的业务服务器 IP 段,降低安全风险。
④ 初始化脚本(可选)
在 init 目录下放入 .sql 或 .sh 文件,仅在容器第一次启动、数据目录为空时自动执行,适合初始化表结构、创建普通用户、导入基础数据。
示例 init/01-init-user.sql:
bash
-- 创建普通业务用户
CREATE USER app_user WITH PASSWORD 'AppUser@2024';
-- 创建业务库
CREATE DATABASE app_db OWNER app_user;
-- 授予权限
GRANT ALL PRIVILEGES ON DATABASE app_db TO app_user;
2.3 Compose 常用运维命令
在 docker-compose.yml 所在目录执行:
bash
# 启动服务(后台运行)
docker compose up -d
# 查看服务状态
docker compose ps
# 查看日志(实时滚动)
docker compose logs -f postgres
# 停止服务(不删除容器)
docker compose stop
# 启动已停止的服务
docker compose start
# 重启服务
docker compose restart
# 停止并删除容器、网络(数据卷不会删)
docker compose down
# 停止并删除容器、网络、数据卷(⚠️ 数据会丢失,谨慎使用)
docker compose down -v
三、核心原理:数据持久化与初始化机制
3.1 为什么必须做数据持久化?
Docker 容器的文件系统是临时的,容器销毁时,内部所有数据都会一起删除。PostgreSQL 的数据默认存在容器内的 /var/lib/postgresql/data 目录下,必须通过 -v 卷挂载映射到宿主机,才能实现数据持久化。
3.2 两种挂载方式对比
表格
| 挂载方式 | 写法示例 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| 绑定挂载(宿主机目录) | -v /opt/pg/data:/var/lib/postgresql/data |
路径直观,方便备份、迁移、手动查看文件 | 需注意权限问题,PG 容器内部用户 UID 是 999 | 生产环境、需要手动管理数据 |
| 具名卷(Docker 管理) | -v pg_data:/var/lib/postgresql/data |
Docker 自动管理权限,无权限问题,性能更好 | 路径不直观,备份需要用 docker 命令 | 测试环境、快速部署 |
3.3 环境变量初始化机制(巨坑预警)
POSTGRES_USER、POSTGRES_PASSWORD、POSTGRES_DB 这三个环境变量,仅在容器第一次启动、数据目录为空时生效!
也就是说:
- 容器启动过一次后,再修改环境变量里的密码,不会生效
- 想修改密码,必须进入数据库执行 SQL 语句修改
- 想让新的环境变量生效,必须清空数据目录,重新初始化
这是 90% 的新手都会踩的坑,务必记住。
3.4 权限问题解决方案
挂载宿主机目录时,经常会遇到「Permission denied」报错,原因是 PostgreSQL 容器内部使用 postgres 用户运行,UID 为 999,而宿主机的目录权限属于 root 或其他用户。
解决方案二选一:
bash
# 方案1:给宿主机目录开放权限(简单粗暴,测试可用)
chmod 777 /opt/postgres/data
# 方案2:将目录所有者改为 UID 999(推荐,生产更安全)
chown -R 999:999 /opt/postgres/data
四、必备运维操作大全
4.1 进入容器与进入数据库
① 进入容器 bash 终端
bash
docker exec -it postgres-prod bash
② 直接进入 PostgreSQL 命令行(推荐,一步到位)
bash
# 格式:docker exec -it 容器名 psql -U 用户名 -d 数据库名
docker exec -it postgres-prod psql -U admin -d my_database
进入 psql 后,提示符变为
my_database=#,表示已进入数据库命令行。
4.2 psql 常用命令
| 命令 | 作用 |
|---|---|
\l |
列出所有数据库 |
\c 数据库名 |
切换到指定数据库,如 \c app_db |
\dt |
列出当前数据库所有表 |
\d 表名 |
查看表结构,如 \d users |
\du |
列出所有用户和角色 |
\conninfo |
查看当前连接信息 |
\timing on |
开启 SQL 执行耗时显示 |
\q |
退出 psql 命令行 |
4.3 账号与数据库管理
① 修改用户密码
bash
-- 语法:ALTER USER 用户名 WITH PASSWORD '新密码';
ALTER USER admin WITH PASSWORD 'NewPass@2024';
② 创建新用户
bash
-- 创建普通用户
CREATE USER app_user WITH PASSWORD 'AppUser@2024';
-- 创建带超级权限的用户(谨慎使用)
CREATE USER super_user WITH SUPERUSER PASSWORD 'Super@2024';
③ 创建数据库并授权
bash
-- 创建数据库,指定所有者
CREATE DATABASE business_db OWNER app_user;
-- 授予用户对数据库的所有权限
GRANT ALL PRIVILEGES ON DATABASE business_db TO app_user;
-- 授予连接权限
GRANT CONNECT ON DATABASE business_db TO app_user;
④ 删除用户 / 数据库
bash
-- 删除数据库
DROP DATABASE IF EXISTS old_db;
-- 删除用户
DROP USER IF EXISTS old_user;
4.4 数据备份与恢复
① 全库备份(pg_dump)
bash
# 格式:docker exec 容器名 pg_dump -U 用户名 数据库名 > 备份文件路径
docker exec postgres-prod pg_dump -U admin my_database > /opt/backup/my_database_20240601.sql
② 恢复数据
bash
# 方式1:从sql文件恢复
docker exec -i postgres-prod psql -U admin -d my_database < /opt/backup/my_database_20240601.sql
# 方式2:进入容器后恢复
docker exec -it postgres-prod bash
psql -U admin -d my_database -f /tmp/backup.sql
③ 备份整个数据卷(适合整实例迁移)
bash
# 停止容器后,打包整个数据目录
docker stop postgres-prod
tar -zcvf pg_data_backup.tar.gz /opt/postgres/data
五、进阶:开启远程访问完整步骤
很多人部署完后无法用 Navicat/DBeaver 连接,按以下 4 步检查:
-
端口映射正确 :确保
-p 5432:5432已配置,宿主机防火墙已开放 5432 端口【默认端口,建议修改,防止被攻击】bash# 云服务器需在安全组放行端口,服务器防火墙放行 firewall-cmd --add-port=5432/tcp --permanent firewall-cmd --reload -
配置监听地址 :
postgresql.conf中listen_addresses = '*' -
配置客户端认证 :
pg_hba.conf中添加允许连接的 IP 规则 -
重启容器生效
bashdocker restart postgres-prod
🔒 安全建议:生产环境不要直接暴露 5432 端口到公网,建议通过 VPN 或内网连接,或修改默认端口,配合强密码使用。
六、避坑指南:90% 的人都踩过的坑
坑 1:修改环境变量密码不生效
原因:环境变量仅第一次初始化生效。 解决:进入数据库执行 ALTER USER 语句修改密码。
坑 2:挂载目录后启动报错 Permission denied
原因:宿主机目录权限和容器内 postgres 用户 UID 不匹配。 解决:chown -R 999:999 宿主机数据目录。
坑 3:用 latest 标签导致版本异常
原因:latest 标签始终指向最新版本,重启后可能自动升级大版本,引发数据不兼容。 解决:生产必须指定具体版本号,如 postgres:16.3。
坑 4:时区不对,时间差 8 小时
原因:容器默认 UTC 时区。 解决:添加环境变量 TZ=Asia/Shanghai,同时配置文件中设置 log_timezone 和 timezone。
坑 5:数据没挂载,容器删除数据丢失
原因:新手忘记加 -v 参数。 解决:部署第一时间配置数据卷挂载,养成习惯。
坑 6:远程连接报错「password authentication failed」
排查顺序:
- 密码是否输入正确
- pg_hba.conf 是否配置了对应 IP 的 md5 认证规则
- 是否修改过密码但没生效
- 连接的用户名和数据库名是否存在
七、总结
- 快速测试 :用
docker run单命令启动,简单高效 - 生产部署 :用
Docker Compose编排,配置可版本化管理,运维更规范 - 核心底线:数据持久化必配、强密码必设、端口暴露需谨慎
- 运维习惯:定期备份数据、不使用 latest 标签、限制远程访问 IP
PostgreSQL + Docker 的组合,兼顾了灵活性和稳定性,掌握本文内容足以应对 99% 的部署场景。下一篇将讲解 PostgreSQL 主从复制的 Docker 部署方案,敬请关注。
原创不易,如果对你有帮助,欢迎点赞、收藏、关注,持续输出硬核运维干货。