StatefulSet 深入实践指南
StatefulSet是Kubernetes中专门用于管理有状态应用的工作负载控制器。与Deployment不同,StatefulSet为每个Pod提供稳定的网络标识、持久化存储和有序的部署与扩展,使其成为部署数据库、消息队列等有状态服务的首选方案。
🎯 StatefulSet核心概念
StatefulSet vs Deployment
yaml
statefulset_vs_deployment:
deployment_characteristics:
pod_identity: "随机名称 + 随机ID"
network_identity: "不稳定,Pod重启后变化"
storage: "共享存储或临时存储"
scaling: "并行扩缩容"
updates: "并行滚动更新"
use_cases:
- "无状态Web应用"
- "API服务"
- "批处理任务"
- "缓存层服务"
example_naming:
- "nginx-deployment-7d8c6df8c5-abc12"
- "nginx-deployment-7d8c6df8c5-def34"
- "nginx-deployment-7d8c6df8c5-ghi56"
statefulset_characteristics:
pod_identity: "稳定的序号标识"
network_identity: "稳定的DNS名称"
storage: "每个Pod独立的持久化存储"
scaling: "有序扩缩容"
updates: "有序滚动更新"
use_cases:
- "数据库集群"
- "消息队列"
- "分布式存储"
- "有状态中间件"
example_naming:
- "postgres-0"
- "postgres-1"
- "postgres-2"yaml
statefulset_mechanics:
pod_management:
ordered_deployment:
description: "Pod按序号顺序创建"
process:
1: "创建postgres-0,等待Running"
2: "创建postgres-1,等待Running"
3: "创建postgres-2,等待Running"
configuration: |
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
spec:
serviceName: postgres
replicas: 3
podManagementPolicy: OrderedReady # 有序创建
selector:
matchLabels:
app: postgres
parallel_deployment:
description: "Pod并行创建"
configuration: |
spec:
podManagementPolicy: Parallel # 并行创建
ordered_termination:
description: "Pod按倒序删除"
process:
1: "删除postgres-2,等待终止"
2: "删除postgres-1,等待终止"
3: "删除postgres-0,等待终止"
network_identity:
stable_hostnames:
pattern: "$(pod-name).$(service-name).$(namespace).svc.cluster.local"
examples:
- "postgres-0.postgres.default.svc.cluster.local"
- "postgres-1.postgres.production.svc.cluster.local"
- "kafka-2.kafka.streaming.svc.cluster.local"
headless_service: |
# StatefulSet必须与Headless Service配对
apiVersion: v1
kind: Service
metadata:
name: postgres
spec:
clusterIP: None # Headless Service
selector:
app: postgres
ports:
- port: 5432
targetPort: 5432
persistent_storage:
volume_claim_templates:
description: "为每个Pod自动创建PVC"
configuration: |
spec:
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: fast-ssd
resources:
requests:
storage: 100Gi
volume_binding:
description: "Pod与PVC的稳定绑定"
pattern:
- "postgres-0 → data-postgres-0"
- "postgres-1 → data-postgres-1"
- "postgres-2 → data-postgres-2"🗄️ 数据库StatefulSet实践
PostgreSQL集群部署
yaml
postgresql_cluster:
master_slave_config:
statefulset: |
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
namespace: production
spec:
serviceName: postgres
replicas: 3
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
securityContext:
runAsUser: 999
runAsGroup: 999
fsGroup: 999
containers:
- name: postgres
image: postgres:14-alpine
env:
- name: POSTGRES_DB
value: "myapp"
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: postgres-secret
key: username
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-secret
key: password
- name: PGUSER
valueFrom:
secretKeyRef:
name: postgres-secret
key: username
# 根据Pod序号配置主从角色
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
ports:
- containerPort: 5432
name: postgres
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
- name: config
mountPath: /etc/postgresql
- name: init-scripts
mountPath: /docker-entrypoint-initdb.d
# 生命周期钩子
lifecycle:
postStart:
exec:
command:
- /bin/bash
- -c
- |
# 配置主从复制
if [[ "${POD_NAME##*-}" == "0" ]]; then
echo "Configuring as master"
# 主节点配置
echo "wal_level = replica" >> /var/lib/postgresql/data/postgresql.conf
echo "max_wal_senders = 3" >> /var/lib/postgresql/data/postgresql.conf
echo "wal_keep_segments = 64" >> /var/lib/postgresql/data/postgresql.conf
else
echo "Configuring as slave"
# 从节点配置
pg_basebackup -h postgres-0.postgres -D /var/lib/postgresql/data -U replicator -W
echo "standby_mode = 'on'" >> /var/lib/postgresql/data/recovery.conf
echo "primary_conninfo = 'host=postgres-0.postgres port=5432 user=replicator'" >> /var/lib/postgresql/data/recovery.conf
fi
# 健康检查
livenessProbe:
exec:
command:
- /bin/bash
- -c
- pg_isready -U $POSTGRES_USER -d $POSTGRES_DB
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
exec:
command:
- /bin/bash
- -c
- pg_isready -U $POSTGRES_USER -d $POSTGRES_DB
initialDelaySeconds: 5
periodSeconds: 5
# 资源限制
resources:
requests:
memory: "512Mi"
cpu: "500m"
limits:
memory: "2Gi"
cpu: "1"
volumes:
- name: config
configMap:
name: postgres-config
- name: init-scripts
configMap:
name: postgres-init
# 持久化存储模板
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: fast-ssd
resources:
requests:
storage: 100Gi
supporting_resources:
secret: |
apiVersion: v1
kind: Secret
metadata:
name: postgres-secret
namespace: production
type: Opaque
stringData:
username: "postgres"
password: "secure-password-123"
replication-username: "replicator"
replication-password: "repl-password-456"
configmap: |
apiVersion: v1
kind: ConfigMap
metadata:
name: postgres-config
data:
postgresql.conf: |
# 连接设置
listen_addresses = '*'
port = 5432
max_connections = 200
# 内存设置
shared_buffers = 256MB
effective_cache_size = 1GB
work_mem = 4MB
maintenance_work_mem = 64MB
# WAL设置
wal_level = replica
max_wal_senders = 3
wal_keep_segments = 64
archive_mode = on
archive_command = 'test ! -f /archive/%f && cp %p /archive/%f'
# 日志设置
logging_collector = on
log_directory = '/var/log/postgresql'
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
log_min_duration_statement = 1000
pg_hba.conf: |
# TYPE DATABASE USER ADDRESS METHOD
local all postgres peer
local all all md5
host all all 127.0.0.1/32 md5
host all all ::1/128 md5
host all all 0.0.0.0/0 md5
host replication replicator 0.0.0.0/0 md5
services: |
# 主服务(读写)
apiVersion: v1
kind: Service
metadata:
name: postgres-master
spec:
selector:
app: postgres
role: master
ports:
- port: 5432
targetPort: 5432
---
# 从服务(只读)
apiVersion: v1
kind: Service
metadata:
name: postgres-slave
spec:
selector:
app: postgres
role: slave
ports:
- port: 5432
targetPort: 5432
---
# Headless服务
apiVersion: v1
kind: Service
metadata:
name: postgres
spec:
clusterIP: None
selector:
app: postgres
ports:
- port: 5432
targetPort: 5432yaml
mongodb_replica_set:
statefulset_config: |
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mongodb
namespace: production
spec:
serviceName: mongodb
replicas: 3
selector:
matchLabels:
app: mongodb
template:
metadata:
labels:
app: mongodb
spec:
containers:
- name: mongodb
image: mongo:5.0
env:
- name: MONGO_INITDB_ROOT_USERNAME
valueFrom:
secretKeyRef:
name: mongodb-secret
key: username
- name: MONGO_INITDB_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mongodb-secret
key: password
command:
- mongod
- --replSet
- rs0
- --bind_ip_all
- --auth
- --keyFile
- /etc/mongodb/keyfile
ports:
- containerPort: 27017
name: mongodb
volumeMounts:
- name: data
mountPath: /data/db
- name: keyfile
mountPath: /etc/mongodb
readOnly: true
# 健康检查
livenessProbe:
exec:
command:
- mongo
- --eval
- "db.adminCommand('ping')"
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
exec:
command:
- mongo
- --eval
- "db.adminCommand('ping')"
initialDelaySeconds: 5
periodSeconds: 5
resources:
requests:
memory: "1Gi"
cpu: "500m"
limits:
memory: "4Gi"
cpu: "2"
# 初始化容器:配置副本集
initContainers:
- name: mongodb-init
image: mongo:5.0
env:
- name: MONGO_INITDB_ROOT_USERNAME
valueFrom:
secretKeyRef:
name: mongodb-secret
key: username
- name: MONGO_INITDB_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mongodb-secret
key: password
command:
- /bin/bash
- -c
- |
# 等待MongoDB启动
until mongo --eval "print('MongoDB is ready')"; do
echo "Waiting for MongoDB to be ready..."
sleep 2
done
# 初始化副本集(仅在第一个Pod上执行)
if [[ "${HOSTNAME}" == "mongodb-0" ]]; then
mongo --eval "
rs.initiate({
_id: 'rs0',
members: [
{ _id: 0, host: 'mongodb-0.mongodb.production.svc.cluster.local:27017' },
{ _id: 1, host: 'mongodb-1.mongodb.production.svc.cluster.local:27017' },
{ _id: 2, host: 'mongodb-2.mongodb.production.svc.cluster.local:27017' }
]
})
"
fi
volumes:
- name: keyfile
secret:
secretName: mongodb-keyfile
defaultMode: 0400
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: fast-ssd
resources:
requests:
storage: 200Gi
replica_set_management:
initialization_job: |
# MongoDB副本集初始化Job
apiVersion: batch/v1
kind: Job
metadata:
name: mongodb-init-replica-set
spec:
template:
spec:
containers:
- name: mongodb-init
image: mongo:5.0
env:
- name: MONGODB_USERNAME
valueFrom:
secretKeyRef:
name: mongodb-secret
key: username
- name: MONGODB_PASSWORD
valueFrom:
secretKeyRef:
name: mongodb-secret
key: password
command:
- /bin/bash
- -c
- |
# 连接到第一个MongoDB实例
mongo mongodb-0.mongodb.production.svc.cluster.local:27017 \
-u $MONGODB_USERNAME -p $MONGODB_PASSWORD --authenticationDatabase admin \
--eval "
try {
rs.initiate({
_id: 'rs0',
members: [
{ _id: 0, host: 'mongodb-0.mongodb.production.svc.cluster.local:27017', priority: 3 },
{ _id: 1, host: 'mongodb-1.mongodb.production.svc.cluster.local:27017', priority: 2 },
{ _id: 2, host: 'mongodb-2.mongodb.production.svc.cluster.local:27017', priority: 1 }
]
});
print('Replica set initiated successfully');
} catch (e) {
print('Replica set already exists or error:', e);
}
"
restartPolicy: OnFailure
monitoring_script: |
#!/bin/bash
# MongoDB副本集监控脚本
check_replica_set_status() {
for i in {0..2}; do
echo "Checking mongodb-$i status..."
# 检查副本集状态
mongo mongodb-$i.mongodb.production.svc.cluster.local:27017 \
-u $MONGODB_USERNAME -p $MONGODB_PASSWORD \
--authenticationDatabase admin \
--quiet --eval "
rs.status().members.forEach(function(member) {
print(member.name + ': ' + member.stateStr);
});
"
done
}
check_replication_lag() {
echo "Checking replication lag..."
mongo mongodb-0.mongodb.production.svc.cluster.local:27017 \
-u $MONGODB_USERNAME -p $MONGODB_PASSWORD \
--authenticationDatabase admin \
--quiet --eval "
rs.printSlaveReplicationInfo();
"
}
# 主函数
main() {
echo "MongoDB Replica Set Health Check"
echo "================================"
check_replica_set_status
echo ""
check_replication_lag
}
main⚡ StatefulSet高级特性
滚动更新策略
yaml
update_strategies:
rolling_update:
configuration: |
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: redis
spec:
updateStrategy:
type: RollingUpdate
rollingUpdate:
# 分批更新配置
partition: 0 # 从最高序号开始更新
# 更新策略详解
# partition: 2 表示只更新序号 >= 2 的Pod
# partition: 0 表示更新所有Pod
controlled_rollout: |
# 分阶段更新脚本
#!/bin/bash
STATEFULSET="redis"
REPLICAS=5
# 阶段1:更新最后一个Pod
kubectl patch statefulset $STATEFULSET -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":4}}}}'
kubectl wait --for=condition=ready pod/${STATEFULSET}-4 --timeout=300s
# 验证Pod健康状态
if kubectl get pod ${STATEFULSET}-4 -o jsonpath='{.status.phase}' | grep -q "Running"; then
echo "Pod ${STATEFULSET}-4 updated successfully"
else
echo "Update failed, rolling back..."
kubectl rollout undo statefulset/$STATEFULSET
exit 1
fi
# 阶段2:更新倒数第二个Pod
kubectl patch statefulset $STATEFULSET -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":3}}}}'
kubectl wait --for=condition=ready pod/${STATEFULSET}-3 --timeout=300s
# 继续更新其余Pod...
for i in $(seq 2 -1 0); do
kubectl patch statefulset $STATEFULSET -p "{\"spec\":{\"updateStrategy\":{\"rollingUpdate\":{\"partition\":$i}}}}"
kubectl wait --for=condition=ready pod/${STATEFULSET}-$i --timeout=300s
# 验证应用健康状态
./verify-redis-cluster-health.sh
if [ $? -ne 0 ]; then
echo "Health check failed at pod $i, stopping update"
exit 1
fi
done
echo "StatefulSet update completed successfully"
on_delete_strategy:
configuration: |
spec:
updateStrategy:
type: OnDelete
manual_update_process: |
# 手动更新流程
update_statefulset_manually() {
local statefulset=$1
local replicas=$2
echo "Starting manual update of $statefulset"
# 更新StatefulSet模板
kubectl apply -f $statefulset-updated.yaml
# 手动删除Pod进行更新
for i in $(seq $((replicas-1)) -1 0); do
echo "Updating ${statefulset}-${i}..."
# 删除Pod
kubectl delete pod ${statefulset}-${i}
# 等待Pod重新创建并就绪
kubectl wait --for=condition=ready pod/${statefulset}-${i} --timeout=300s
# 验证Pod健康状态
if ! verify_pod_health ${statefulset}-${i}; then
echo "Pod ${statefulset}-${i} failed health check"
return 1
fi
echo "Pod ${statefulset}-${i} updated successfully"
sleep 10 # 等待间隔
done
echo "Manual update completed"
}yaml
scaling_management:
horizontal_scaling:
scale_up: |
# 扩容操作
kubectl scale statefulset postgres --replicas=5
# 等待新Pod就绪
kubectl wait --for=condition=ready pod/postgres-3 --timeout=300s
kubectl wait --for=condition=ready pod/postgres-4 --timeout=300s
# 对于数据库,需要手动将新节点加入集群
add_postgres_replica() {
local new_replica=$1
# 在主节点上创建复制槽
kubectl exec postgres-0 -- psql -U postgres -c "
SELECT pg_create_physical_replication_slot('slot_${new_replica}');
"
# 配置新从节点
kubectl exec $new_replica -- bash -c "
pg_basebackup -h postgres-0 -D /var/lib/postgresql/data -U replicator -W -S slot_${new_replica}
echo \"standby_mode = 'on'\" >> /var/lib/postgresql/data/recovery.conf
echo \"primary_conninfo = 'host=postgres-0 port=5432 user=replicator'\" >> /var/lib/postgresql/data/recovery.conf
echo \"primary_slot_name = 'slot_${new_replica}'\" >> /var/lib/postgresql/data/recovery.conf
"
}
scale_down: |
# 缩容操作(需要特别小心)
scale_down_statefulset() {
local statefulset=$1
local current_replicas=$2
local target_replicas=$3
echo "Scaling down $statefulset from $current_replicas to $target_replicas"
# 对于数据库,需要先处理数据迁移和复制关系
for i in $(seq $((current_replicas-1)) -1 $target_replicas); do
echo "Preparing to remove ${statefulset}-${i}..."
# 如果是从节点,从主节点移除复制槽
if [ "$i" -gt 0 ]; then
kubectl exec ${statefulset}-0 -- psql -U postgres -c "
SELECT pg_drop_replication_slot('slot_${statefulset}_${i}');
"
fi
# 备份重要数据(如果需要)
backup_pod_data ${statefulset}-${i}
echo "Removing ${statefulset}-${i}"
done
# 执行缩容
kubectl scale statefulset $statefulset --replicas=$target_replicas
# 清理孤立的PVC(可选,根据策略决定)
cleanup_orphaned_pvcs $statefulset $target_replicas $current_replicas
}
storage_expansion:
volume_expansion: |
# 存储扩容(需要StorageClass支持)
expand_storage() {
local statefulset=$1
local new_size=$2
echo "Expanding storage for $statefulset to $new_size"
# 获取当前副本数
replicas=$(kubectl get statefulset $statefulset -o jsonpath='{.spec.replicas}')
# 逐个扩展PVC
for i in $(seq 0 $((replicas-1))); do
pvc_name="data-${statefulset}-${i}"
echo "Expanding PVC $pvc_name to $new_size"
kubectl patch pvc $pvc_name -p "{\"spec\":{\"resources\":{\"requests\":{\"storage\":\"$new_size\"}}}}"
# 等待扩展完成
kubectl wait --for=condition=FileSystemResizePending=false pvc/$pvc_name --timeout=300s
# 重启Pod以识别新的存储大小
kubectl delete pod ${statefulset}-${i}
kubectl wait --for=condition=ready pod/${statefulset}-${i} --timeout=300s
echo "Storage expansion completed for ${statefulset}-${i}"
done
}
automated_expansion: |
# 自动化存储监控和扩展
apiVersion: v1
kind: ConfigMap
metadata:
name: storage-monitor
data:
monitor.sh: |
#!/bin/bash
# 监控存储使用率
monitor_storage_usage() {
local threshold=80 # 使用率阈值
# 获取所有StatefulSet的PVC
kubectl get pvc -l app.kubernetes.io/managed-by=statefulset -o json | \
jq -r '.items[] | "\(.metadata.name) \(.metadata.namespace)"' | \
while read pvc_name namespace; do
# 获取对应的Pod
pod_name=$(echo $pvc_name | sed 's/data-//')
# 检查存储使用率
usage=$(kubectl exec $pod_name -n $namespace -- df -h /data | awk 'NR==2 {print $5}' | sed 's/%//')
if [ "$usage" -gt "$threshold" ]; then
echo "Storage usage for $pvc_name is ${usage}%, triggering expansion"
expand_pvc_storage $pvc_name $namespace
fi
done
}
expand_pvc_storage() {
local pvc_name=$1
local namespace=$2
local current_size=$(kubectl get pvc $pvc_name -n $namespace -o jsonpath='{.spec.resources.requests.storage}')
# 扩展到当前大小的1.5倍
local new_size=$(echo $current_size | sed 's/Gi//' | awk '{print int($1*1.5)"Gi"}')
kubectl patch pvc $pvc_name -n $namespace -p "{\"spec\":{\"resources\":{\"requests\":{\"storage\":\"$new_size\"}}}}"
# 发送告警通知
send_alert "PVC $pvc_name expanded from $current_size to $new_size"
}
# 主循环
while true; do
monitor_storage_usage
sleep 300 # 每5分钟检查一次
done🔧 StatefulSet运维实践
备份与恢复
yaml
backup_strategies:
scheduled_backup:
cronjob_config: |
apiVersion: batch/v1
kind: CronJob
metadata:
name: postgres-backup
namespace: production
spec:
schedule: "0 2 * * *" # 每天凌晨2点
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 3
jobTemplate:
spec:
template:
spec:
containers:
- name: postgres-backup
image: postgres:14-alpine
env:
- name: POSTGRES_HOST
value: "postgres-0.postgres"
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: postgres-secret
key: username
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-secret
key: password
- name: BACKUP_RETENTION_DAYS
value: "30"
command:
- /bin/bash
- -c
- |
# 创建备份目录
BACKUP_DIR="/backup/postgres/$(date +%Y-%m-%d)"
mkdir -p $BACKUP_DIR
# 创建数据库备份
pg_dump -h $POSTGRES_HOST -U $POSTGRES_USER -d myapp \
--no-password --verbose --format=custom \
--file=$BACKUP_DIR/myapp_$(date +%H%M%S).backup
# 备份全局对象(用户、角色等)
pg_dumpall -h $POSTGRES_HOST -U $POSTGRES_USER \
--no-password --globals-only \
--file=$BACKUP_DIR/globals_$(date +%H%M%S).sql
# 上传到对象存储
aws s3 sync $BACKUP_DIR s3://database-backups/postgres/$(date +%Y-%m-%d)/
# 清理本地备份文件
rm -rf $BACKUP_DIR
# 清理过期的S3备份
aws s3 ls s3://database-backups/postgres/ | \
awk '{print $2}' | \
while read date_dir; do
if [[ $(date -d "$date_dir" +%s) -lt $(date -d "$BACKUP_RETENTION_DAYS days ago" +%s) ]]; then
aws s3 rm s3://database-backups/postgres/$date_dir --recursive
fi
done
volumeMounts:
- name: backup-volume
mountPath: /backup
- name: aws-credentials
mountPath: /root/.aws
readOnly: true
volumes:
- name: backup-volume
emptyDir: {}
- name: aws-credentials
secret:
secretName: aws-credentials
restartPolicy: OnFailure
continuous_backup:
wal_archiving: |
# PostgreSQL WAL归档配置
postgresql_config:
archive_mode: "on"
archive_command: "aws s3 cp %p s3://database-wal-archive/postgres/%f"
archive_timeout: "300s"
# WAL恢复脚本
recovery_script: |
#!/bin/bash
restore_from_backup() {
local backup_date=$1
local target_time=$2
echo "Starting point-in-time recovery to $target_time"
# 停止数据库
kubectl scale statefulset postgres --replicas=0
# 清理数据目录
kubectl exec postgres-0 -- rm -rf /var/lib/postgresql/data/*
# 恢复基础备份
aws s3 cp s3://database-backups/postgres/$backup_date/myapp.backup /tmp/
kubectl cp /tmp/myapp.backup postgres-0:/tmp/
# 恢复数据
kubectl exec postgres-0 -- pg_restore -U postgres -d myapp /tmp/myapp.backup
# 配置WAL恢复
kubectl exec postgres-0 -- bash -c "
echo \"restore_command = 'aws s3 cp s3://database-wal-archive/postgres/%f %p'\" >> /var/lib/postgresql/data/recovery.conf
echo \"recovery_target_time = '$target_time'\" >> /var/lib/postgresql/data/recovery.conf
echo \"recovery_target_action = 'promote'\" >> /var/lib/postgresql/data/recovery.conf
"
# 启动数据库
kubectl scale statefulset postgres --replicas=1
echo "Point-in-time recovery completed"
}yaml
monitoring_alerting:
prometheus_monitoring:
postgres_exporter: |
# PostgreSQL Exporter部署
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres-exporter
spec:
replicas: 1
selector:
matchLabels:
app: postgres-exporter
template:
spec:
containers:
- name: postgres-exporter
image: prometheuscommunity/postgres-exporter:v0.11.1
env:
- name: DATA_SOURCE_NAME
valueFrom:
secretKeyRef:
name: postgres-monitoring-secret
key: data-source-name
ports:
- containerPort: 9187
name: metrics
# 自定义监控查询
volumeMounts:
- name: queries
mountPath: /etc/postgres_exporter
volumes:
- name: queries
configMap:
name: postgres-exporter-queries
monitoring_queries: |
apiVersion: v1
kind: ConfigMap
metadata:
name: postgres-exporter-queries
data:
queries.yaml: |
# 复制延迟监控
pg_replication_lag:
query: "SELECT client_addr, pg_wal_lsn_diff(pg_current_wal_lsn(), flush_lsn) as lag_bytes FROM pg_stat_replication"
master: true
metrics:
- client_addr:
usage: "LABEL"
description: "Client address"
- lag_bytes:
usage: "GAUGE"
description: "Replication lag in bytes"
# 数据库大小监控
pg_database_size:
query: "SELECT datname, pg_database_size(datname) as size_bytes FROM pg_database WHERE datistemplate = false"
master: true
metrics:
- datname:
usage: "LABEL"
description: "Database name"
- size_bytes:
usage: "GAUGE"
description: "Database size in bytes"
# 表大小监控
pg_table_size:
query: "SELECT schemaname, tablename, pg_total_relation_size(schemaname||'.'||tablename) as size_bytes FROM pg_tables WHERE schemaname NOT IN ('information_schema', 'pg_catalog')"
master: true
metrics:
- schemaname:
usage: "LABEL"
description: "Schema name"
- tablename:
usage: "LABEL"
description: "Table name"
- size_bytes:
usage: "GAUGE"
description: "Table size in bytes"
alert_rules:
prometheus_rules: |
groups:
- name: statefulset-alerts
rules:
- alert: StatefulSetReplicasMismatch
expr: kube_statefulset_status_replicas != kube_statefulset_spec_replicas
for: 5m
labels:
severity: critical
annotations:
summary: "StatefulSet replicas mismatch"
description: "StatefulSet {{ $labels.statefulset }} has {{ $value }} replicas but should have {{ $labels.spec_replicas }}"
- alert: StatefulSetUpdateBlocked
expr: kube_statefulset_status_current_revision != kube_statefulset_status_update_revision
for: 10m
labels:
severity: warning
annotations:
summary: "StatefulSet update is blocked"
description: "StatefulSet {{ $labels.statefulset }} update has been blocked for more than 10 minutes"
- alert: PostgreSQLDown
expr: up{job="postgres-exporter"} == 0
for: 1m
labels:
severity: critical
annotations:
summary: "PostgreSQL is down"
description: "PostgreSQL instance {{ $labels.instance }} has been down for more than 1 minute"
- alert: PostgreSQLReplicationLag
expr: pg_replication_lag_bytes > 100*1024*1024 # 100MB
for: 2m
labels:
severity: critical
annotations:
summary: "High PostgreSQL replication lag"
description: "Replication lag is {{ $value | humanizeBytes }} for client {{ $labels.client_addr }}"
- alert: PostgreSQLTooManyConnections
expr: pg_stat_database_numbackends / pg_settings_max_connections * 100 > 80
for: 5m
labels:
severity: warning
annotations:
summary: "PostgreSQL too many connections"
description: "PostgreSQL connection usage is {{ $value }}%"📋 StatefulSet面试重点
基础概念类
StatefulSet与Deployment的核心区别?
- Pod身份稳定性
- 网络标识管理
- 存储绑定机制
- 部署和扩展顺序
StatefulSet的三个保证?
- 稳定的网络标识
- 稳定的持久化存储
- 有序的部署和扩展
Headless Service的作用?
- DNS解析机制
- Pod直接访问
- 服务发现模式
- 负载均衡策略
部署配置类
如何设计数据库StatefulSet?
- 主从复制配置
- 健康检查设计
- 初始化容器使用
- 资源限制策略
VolumeClaimTemplate的工作原理?
- 动态PVC创建
- 存储绑定关系
- 回收策略配置
- 存储类选择
StatefulSet滚动更新策略?
- RollingUpdate配置
- Partition参数作用
- OnDelete更新模式
- 更新回滚机制
运维实践类
如何安全地扩缩容StatefulSet?
- 数据迁移策略
- 集群重新配置
- PVC处理方式
- 服务可用性保证
StatefulSet备份和恢复策略?
- 快照备份机制
- WAL归档策略
- 点对点时间恢复
- 跨集群灾难恢复
如何监控StatefulSet健康状态?
- 关键监控指标
- 告警规则设计
- 性能基线建立
- 故障预警机制
高级特性类
StatefulSet的Pod管理策略?
- OrderedReady vs Parallel
- 启动依赖处理
- 失败恢复机制
- 数据一致性保证
如何处理StatefulSet的网络分区?
- 脑裂检测机制
- 自动故障转移
- 数据同步恢复
- 服务降级策略
StatefulSet与Operator的关系?
- Operator增强功能
- 自动化运维能力
- 状态管理复杂度
- 选择决策因素
🔗 相关内容
- 数据管理概述 - 云原生数据管理架构
- Kubernetes Operator - Operator模式详解
- 云原生数据库 - 云原生数据库解决方案
- 持久化存储 - Kubernetes存储管理
StatefulSet是Kubernetes中部署有状态应用的核心工具,掌握其工作原理、配置方法和运维实践对于管理云原生数据平台至关重要。通过合理设计StatefulSet配置和完善的监控备份机制,可以构建稳定可靠的数据服务平台。
