硬核实践:使用 Docker 部署生产级 PostgreSQL

本文从最基础的单命令启动,到生产级 Compose 编排,逐层拆解参数原理、数据持久化、账号管理、远程访问等核心知识点,新手可照抄落地,老手可查漏补缺。

0. 前言与前置准备

Docker 部署 PostgreSQL 是开发、测试、生产环境最常用的方案之一,核心优势在于:

  • 环境一致性:彻底解决「我本地能跑,服务器上不行」的问题
  • 秒级部署:一条命令启动实例,版本切换无成本
  • 隔离性强:多版本、多实例互不干扰
  • 运维简单:数据持久化、备份、迁移标准化

前置条件

  1. 已安装 Docker(建议 20.10+)
  2. 已安装 Docker Compose v2(建议 2.20+)
  3. 服务器 / 本地已开放对应端口(默认 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 种可选值,区别如下:

  1. no:默认值,容器退出时不自动重启
  2. on-failure[:max-retries]:容器非正常退出(退出码非 0)时自动重启,可设置最大重试次数
  3. always:无论什么原因退出都自动重启,包括手动停止的容器,Docker 重启后也会自动拉起
  4. 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 同级目录创建 confdatainit 三个文件夹:

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_USERPOSTGRES_PASSWORDPOSTGRES_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 步检查:

  1. 端口映射正确 :确保 -p 5432:5432 已配置,宿主机防火墙已开放 5432 端口【默认端口,建议修改,防止被攻击】

    bash 复制代码
    # 云服务器需在安全组放行端口,服务器防火墙放行
    firewall-cmd --add-port=5432/tcp --permanent
    firewall-cmd --reload
  2. 配置监听地址postgresql.conflisten_addresses = '*'

  3. 配置客户端认证pg_hba.conf 中添加允许连接的 IP 规则

  4. 重启容器生效

    bash 复制代码
    docker 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_timezonetimezone

坑 5:数据没挂载,容器删除数据丢失

原因:新手忘记加 -v 参数。 解决:部署第一时间配置数据卷挂载,养成习惯。

坑 6:远程连接报错「password authentication failed」

排查顺序:

  1. 密码是否输入正确
  2. pg_hba.conf 是否配置了对应 IP 的 md5 认证规则
  3. 是否修改过密码但没生效
  4. 连接的用户名和数据库名是否存在

七、总结

  • 快速测试 :用 docker run 单命令启动,简单高效
  • 生产部署 :用 Docker Compose 编排,配置可版本化管理,运维更规范
  • 核心底线:数据持久化必配、强密码必设、端口暴露需谨慎
  • 运维习惯:定期备份数据、不使用 latest 标签、限制远程访问 IP

PostgreSQL + Docker 的组合,兼顾了灵活性和稳定性,掌握本文内容足以应对 99% 的部署场景。下一篇将讲解 PostgreSQL 主从复制的 Docker 部署方案,敬请关注。

原创不易,如果对你有帮助,欢迎点赞、收藏、关注,持续输出硬核运维干货。

相关推荐
勉灬之1 小时前
利用双网卡服务器搭建 Verdaccio 中转,解决内网 npm 依赖下载问题
运维·服务器·npm
江湖有缘2 小时前
Lunalytics部署指南:使用Docker快速搭建私有监控面板
运维·docker·容器
DB哥讲数据库2 小时前
rocky linux安装教程:VMware虚拟机图文讲解部署Rocky Linux 9(附镜像包)
linux·运维·服务器
未*望2 小时前
【Linux入坑(二)—全志T133开发板适配USB-电容屏触摸屏驱动(多点触控) 】
linux·运维·服务器
分布式存储与RustFS2 小时前
RustFS保姆级教程:Docker快速部署兼容S3的本地对象存储
运维·docker·容器·rustfs部署教程·本地搭建s3对象存储·rustfs网页控制台使用·awscli连接rustfs
江湖有缘2 小时前
Docker部署Papra极简文件归档平台
运维·docker·容器
gooxi_hui2 小时前
海量存力,智驭未来丨国鑫4U60盘位高密度存储服务器SL401-G4重磅上市
运维·服务器·人工智能
吴爃2 小时前
小微企业 SRE 稳定性建设
运维·稳定性·小微企业
IvorySQL3 小时前
PG 技术日报|2026-07-03
数据库·postgresql·开源
开开心心_Every3 小时前
带OCR识别的电子发票打印工具
运维·自动化·ocr·电脑·powerpoint·音视频·lua