外观
PostgreSQL 容器化部署
容器化部署的优势
1. 环境一致性
- 确保开发、测试和生产环境完全一致
- 消除"在我的机器上可以运行"的问题
- 便于团队协作和版本控制
2. 简化部署和管理
- 快速部署和扩展
- 简化依赖管理
- 便于自动化部署和编排
- 支持滚动升级和回滚
3. 资源隔离
- 进程级隔离,提高安全性
- 资源限制和配额管理
- 减少相互影响
4. 云原生支持
- 与云平台深度集成
- 支持微服务架构
- 便于实现高可用性和灾备
Docker 部署
1. 基本部署
拉取 PostgreSQL 镜像
bash
# 拉取最新版 PostgreSQL 镜像
docker pull postgres
# 拉取特定版本(例如 PostgreSQL 16)
docker pull postgres:16运行 PostgreSQL 容器
bash
# 基本运行方式
docker run -d \
--name postgres \
-e POSTGRES_PASSWORD=secure_password \
-e POSTGRES_USER=postgres \
-e POSTGRES_DB=postgres \
-p 5432:5432 \
postgres:16连接到 PostgreSQL
bash
# 使用 psql 客户端连接到容器内的 PostgreSQL
docker exec -it postgres psql -U postgres
# 从外部主机连接到容器内的 PostgreSQL
psql -h localhost -p 5432 -U postgres -d postgres2. 数据持久化
使用 Docker 卷
bash
# 创建名为 postgres_data 的 Docker 卷,用于持久化 PostgreSQL 数据
docker volume create postgres_data
# 使用 Docker 卷运行 PostgreSQL 容器
# 卷将自动管理数据持久化,即使容器被删除,数据也会保留
docker run -d \
--name postgres \
-e POSTGRES_PASSWORD=secure_password \
-e POSTGRES_USER=postgres \
-e POSTGRES_DB=postgres \
-p 5432:5432 \
-v postgres_data:/var/lib/postgresql/data \
postgres:16使用主机目录
bash
# 在主机上创建数据目录,用于持久化 PostgreSQL 数据
mkdir -p /data/postgres
# 使用主机目录运行 PostgreSQL 容器
# 数据将直接存储在主机目录中,便于直接访问和管理
docker run -d \
--name postgres \
-e POSTGRES_PASSWORD=secure_password \
-e POSTGRES_USER=postgres \
-e POSTGRES_DB=postgres \
-p 5432:5432 \
-v /data/postgres:/var/lib/postgresql/data \
postgres:163. 高级配置
自定义配置文件
bash
# 在主机上创建 PostgreSQL 配置目录
mkdir -p /data/postgres/config
# 从运行的 PostgreSQL 容器中复制默认配置文件到主机
# 这样可以获取适合当前版本的默认配置
docker cp postgres:/usr/share/postgresql/postgresql.conf.sample /data/postgres/config/postgresql.conf
# 使用编辑器修改配置文件,根据实际需求调整参数
vi /data/postgres/config/postgresql.conf
# 使用自定义配置文件运行新的 PostgreSQL 容器
# 同时挂载自定义的 postgresql.conf 和 pg_hba.conf 文件
docker run -d \
--name postgres \
-e POSTGRES_PASSWORD=secure_password \
-e POSTGRES_USER=postgres \
-e POSTGRES_DB=postgres \
-p 5432:5432 \
-v postgres_data:/var/lib/postgresql/data \
-v /data/postgres/config/postgresql.conf:/etc/postgresql/postgresql.conf \
-v /data/postgres/config/pg_hba.conf:/etc/postgresql/pg_hba.conf \
postgres:16 -c 'config_file=/etc/postgresql/postgresql.conf'配置 pg_hba.conf
bash
# 创建自定义的 pg_hba.conf 文件,用于配置访问控制策略
# 这个文件定义了哪些主机可以连接到 PostgreSQL,以及使用什么认证方式
cat > /data/postgres/config/pg_hba.conf << EOF
# 类型 数据库 用户 地址 认证方式
host all all 0.0.0.0/0 md5 # 允许所有 IPv4 地址使用 MD5 认证连接所有数据库
host all all ::/0 md5 # 允许所有 IPv6 地址使用 MD5 认证连接所有数据库
local all all trust # 允许本地连接使用 trust 认证
EOF
# 重启容器以应用新的配置文件
docker restart postgres4. Docker Compose 部署
创建 docker-compose.yml 文件
yaml
# docker-compose.yml - PostgreSQL Docker Compose 配置文件
# 使用 Docker Compose 可以更方便地管理多个服务和配置
version: '3.8'
services:
postgres: # PostgreSQL 服务定义
image: postgres:16 # PostgreSQL 镜像版本
container_name: postgres # 容器名称
environment: # 环境变量配置
POSTGRES_PASSWORD: secure_password # 数据库密码
POSTGRES_USER: postgres # 数据库用户名
POSTGRES_DB: postgres # 初始数据库名称
PGDATA: /var/lib/postgresql/data # 数据存储目录
volumes: # 卷挂载配置
- postgres_data:/var/lib/postgresql/data # 数据持久化卷
- ./config/postgresql.conf:/etc/postgresql/postgresql.conf # 自定义配置文件
- ./config/pg_hba.conf:/etc/postgresql/pg_hba.conf # 自定义访问控制配置
ports: # 端口映射
- "5432:5432" # 将主机 5432 端口映射到容器 5432 端口
restart: unless-stopped # 重启策略:除非手动停止,否则总是重启
healthcheck: # 健康检查配置
test: ["CMD-SHELL", "pg_isready -U postgres -d postgres"] # 健康检查命令
interval: 10s # 检查间隔
timeout: 5s # 检查超时时间
retries: 5 # 失败重试次数
volumes: # 卷定义
postgres_data: # 数据持久化卷
driver: local # 使用本地卷驱动启动服务
bash
# 使用 Docker Compose 启动所有服务
# -d 参数表示在后台运行
docker-compose up -d停止服务
bash
# 使用 Docker Compose 停止所有服务
docker-compose downKubernetes 部署
1. 基本部署
Kubernetes 部署是生产环境中常用的 PostgreSQL 部署方式,它提供了强大的编排能力、自动扩展和高可用性支持。
创建命名空间
bash
# 创建 PostgreSQL 专用命名空间,用于隔离 PostgreSQL 相关资源
# 命名空间可以帮助我们更好地管理和组织集群中的资源
kubectl create namespace postgres创建密钥
bash
# 创建包含 PostgreSQL 密码的密钥对象
# 使用密钥来存储敏感信息,避免将密码直接暴露在配置文件中
kubectl create secret generic postgres-secret \
--namespace postgres \
--from-literal=POSTGRES_PASSWORD=secure_password创建 Deployment
yaml
# postgres-deployment.yaml - PostgreSQL Deployment 配置文件
# Deployment 是 Kubernetes 中用于管理无状态应用的资源对象
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres # Deployment 名称
namespace: postgres # 所属命名空间
spec:
replicas: 1 # 期望的 Pod 副本数量
selector:
matchLabels:
app: postgres # 标签选择器,用于匹配和管理 Pod
template:
metadata:
labels:
app: postgres # Pod 标签,用于被 Service 和其他资源引用
spec:
containers:
- name: postgres # 容器名称
image: postgres:16 # 使用的 Docker 镜像及版本
ports:
- containerPort: 5432 # 容器内部监听的端口
env: # 环境变量配置
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef: # 从密钥中获取密码,提高安全性
name: postgres-secret
key: POSTGRES_PASSWORD
- name: POSTGRES_USER
value: postgres # 数据库用户名
- name: POSTGRES_DB
value: postgres # 初始数据库名称
volumeMounts: # 卷挂载配置
- name: postgres-data
mountPath: /var/lib/postgresql/data # 容器内数据存储路径
volumes: # 卷定义
- name: postgres-data
emptyDir: {} # 使用临时目录,生产环境建议使用持久卷bash
# 应用 Deployment 配置,创建并启动 PostgreSQL Pod
kubectl apply -f postgres-deployment.yaml创建 Service
yaml
# postgres-service.yaml - PostgreSQL Service 配置文件
# Service 用于在 Kubernetes 集群中暴露应用,提供稳定的访问入口
apiVersion: v1
kind: Service
metadata:
name: postgres # Service 名称
namespace: postgres # 所属命名空间
spec:
selector:
app: postgres # 标签选择器,匹配后端 Pod
ports:
- port: 5432 # Service 暴露的端口
targetPort: 5432 # 后端 Pod 监听的端口
type: ClusterIP # Service 类型,ClusterIP 仅在集群内部可访问bash
# 应用 Service 配置,创建 PostgreSQL 服务
kubectl apply -f postgres-service.yaml2. 持久化存储
在 Kubernetes 中,为了确保数据持久化,我们需要使用 PersistentVolume (PV) 和 PersistentVolumeClaim (PVC)。PV 是集群级别的存储资源,PVC 是对 PV 的请求和声明。
使用 PersistentVolumeClaim
yaml
# postgres-pvc.yaml - PostgreSQL 持久卷声明配置文件
# PVC 用于请求存储资源,不需要关心底层存储的具体实现
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-pvc # PVC 名称
namespace: postgres # 所属命名空间
spec:
accessModes:
- ReadWriteOnce # 访问模式:只允许一个节点读写挂载
resources:
requests:
storage: 10Gi # 请求的存储容量
storageClassName: standard # 使用的存储类名称bash
# 应用 PVC 配置,创建持久卷声明
kubectl apply -f postgres-pvc.yaml更新 Deployment 使用 PVC
yaml
# postgres-deployment.yaml - 使用持久卷的 PostgreSQL 部署配置
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres # Deployment 名称
namespace: postgres # 所属命名空间
spec:
replicas: 1 # 副本数量
selector:
matchLabels:
app: postgres # 标签选择器
template:
metadata:
labels:
app: postgres # Pod 标签
spec:
containers:
- name: postgres # 容器名称
image: postgres:16 # Docker 镜像
ports:
- containerPort: 5432 # 容器端口
env: # 环境变量
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef: # 从密钥获取密码
name: postgres-secret
key: POSTGRES_PASSWORD
- name: POSTGRES_USER
value: postgres # 用户名
- name: POSTGRES_DB
value: postgres # 数据库名称
volumeMounts: # 卷挂载
- name: postgres-data
mountPath: /var/lib/postgresql/data # 数据目录
volumes: # 卷定义
- name: postgres-data
persistentVolumeClaim:
claimName: postgres-pvc # 使用之前创建的 PVCbash
# 更新 Deployment 配置,使用持久卷存储
kubectl apply -f postgres-deployment.yaml3. 高可用性部署
使用 StatefulSet
yaml
# postgres-statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
namespace: postgres
spec:
serviceName: "postgres"
replicas: 3
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:16
ports:
- containerPort: 5432
env:
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-secret
key: POSTGRES_PASSWORD
- name: POSTGRES_USER
value: postgres
- name: POSTGRES_DB
value: postgres
volumeMounts:
- name: postgres-data
mountPath: /var/lib/postgresql/data
volumes:
- name: postgres-data
persistentVolumeClaim:
claimName: postgres-pvcbash
kubectl apply -f postgres-statefulset.yaml创建 Headless Service
yaml
# postgres-headless-service.yaml
apiVersion: v1
kind: Service
metadata:
name: postgres
namespace: postgres
spec:
selector:
app: postgres
ports:
- port: 5432
targetPort: 5432
clusterIP: Nonebash
kubectl apply -f postgres-headless-service.yaml4. 使用 Helm 部署
安装 Helm
bash
# 下载 Helm
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
chmod 700 get_helm.sh
./get_helm.sh添加 Bitnami 仓库
bash
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update安装 PostgreSQL Helm Chart
bash
# 基本安装
helm install postgres bitnami/postgresql \
--namespace postgres \
--create-namespace \
--set auth.postgresPassword=secure_password \
--set persistence.size=10Gi
# 安装特定版本
helm install postgres bitnami/postgresql \
--namespace postgres \
--create-namespace \
--set image.tag=16 \
--set auth.postgresPassword=secure_password \
--set persistence.size=10Gi查看 Helm 发布
bash
helm list -n postgres连接到 PostgreSQL
bash
# 获取密码
export POSTGRES_PASSWORD=$(kubectl get secret --namespace postgres postgres-postgresql -o jsonpath="{.data.postgres-password}" | base64 -d)
# 端口转发
kubectl port-forward --namespace postgres svc/postgres-postgresql 5432:5432 &
# 连接
psql --host 127.0.0.1 -U postgres -d postgres -p 5432配置优化
1. 内存配置
yaml
# docker-compose.yml
version: '3.8'
services:
postgres:
image: postgres:16
environment:
POSTGRES_PASSWORD: secure_password
POSTGRES_USER: postgres
POSTGRES_DB: postgres
command: >
postgres
-c shared_buffers=2GB
-c work_mem=16MB
-c maintenance_work_mem=1GB
-c effective_cache_size=6GB2. WAL 配置
yaml
# docker-compose.yml
version: '3.8'
services:
postgres:
image: postgres:16
environment:
POSTGRES_PASSWORD: secure_password
POSTGRES_USER: postgres
POSTGRES_DB: postgres
command: >
postgres
-c wal_level=replica
-c checkpoint_timeout=15min
-c max_wal_size=4GB
-c min_wal_size=1GB3. 连接配置
yaml
# docker-compose.yml
version: '3.8'
services:
postgres:
image: postgres:16
environment:
POSTGRES_PASSWORD: secure_password
POSTGRES_USER: postgres
POSTGRES_DB: postgres
command: >
postgres
-c max_connections=200
-c listen_addresses='*'监控和日志
1. Docker 监控
使用 Docker Stats
bash
docker stats postgres使用 Prometheus 和 Grafana
yaml
# docker-compose.yml
version: '3.8'
services:
postgres:
image: postgres:16
environment:
POSTGRES_PASSWORD: secure_password
POSTGRES_USER: postgres
POSTGRES_DB: postgres
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
postgres_exporter:
image: prometheuscommunity/postgres-exporter:latest
environment:
DATA_SOURCE_NAME: "postgresql://postgres:secure_password@postgres:5432/postgres?sslmode=disable"
ports:
- "9187:9187"
depends_on:
- postgres
prometheus:
image: prom/prometheus:latest
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
ports:
- "9090:9090"
depends_on:
- postgres_exporter
grafana:
image: grafana/grafana:latest
volumes:
- grafana_data:/var/lib/grafana
ports:
- "3000:3000"
depends_on:
- prometheus
volumes:
postgres_data:
prometheus_data:
grafana_data:2. Kubernetes 监控
使用 Prometheus Operator
bash
# 安装 Prometheus Operator
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
helm install prometheus prometheus-community/kube-prometheus-stack \
--namespace monitoring \
--create-namespace配置 PostgreSQL ServiceMonitor
yaml
# postgres-servicemonitor.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: postgres
namespace: postgres
labels:
release: prometheus
spec:
selector:
matchLabels:
app: postgres
endpoints:
- port: metrics
interval: 15s3. 日志管理
Docker 日志
bash
# 查看日志
docker logs postgres
# 实时查看日志
docker logs -f postgres
# 查看最后 100 行
docker logs --tail 100 postgresKubernetes 日志
bash
# 查看 Pod 日志
kubectl logs -n postgres deployment/postgres
# 实时查看日志
kubectl logs -f -n postgres deployment/postgres
# 查看特定容器日志
kubectl logs -n postgres deployment/postgres -c postgres高可用性和灾备
1. Docker 高可用性
使用 Docker Swarm
yaml
# docker-stack.yml
version: '3.8'
services:
postgres:
image: postgres:16
environment:
POSTGRES_PASSWORD: secure_password
POSTGRES_USER: postgres
POSTGRES_DB: postgres
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "5432:5432"
deploy:
replicas: 1
placement:
constraints:
- node.role == manager
volumes:
postgres_data:
driver: localbash
# 初始化 Swarm
docker swarm init
# 部署堆栈
docker stack deploy -c docker-stack.yml postgres2. Kubernetes 高可用性
使用 Patroni
yaml
# patroni-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: patroni-config
namespace: postgres
data:
patroni.yaml: |
scope: postgres
namespace: postgres
name: postgres
restapi:
listen: 0.0.0.0:8008
connect_address: 0.0.0.0:8008
etcd:
hosts: etcd-client.etcd.svc.cluster.local:2379
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576
postgresql:
use_pg_rewind: true
parameters:
shared_buffers: 256MB
work_mem: 8MB
maintenance_work_mem: 128MB
wal_level: replica
max_wal_senders: 10
max_replication_slots: 10
wal_keep_size: 1GB
checkpoint_timeout: 300s
max_wal_size: 1GB
min_wal_size: 512MB
initdb:
- encoding: UTF8
- data-checksums
pg_hba:
- host replication replicator 0.0.0.0/0 md5
- host all all 0.0.0.0/0 md5
users:
admin:
password: admin
options:
- createrole
- createdb
postgresql:
listen: 0.0.0.0:5432
connect_address: 0.0.0.0:5432
data_dir: /var/lib/postgresql/data
pgpass: /tmp/pgpass
authentication:
replication:
username: replicator
password: secure_password
superuser:
username: postgres
password: secure_password
parameters:
unix_socket_directories: /tmp
tags:
nofailover: false
noloadbalance: false
clonefrom: false
nosync: false备份和恢复
1. Docker 备份
使用 pg_dump
bash
# 备份数据库
docker exec -t postgres pg_dump -U postgres -F c -b -v -f /tmp/backup.dump postgres
# 复制备份文件到主机
docker cp postgres:/tmp/backup.dump /data/backup.dump使用卷备份
bash
# 备份卷
docker run --rm \
-v postgres_data:/data \
-v /data/backup:/backup \
alpine \
tar -czf /backup/postgres_data.tar.gz /data2. Kubernetes 备份
使用 CronJob
yaml
# postgres-backup-cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: postgres-backup
namespace: postgres
spec:
schedule: "0 0 * * *" # 每天凌晨 0 点执行
jobTemplate:
spec:
template:
spec:
containers:
- name: postgres-backup
image: postgres:16
env:
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-secret
key: POSTGRES_PASSWORD
command:
- /bin/bash
- -c
- |
pg_dump -h postgres -U postgres -F c -b -v -f /tmp/backup-$(date +%Y%m%d%H%M%S).dump postgres
echo "备份完成"
volumeMounts:
- name: backup-volume
mountPath: /tmp
restartPolicy: OnFailure
volumes:
- name: backup-volume
persistentVolumeClaim:
claimName: postgres-backup-pvc常见问题(FAQ)
Q1: 如何修改 PostgreSQL 容器的配置?
A1: 有两种方式修改配置:
- 使用命令行参数:在运行容器时使用
-c参数指定配置项 - 挂载自定义配置文件:将自定义的
postgresql.conf和pg_hba.conf文件挂载到容器中
Q2: 如何在 Docker 中运行多个 PostgreSQL 实例?
A2: 使用不同的容器名称和端口映射:
bash
docker run -d \
--name postgres1 \
-e POSTGRES_PASSWORD=secure_password \
-p 5432:5432 \
postgres:16
docker run -d \
--name postgres2 \
-e POSTGRES_PASSWORD=secure_password \
-p 5433:5432 \
postgres:16Q3: 如何在 Kubernetes 中扩缩容 PostgreSQL?
A3: 使用 StatefulSet 可以实现扩缩容,但需要注意 PostgreSQL 的主从复制配置:
bash
# 扩缩容到 3 个副本
kubectl scale statefulset postgres --replicas=3 -n postgresQ4: 如何更新 PostgreSQL 容器镜像?
A4: Docker 环境:
bash
docker pull postgres:16.1
docker stop postgres
docker rm postgres
docker run -d --name postgres -e POSTGRES_PASSWORD=secure_password postgres:16.1Kubernetes 环境:
bash
kubectl set image deployment/postgres postgres=postgres:16.1 -n postgresQ5: 如何监控 PostgreSQL 容器的性能?
A5: 使用以下方法:
- Docker Stats 查看资源使用情况
- Prometheus + Grafana 进行全面监控
- pg_stat_statements 扩展分析查询性能
- 定期查看 PostgreSQL 日志
Q6: 如何确保 PostgreSQL 容器的数据安全?
A6: 采取以下措施:
- 使用强密码
- 启用 SSL 加密
- 限制访问 IP 地址
- 定期备份数据
- 使用加密卷存储敏感数据
- 定期更新 PostgreSQL 版本
Q7: 如何在 Kubernetes 中实现 PostgreSQL 主从复制?
A7: 可以使用以下方法:
- 使用 Patroni 实现自动故障转移
- 使用 Stolon 管理 PostgreSQL 集群
- 使用 Bitnami PostgreSQL Helm Chart 配置主从复制
- 手动配置主从复制
Q8: 如何优化 PostgreSQL 容器的性能?
A8: 优化方法:
- 根据硬件资源调整内存配置
- 优化 WAL 配置
- 调整连接数和工作内存
- 合理设置 checkpoint 相关参数
- 定期进行 VACUUM 和 ANALYZE
- 优化查询和索引
最佳实践
1. 安全最佳实践
- 使用强密码和 Secret 管理
- 启用 SSL/TLS 加密
- 限制网络访问
- 定期更新镜像
- 最小化容器权限
- 启用审计日志
2. 性能最佳实践
- 根据硬件资源调整配置
- 使用高性能存储
- 优化查询和索引
- 合理设置连接池
- 定期维护数据库
- 监控性能指标
3. 高可用性最佳实践
- 使用 StatefulSet 或 Operator 管理集群
- 配置自动故障转移
- 实现跨可用区部署
- 定期测试故障转移
- 配置适当的资源限制
4. 备份最佳实践
- 定期进行全量备份
- 结合 WAL 归档和增量备份
- 测试恢复流程
- 存储备份到多个位置
- 定期验证备份完整性
- 使用自动化工具管理备份
5. 部署最佳实践
- 使用版本控制管理配置文件
- 自动化部署流程
- 实现蓝绿部署或滚动升级
- 配置健康检查和就绪探针
- 监控部署状态
- 实现自动扩缩容
版本差异
PostgreSQL 15 及以上版本
- 改进了逻辑复制性能
- 增强了分区表功能
- 引入了新的权限管理功能
- 改进了真空清理机制
PostgreSQL 13 及以上版本
- 引入了增量排序
- 改进了并行查询
- 增强了 JSONB 支持
- 引入了存储过程支持
PostgreSQL 11 及以上版本
- 引入了声明式分区
- 改进了并行查询
- 增强了窗口函数
- 引入了新的索引类型
