生产部署
本章将学习如何在生产环境中部署、运维和监控 etcd 集群。
生产架构设计
集群拓扑
单机房部署
┌──────────────────────────────────────────────────────────┐
│ 机房 A │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Node 1 │ │ Node 2 │ │ Node 3 │ │
│ │ (Leader) │◄──►│(Follower)│◄──►│(Follower)│ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ 网络延迟 < 10ms │
└──────────────────────────────────────────────────────────┘适用场景:
- 中小型企业
- 网络延迟低
- 运维简单
跨机房部署
┌─────────────────┐ ┌─────────────────┐
│ 机房 A │ │ 机房 B │
│ │ │ │
│ ┌──────────┐ │ │ ┌──────────┐ │
│ │ Node 1 │ │◄────────►│ │ Node 2 │ │
│ │ (Leader) │ │ │ │(Follower)│ │
│ └──────────┘ │ │ └──────────┘ │
│ │ │ │
│ ┌──────────┐ │ │ ┌──────────┐ │
│ │ Node 3 │ │ │ │ Node 4 │ │
│ │(Follower)│◄─┼─────────┼─►│(Follower)│ │
│ └──────────┘ │ │ └──────────┘ │
│ │ │ │
└─────────────────┘ └─────────────────┘
注意:跨机房网络延迟应尽量低(建议 < 50ms)适用场景:
- 大型企业
- 容灾要求高
- 网络稳定
节点规划
| 集群规模 | 容忍故障数 | 适用场景 |
|---|---|---|
| 3 节点 | 1 | 小规模生产 |
| 5 节点 | 2 | 中规模生产 |
| 7 节点 | 3 | 大规模生产 |
硬件要求
| 项目 | 最低要求 | 推荐配置 |
|---|---|---|
| CPU | 2 核 | 4-8 核 |
| 内存 | 8 GB | 16-32 GB |
| 存储 | 10 GB | 50-100 GB SSD |
| 网络 | 1 Gbps | 10 Gbps |
关键要求:
- SSD 存储:顺序写入性能至关重要
- 低延迟网络:节点间延迟 < 10ms(同机房)
- 独立部署:避免与其他服务竞争资源
Kubernetes 部署
StatefulSet 配置
yaml
apiVersion: v1
kind: Service
metadata:
name: etcd
labels:
app: etcd
spec:
clusterIP: None
ports:
- port: 2379
name: client
- port: 2380
name: peer
selector:
app: etcd
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: etcd
spec:
serviceName: etcd
replicas: 3
selector:
matchLabels:
app: etcd
template:
metadata:
labels:
app: etcd
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: etcd
topologyKey: kubernetes.io/hostname
containers:
- name: etcd
image: quay.io/coreos/etcd:v3.5.17
ports:
- containerPort: 2379
name: client
- containerPort: 2380
name: peer
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
command:
- /bin/sh
- -c
- |
PEERS="etcd-0=http://etcd-0.etcd:2380,etcd-1=http://etcd-1.etcd:2380,etcd-2=http://etcd-2.etcd:2380"
exec etcd --name ${POD_NAME} \
--data-dir /var/lib/etcd \
--listen-client-urls http://0.0.0.0:2379 \
--advertise-client-urls http://${POD_NAME}.etcd.${POD_NAMESPACE}.svc.cluster.local:2379 \
--listen-peer-urls http://0.0.0.0:2380 \
--initial-advertise-peer-urls http://${POD_NAME}.etcd.${POD_NAMESPACE}.svc.cluster.local:2380 \
--initial-cluster ${PEERS} \
--initial-cluster-token my-etcd-cluster \
--initial-cluster-state new \
--snapshot-count 10000 \
--heartbeat-interval 100 \
--election-timeout 1000
volumeMounts:
- name: etcd-data
mountPath: /var/lib/etcd
resources:
requests:
cpu: 500m
memory: 1Gi
limits:
cpu: 2
memory: 4Gi
volumeClaimTemplates:
- metadata:
name: etcd-data
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: ssd-storage
resources:
requests:
storage: 50Gi持久化存储
使用 StorageClass 配置 SSD 存储:
yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ssd-storage
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp3
fsType: ext4
volumeBindingMode: WaitForFirstConsumer性能调优
关键参数
bash
# 心跳和选举超时
--heartbeat-interval=100 # 心跳间隔(毫秒)
--election-timeout=1000 # 选举超时(毫秒)
# 快照和压缩
--snapshot-count=10000 # 触发快照的日志数
--auto-compaction-retention=1h # 自动压缩保留时间
--auto-compaction-mode=periodic # 压缩模式
# quota
--quota-backend-bytes=8589934592 # 数据上限(8GB)
# 性能
--max-request-bytes=15728640 # 单次请求最大字节数(15MB)
--max-txn-ops=128 # 单次事务最大操作数性能基准
bash
# 运行性能基准测试
etcdctl check perf --load=s
# 输出
Pass: read-only requests are within limit.
Pass: read-write requests are within limit.
Pass: write-only requests are within limit.性能指标
| 指标 | 目标值 |
|---|---|
| P99 读延迟 | < 10ms |
| P99 写延迟 | < 20ms |
| QPS | 10,000+ |
| 数据大小 | < 8GB |
监控告警
Prometheus 指标
etcd 提供丰富的 Prometheus 指标:
# 集群健康
etcd_server_has_leader
etcd_server_leader_changes_seen_total
# 性能
etcd_server_read_indexes_failed_total
etcd_server_slow_read_indexes_total
etcd_mvcc_db_total_size_in_bytes
etcd_disk_wal_fsync_duration_seconds_sum
etcd_disk_backend_commit_duration_seconds_sum
# 网络
etcd_network_peer_received_bytes_total
etcd_network_peer_sent_bytes_total
etcd_network_client_received_bytes_total
etcd_network_client_sent_bytes_total
# Raft
etcd_raft_proposal_failed_total
etcd_raft_proposal_committed_total
etcd_raft_proposal_applied_totalPrometheus 配置
yaml
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'etcd'
static_configs:
- targets:
- 'etcd-0:2379'
- 'etcd-1:2379'
- 'etcd-2:2379'
metrics_path: '/metrics'关键告警规则
yaml
groups:
- name: etcd-alerts
rules:
# Leader 变更频繁
- alert: EtcdLeaderChangesFrequent
expr: increase(etcd_server_leader_changes_seen_total[1h]) > 10
for: 5m
severity: warning
message: "etcd Leader 变更频繁"
# 没有 Leader
- alert: EtcdNoLeader
expr: etcd_server_has_leader == 0
for: 1m
severity: critical
message: "etcd 集群没有 Leader"
# 数据库过大
- alert: EtcdDatabaseSizeTooLarge
expr: etcd_mvcc_db_total_size_in_bytes > 8589934592
for: 5m
severity: warning
message: "etcd 数据库大小超过 8GB"
#慢请求
- alert: EtcdSlowRequests
expr: etcd_server_slow_read_indexes_total > 100
for: 5m
severity: warning
message: "etcd 慢请求过多"
# 磁盘延迟高
- alert: EtcdDiskFsyncSlow
expr: histogram_quantile(0.99, rate(etcd_disk_wal_fsync_duration_seconds_bucket[5m])) > 0.1
for: 5m
severity: warning
message: "etcd WAL fsync 延迟过高"Grafana Dashboard
使用官方 Dashboard:
关键监控面板:
- 集群健康状态
- 读写 QPS 和延迟
- 数据库大小
- 网络流量
- Leader 变更次数
维护操作
数据备份
bash
# 创建快照
etcdctl snapshot save /backup/etcd-$(date +%Y%m%d-%H%M%S).db \
--endpoints=https://etcd-0:2379 \
--cacert=/etc/etcd/ca.pem \
--cert=/etc/etcd/client.pem \
--key=/etc/etcd/client-key.pem
# 查看快照状态
etcdctl snapshot status /backup/etcd-20250106-120000.db -w table
# 输出
+----------+----------+------------+------------+
| HASH | REVISION | TOTAL KEYS | TOTAL SIZE |
+----------+----------+------------+------------+
| 2a56c3e8 | 1024 | 256 | 1.2 MB |
+----------+----------+------------+------------+自动备份脚本
bash
#!/bin/bash
# etcd-backup.sh
BACKUP_DIR="/backup/etcd"
DATE=$(date +%Y%m%d-%H%M%S)
BACKUP_FILE="${BACKUP_DIR}/etcd-${DATE}.db"
# 创建快照
etcdctl snapshot save ${BACKUP_FILE}
# 检查快照
if etcdctl snapshot status ${BACKUP_FILE} &>/dev/null; then
echo "Backup succeeded: ${BACKUP_FILE}"
else
echo "Backup failed"
rm -f ${BACKUP_FILE}
exit 1
fi
# 清理旧备份(保留 7 天)
find ${BACKUP_DIR} -name "etcd-*.db" -mtime +7 -delete
# 上传到远程存储(示例:AWS S3)
aws s3 cp ${BACKUP_FILE} s3://my-bucket/etcd-backups/数据恢复
bash
# 1. 停止所有 etcd 节点
kubectl delete statefulset etcd
# 2. 在每个节点上恢复数据
for i in 0 1 2; do
etcdctl snapshot restore /backup/etcd-20250106-120000.db \
--name etcd-${i} \
--data-dir /var/lib/etcd-${i} \
--initial-cluster etcd-0=http://etcd-0.etcd:2380,etcd-1=http://etcd-1.etcd:2380,etcd-2=http://etcd-2.etcd:2380 \
--initial-cluster-token my-etcd-cluster \
--initial-advertise-peer-urls http://etcd-${i}.etcd:2380
done
# 3. 启动 etcd 集群(使用 --initial-cluster-state new)
kubectl apply -f etcd-statefulset.yaml数据压缩
bash
# 获取当前 revision
REVISION=$(etcdctl endpoint status --write-out="json" | grep -o '"revision":[0-9]*' | head -1 | grep -o '[0-9]*')
# 压缩历史版本
etcdctl compact ${REVISION}
# 碎片整理
etcdctl defrag --endpoints=http://etcd-0:2379,http://etcd-1:2379,http://etcd-2:2379
# 检查数据库大小
etcdctl endpoint status --write-out="table"自动压缩配置
bash
# 启动时配置自动压缩
etcd \
--auto-compaction-retention=1h \
--auto-compaction-mode=periodic添加成员
bash
# 添加新成员(先作为 learner)
etcdctl member add etcd-3 \
--peer-urls=http://etcd-3:2380 \
--learner=true
# 启动新节点
etcd \
--name etcd-3 \
--data-dir /var/lib/etcd \
--listen-client-urls http://0.0.0.0:2379 \
--advertise-client-urls http://etcd-3:2379 \
--listen-peer-urls http://0.0.0.0:2380 \
--initial-advertise-peer-urls http://etcd-3:2380 \
--initial-cluster-state existing
# 提升为正式成员
etcdctl member promote <member-id>移除成员
bash
# 查看成员列表
etcdctl member list -w table
# 移除成员
etcdctl member remove <member-id>
# 被移除节点需要清空数据目录才能重新加入安全加固
TLS 配置
bash
# 客户端 TLS
etcd \
--client-cert-auth \
--trusted-ca-file /etc/etcd/ca.pem \
--cert-file /etc/etcd/server.pem \
--key-file /etc/etcd/server-key.pem
# 对等 TLS
etcd \
--peer-client-cert-auth \
--peer-trusted-ca-file /etc/etcd/ca.pem \
--peer-cert-file /etc/etcd/peer.pem \
--peer-key-file /etc/etcd/peer-key.pemRBAC 配置
bash
# 启用认证
etcdctl auth enable
# 创建用户和角色
etcdctl user add root
etcdctl user add app-user
etcdctl role add app-role
etcdctl role grant-permission app-role readwrite /app/
etcdctl user grant-role app-user app-role
# 测试认证
etcdctl --user app-user:password get /app/config证书自动轮换
使用 cert-manager 自动管理证书:
yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: etcd-server
spec:
secretName: etcd-server-tls
issuerRef:
name: etcd-ca
kind: Issuer
commonName: etcd
dnsNames:
- etcd-0.etcd
- etcd-1.etcd
- etcd-2.etcd
- localhost
duration: 2160h # 90 天
renewBefore: 360h # 自动续期故障处理
节点故障
bash
# 检查节点状态
etcdctl endpoint health --cluster
# 输出
http://etcd-0:2379 is healthy: successfully committed proposal: took = 1.2ms
http://etcd-1:2379 is unhealthy: failed to connect
http://etcd-2:2379 is healthy: successfully committed proposal: took = 1.5ms
# 移除故障节点
etcdctl member remove <member-id>
# 添加新节点替换
etcdctl member add etcd-1-new --peer-urls=http://etcd-1-new:2380Leader 选举失败
bash
# 检查 Leader 状态
etcdctl endpoint status --cluster -w table
# 如果无 Leader,检查网络和磁盘
# 重启节点尝试恢复数据损坏
bash
# 从健康节点恢复数据
# 1. 创建快照
etcdctl snapshot save /backup/etcd-recovery.db
# 2. 在损坏节点上恢复
etcdctl snapshot restore /backup/etcd-recovery.db \
--name etcd-0 \
--data-dir /var/lib/etcd \
--initial-cluster-state new网络分区
bash
# 检查集群状态
etcdctl endpoint status --cluster
# 如果发生网络分区:
# 1. 确认多数派节点可达
# 2. 多数派继续工作
# 3. 少数派节点等待网络恢复
# 4. 网络恢复后自动同步运维最佳实践
日常运维检查清单
| 检查项 | 命令 | 频率 |
|---|---|---|
| 集群健康 | etcdctl endpoint health --cluster | 每小时 |
| 数据库大小 | etcdctl endpoint status --cluster | 每天 |
| 备份状态 | etcdctl snapshot status | 每天备份后 |
| 证书有效期 | 检查证书到期时间 | 每月 |
| 性能基准 | etcdctl check perf | 每周 |
性能优化建议
存储优化
- 使用 SSD 存储
- 定期压缩和碎片整理
- 控制数据大小 < 8GB
网络优化
- 同机房部署,延迟 < 10ms
- 使用高速网络(10 Gbps)
- 避免 NAT 和代理
调优配置
- 根据负载调整心跳和选举超时
- 合理设置快照阈值
- 启用自动压缩
容灾策略
备份策略
- 每天创建快照备份
- 备份存储到远程存储
- 定期验证恢复流程
多机房部署
- 跨机房部署至少 3 个节点
- 网络延迟 < 50ms
- 节点分布在不同机房
故障演练
- 定期进行故障演练
- 验证自动恢复流程
- 测试备份恢复
Kubernetes etcd 特殊注意
Kubernetes 集群状态
- etcd 存储 Kubernetes 所有状态
- etcd 故障会导致 Kubernetes 不可用
- 必须定期备份
资源隔离
- etcd 独立部署
- 使用专用的 SSD 存储
- 避免资源竞争
监控集成
- 监控 Kubernetes API Server 对 etcd 的访问
- 监控 etcd 响应时间
- 设置合理的告警阈值
总结
生产部署 etcd 需要关注:
- 架构设计:集群拓扑、节点规划、硬件配置
- 性能调优:参数配置、性能基准、监控指标
- 运维管理:数据备份、恢复、压缩、成员管理
- 安全加固:TLS 配置、RBAC、证书管理
- 故障处理:节点故障、数据损坏、网络分区
- 最佳实践:日常检查、性能优化、容灾策略
掌握这些运维知识,才能保障 etcd 集群在生产环境中稳定运行。