Kubernetes 环境下的 PostgreSQL 部署
基于官方 postgres 镜像的生产级部署与备份实践
前言
PostgreSQL 作为最强大的开源关系型数据库之一,在企业级应用中扮演着重要角色。将 PostgreSQL 部署在 Kubernetes 环境中,不仅能享受容器化带来的便利,还能利用 Kubernetes 的弹性伸缩和自愈能力。
今天,我将分享一套完整的 PostgreSQL K8s 部署方案,包括 StatefulSet 部署、用户权限管理、以及自动备份策略。
为什么选择 Kubernetes 部署 PostgreSQL?
| 优势 | 说明 |
|---|---|
| 高可用 | Kubernetes 自动重启故障 Pod,保证服务持续运行 |
| 弹性伸缩 | 根据负载动态调整资源配额 |
| 版本管理 | 通过镜像版本轻松实现数据库升级 |
| 资源隔离 | 独立的 Namespace 和资源配额 |
| 存储管理 | HostPath 或持久卷灵活配置 |
整体架构一览
先来看一张部署架构图:

核心组件解析
1. StatefulSet 控制器
采用 StatefulSet 而非 Deployment,这是 PostgreSQL 作为有状态应用的必然选择:
- 稳定的网络标识:Pod 名称固定为
postgres-master-0 - 有序的部署/扩缩容:确保数据完整性
- 独立的持久存储:每个 Pod 绑定独立的 HostPath
2. hostNetwork 网络模式
spec:
hostNetwork: true
hostAliases:
- ip: "<INTERNAL_IP>"
hostnames:
- "postgres-master"
使用 hostNetwork: true 让 PostgreSQL 直接使用宿主机网络,避免端口映射带来的性能损耗。
3. NodePort 外部访问
spec:
type: NodePort
ports:
- port: 5432
targetPort: 5432
nodePort: 30032
通过 NodePort 30032 暴露服务,外部客户端可通过 host:<NODE_IP>:30032 访问数据库。
4. 双目录 HostPath 挂载
volumeMounts:
- name: postgres-lib
mountPath: /var/lib/postgresql/
- name: postgres-data
mountPath: /var/lib/postgresql/data/
分离 lib 目录和数据目录,便于分别管理配置文件和数据文件。
部署配置文件详解
完整的 YAML 编排
apiVersion: v1
kind: Namespace
metadata:
name: csjg-postgres
---
apiVersion: v1
kind: Service
metadata:
labels:
app: postgres-master-out
name: postgres-master-out
namespace: csjg-postgres
spec:
type: NodePort
ports:
- port: 5432
targetPort: 5432
nodePort: 30032
selector:
app: postgres-master
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
labels:
app: postgres-master
name: postgres-master
namespace: csjg-postgres
spec:
replicas: 1
selector:
matchLabels:
app: postgres-master
template:
metadata:
labels:
app: postgres-master
spec:
hostNetwork: true
hostAliases:
- ip: "<INTERNAL_IP>"
hostnames:
- "postgres-master"
containers:
- name: postgres-master
image: postgres:10.20-alpine
imagePullPolicy: IfNotPresent
env:
- name: POSTGRES_PASSWORD
value: "********"
- name: ALLOW_IP_RANGE
value: "0.0.0.0/0"
- name: TZ
value: "Asia/Shanghai"
ports:
- containerPort: 5432
volumeMounts:
- name: postgres-lib
mountPath: /var/lib/postgresql/
- name: postgres-data
mountPath: /var/lib/postgresql/data/
resources:
limits:
cpu: 3
memory: 30Gi
requests:
cpu: 100m
memory: 2Gi
volumes:
- name: postgres-lib
hostPath:
path: /home/postgres/data/
- name: postgres-data
hostPath:
path: /home/postgres/data/data/
nodeSelector:
postgres-server: master
关键配置说明
| 配置项 | 说明 |
|---|---|
postgres:10.20-alpine |
Alpine 精简镜像,体积小、安全性高 |
POSTGRES_PASSWORD |
数据库超级用户密码 |
ALLOW_IP_RANGE |
允许访问的 IP 段 |
resources |
CPU/内存限制,防止资源滥用 |
nodeSelector |
调度到专用数据库节点 |
部署实战
部署流程图

详细部署步骤
步骤一:节点准备
# 查看当前节点及其标签
kubectl get node --show-labels=true
# 给专用节点添加标签
kubectl label nodes <NODE_NAME> postgres-server=master
步骤二:创建数据目录
# 在目标节点上创建数据目录
mkdir -p /home/postgres/data/data
# 确保权限正确
chmod -R 777 /home/postgres
步骤三:部署资源
# 一键部署所有资源
kubectl apply -f postgres.yaml
# 查看 Pod 状态
kubectl get pod -n csjg-postgres -o wide
# 查看日志
kubectl logs -f postgres-master-0 -n csjg-postgres
用户权限管理
数据库安全至关重要,我们需要创建不同角色的用户:
创建只读用户
-- 创建只读账号
CREATE USER readonly_user WITH PASSWORD '********';
-- 设置只读事务模式
ALTER USER readonly_user SET default_transaction_read_only = on;
-- 授予连接权限
GRANT CONNECT ON DATABASE <DATABASE_NAME> TO readonly_user;
GRANT USAGE ON SCHEMA public TO readonly_user;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly_user;
创建读写用户
-- 创建读写账号
CREATE USER readwrite_user WITH PASSWORD '********';
-- 授予数据库级权限
GRANT ALL PRIVILEGES ON DATABASE <DATABASE_NAME> TO readwrite_user;
-- 授予 Schema 权限
GRANT ALL PRIVILEGES ON SCHEMA public TO readwrite_user;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO readwrite_user;
-- 如需超级权限(谨慎使用)
ALTER USER readwrite_user WITH SUPERUSER;
密码重置
-- 重置用户密码
ALTER USER <USER_NAME> WITH PASSWORD '********';
数据备份与恢复
数据备份是数据库运维的生命线!下面介绍完整的备份方案:
备份策略架构图

备份脚本
#!/bin/bash
# 备份存放位置
BACKUP_DIR=/var/lib/backup/
# 创建备份目录
if [ ! -d "$BACKUP_DIR" ]; then
mkdir -p "$BACKUP_DIR"
fi
cd $BACKUP_DIR
# 删除30天之前的备份
find $BACKUP_DIR -type d -mtime +30 -exec rm -rf {} \;
# 每天凌晨执行,备份数据文件夹名为 yyyy-MM-dd 格式
dateDIR=`date +%Y-%m-%d`
mkdir -p $dateDIR
# 备份指定的数据库
backupDB=(bac_doc bac_delivery)
backupDBArr=$(echo ${backupDB[@]})
# 使用压缩转储每一个数据库
for i in $backupDBArr; do
pg_dump -h <POSTGRES_HOST> -p 30032 -U postgres $i | gzip > $BACKUP_DIR$dateDIR/${i}_${dateDIR}.gz
done
定时任务配置
# crontab 配置
01 00 * * * root docker exec postgres-db-1 /backup.sh 2>&1
每天凌晨 00:01 自动执行备份任务。
备份文件格式
/var/lib/backup/
├── 2026-04-15/
│ ├── bac_doc_2026-04-15.gz
│ └── bac_delivery_2026-04-15.gz
├── 2026-04-16/
│ ├── bac_doc_2026-04-16.gz
│ └── bac_delivery_2026-04-16.gz
└── 2026-04-17/
├── bac_doc_2026-04-17.gz
└── bac_delivery_2026-04-17.gz
恢复方法
方法一:pg_restore(推荐)
# 解压并恢复
gunzip -c backup.gz | pg_restore -h <HOST> -p 5432 -U postgres -d <DB_NAME>
方法二:psql(文本格式)
# 全量恢复
gunzip -c backup.sql.gz | psql -h <HOST> -p 5432 -U postgres -d <DB_NAME>
方法三:物理备份
适用于需要快速恢复的场景,但需要停机或配合 PITR(Point-In-Time Recovery)。
连接验证
命令行连接
# 连接 PostgreSQL
psql -h <NODE_IP> -p 30032 -U postgres
# 查看数据库列表
SELECT datname FROM pg_database;
# 查看版本
SELECT version();
连接字符串
postgresql://postgres:<PASSWORD>@<NODE_IP>:30032/<DATABASE_NAME>
常用管理工具
| 工具 | 平台 | 说明 |
|---|---|---|
| pgAdmin | Web | 官方推荐的图形化管理工具 |
| DBeaver | 跨平台 | 开源通用数据库客户端 |
| Navicat | 跨平台 | 商业级数据库管理工具 |
运维最佳实践
日常检查清单
# 1. Pod 状态检查
kubectl get pod -n csjg-postgres
# 2. 存储使用情况
kubectl exec postgres-master-0 -n csjg-postgres -- df -h /var/lib/postgresql/data/
# 3. 数据库连接数
kubectl exec postgres-master-0 -n csjg-postgres -- psql -U postgres -c "SELECT count(*) FROM pg_stat_activity;"
# 4. 慢查询检查
kubectl exec postgres-master-0 -n csjg-postgres -- psql -U postgres -c "SELECT * FROM pg_stat_statements ORDER BY mean_exec_time DESC LIMIT 10;"
故障排查
| 症状 | 可能原因 | 解决方案 |
|---|---|---|
| Pod 处于 Pending | 节点标签不存在 | 添加 kubectl label nodes <node> postgres-server=master |
| 连接被拒绝 | 端口未开放 | 检查防火墙和 NodePort 配置 |
| 数据目录权限错误 | HostPath 权限不足 | chmod -R 777 /home/postgres |
| 密码错误 | 环境变量配置错误 | 检查 POSTGRES_PASSWORD 设置 |