核心概念 - 集群管理
etcd 集群的管理是运维工作的核心。本章将学习如何搭建、配置和管理 etcd 集群。
集群架构
节点角色
etcd 集群中的每个节点都是平等的,没有主从之分,但 Raft 会选举出 Leader。
┌───────────────────────────────────────────────────────┐
│ etcd 群 │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Node 1 │◄──►│ Node 2 │◄──►│ Node 3 │ │
│ │ (Leader) │ │(Follower)│ │(Follower)│ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ 客户端端口: 2379 对等端口: 2380 │
└───────────────────────────────────────────────────────┘集群规模
| 集群大小 | 容忍故障节点数 | 适用场景 |
|---|---|---|
| 1 | 0 | 开发测试 |
| 3 | 1 | 生产环境(推荐) |
| 5 | 2 | 高可用生产环境 |
| 7 | 3 | 关键业务 |
推荐奇数节点,因为:
- 多数派要求:至少 N/2 + 1 个节点存活
- 3 个节点可以容忍 1 个故障
- 4 个节点也只能容忍 1 个故障(不比 3 强)
集群搭建
静态配置
预先知道所有节点地址,适合小规模集群。
本地开发集群
bash
# 启动 3 节点本地集群
# 节点 1
docker run -d --name etcd-node1 \
-p 2379:2379 -p 2380:2380 \
quay.io/coreos/etcd:v3.5.17 \
/usr/local/bin/etcd \
--name node1 \
--data-dir /etcd-data \
--listen-client-urls http://0.0.0.0:2379 \
--advertise-client-urls http://node1:2379 \
--listen-peer-urls http://0.0.0.0:2380 \
--initial-advertise-peer-urls http://node1:2380 \
--initial-cluster node1=http://node1:2380,node2=http://node2:2380,node3=http://node3:2380 \
--initial-cluster-token my-etcd-cluster \
--initial-cluster-state new
# 节点 2
docker run -d --name etcd-node2 \
-p 22379:2379 -p 22380:2380 \
quay.io/coreos/etcd:v3.5.17 \
/usr/local/bin/etcd \
--name node2 \
--data-dir /etcd-data \
--listen-client-urls http://0.0.0.0:2379 \
--advertise-client-urls http://node2:2379 \
--listen-peer-urls http://0.0.0.0:2380 \
--initial-advertise-peer-urls http://node2:2380 \
--initial-cluster node1=http://node1:2380,node2=http://node2:2380,node3=http://node3:2380 \
--initial-cluster-token my-etcd-cluster \
--initial-cluster-state new
# 节点 3
docker run -d --name etcd-node3 \
-p 32379:2379 -p 32380:2380 \
quay.io/coreos/etcd:v3.5.17 \
/usr/local/bin/etcd \
--name node3 \
--data-dir /etcd-data \
--listen-client-urls http://0.0.0.0:2379 \
--advertise-client-urls http://node3:2379 \
--listen-peer-urls http://0.0.0.0:2380 \
--initial-advertise-peer-urls http://node3:2380 \
--initial-cluster node1=http://node1:2380,node2=http://node2:2380,node3=http://node3:2380 \
--initial-cluster-token my-etcd-cluster \
--initial-cluster-state new生产环境配置
bash
# 节点配置示例
etcd \
--name etcd-node1 \
--data-dir /var/lib/etcd \
--listen-client-urls https://10.0.1.10:2379 \
--advertise-client-urls https://10.0.1.10:2379 \
--listen-peer-urls https://10.0.1.10:2380 \
--initial-advertise-peer-urls https://10.0.1.10:2380 \
--initial-cluster etcd-node1=https://10.0.1.10:2380,etcd-node2=https://10.0.1.11:2380,etcd-node3=https://10.0.1.12:2380 \
--initial-cluster-token production-cluster \
--initial-cluster-state new \
--client-cert-auth \
--trusted-ca-file /etc/etcd/ca.crt \
--cert-file /etc/etcd/server.crt \
--key-file /etc/etcd/server.key \
--peer-client-cert-auth \
--peer-trusted-ca-file /etc/etcd/ca.crt \
--peer-cert-file /etc/etcd/peer.crt \
--peer-key-file /etc/etcd/peer.key动态发现
通过 Discovery Service 获取节点列表,适合大规模集群。
bash
# 使用 Discovery Service
DISCOVERY_URL="https://discovery.etcd.io/new?size=3"
etcd \
--name node1 \
--data-dir /etcd-data \
--discovery $DISCOVERY_URL \
--listen-client-urls http://0.0.0.0:2379 \
--advertise-client-urls http://node1:2379 \
--listen-peer-urls http://0.0.0.0:2380 \
--initial-advertise-peer-urls http://node1:2380Kubernetes StatefulSet
在 Kubernetes 中部署 etcd 集群。
yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: etcd
spec:
serviceName: etcd
replicas: 3
selector:
matchLabels:
app: etcd
template:
metadata:
labels:
app: etcd
spec:
containers:
- name: etcd
image: quay.io/coreos/etcd:v3.5.17
ports:
- containerPort: 2379
name: client
- containerPort: 2380
name: peer
command:
- /bin/sh
- -c
- |
etcd --name etcd-$(HOSTNAME) \
--data-dir /var/lib/etcd \
--listen-client-urls http://0.0.0.0:2379 \
--advertise-client-urls http://etcd-$(HOSTNAME).etcd.default.svc.cluster.local:2379 \
--listen-peer-urls http://0.0.0.0:2380 \
--initial-advertise-peer-urls http://etcd-$(HOSTNAME).etcd.default.svc.cluster.local:2380 \
--initial-cluster etcd-0=http://etcd-0.etcd.default.svc.cluster.local:2380,etcd-1=http://etcd-1.etcd.default.svc.cluster.local:2380,etcd-2=http://etcd-2.etcd.default.svc.cluster.local:2380 \
--initial-cluster-token my-etcd-cluster \
--initial-cluster-state new
volumeMounts:
- name: etcd-data
mountPath: /var/lib/etcd
volumeClaimTemplates:
- metadata:
name: etcd-data
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 10Gi配置参数
关键配置项
| 参数 | 说明 | 默认值 |
|---|---|---|
--name | 节点名称 | default |
--data-dir | 数据存储目录 | default.etcd |
--listen-client-urls | 客户端监听地址 | http://127.0.0.1:2379 |
--advertise-client-urls | 客户端广播地址 | http://127.0.0.1:2379 |
--listen-peer-urls | 对等节点监听地址 | http://127.0.0.1:2380 |
--initial-advertise-peer-urls | 对等节点广播地址 | http://127.0.0.1:2380 |
--initial-cluster | 初始集群配置 | 根据名称自动生成 |
--initial-cluster-token | 集群标识 | new-cluster |
--initial-cluster-state | 集群初始状态 | new |
性能调优参数
bash
# 快照设置
--snapshot-count=10000 # 触发快照的日志条目数
--auto-compaction-retention=1h # 自动压缩保留时间
# 心跳和选举超时(单位:tick)
--heartbeat-interval=100 # 心跳间隔(毫秒)
--election-timeout=1000 # 选举超时(毫秒)
# quota 设置
--quota-backend-bytes=8GB # 数据存储上限配置文件
推荐使用配置文件管理:
yaml
# etcd.conf.yml
name: etcd-node1
data-dir: /var/lib/etcd
listen-client-urls: http://0.0.0.0:2379
advertise-client-urls: http://10.0.1.10:2379
listen-peer-urls: http://0.0.0.0:2380
initial-advertise-peer-urls: http://10.0.1.10:2380
initial-cluster:
etcd-node1: http://10.0.1.10:2380
etcd-node2: http://10.0.1.11:2380
etcd-node3: http://10.0.1.12:2380
initial-cluster-token: production-cluster
initial-cluster-state: new
snapshot-count: 10000
heartbeat-interval: 100
election-timeout: 1000成员管理
添加成员
bash
# 添加新成员(需要先通知集群)
etcdctl member add node4 \
--peer-urls=http://10.0.1.13:2380 \
--learner=true # 先作为 learner 加入
# 启动新节点
etcd \
--name node4 \
--data-dir /etcd-data \
--listen-client-urls http://0.0.0.0:2379 \
--advertise-client-urls http://10.0.1.13:2379 \
--listen-peer-urls http://0.0.0.0:2380 \
--initial-advertise-peer-urls http://10.0.1.13:2380 \
--initial-cluster-state existing
# 将 learner 提升为正式成员
etcdctl member promote <member-id>移除成员
bash
# 查看成员列表
etcdctl member list
# 移除成员
etcdctl member remove <member-id>
# 被移除的节点需要清空数据目录才能重新加入更新成员
bash
# 更新成员的 peer URLs
etcdctl member update <member-id> \
--peer-urls=http://new-address:2380查看成员状态
bash
# 成员列表
etcdctl member list -w table
# 成员详细状态
etcdctl endpoint status --cluster -w table
# 输出示例
+------------------------+------------------+---------+---------+-----------+------------+-----------+
| ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | RAFT INDEX | RAFT TERM |
+------------------------+------------------+---------+---------+-----------+------------+-----------+
| http://10.0.1.10:2379 | 4917a7ab173fabe7 | 3.5.17 | 25 kB | true | 12 | 2 |
| http://10.0.1.11:2379 | 592b7c8f7c5b4c3a | 3.5.17 | 25 kB | false | 12 | 2 |
| http://10.0.1.12:2379 | 6a3b8d9e0c1a2b4c | 3.5.17 | 25 kB | false | 12 | 2 |
+------------------------+------------------+---------+---------+-----------+------------+-----------+安全配置
TLS 加密
生成证书
bash
# 创建 CA
cfssl gencert -initca ca-csr.json | cfssljson -bare ca
# 创建服务器证书
cfssl gencert \
-ca=ca.pem \
-ca-key=ca-key.pem \
-config=ca-config.json \
-hostname="node1,node2,node3,localhost,127.0.0.1" \
server-csr.json | cfssljson -bare server
# 创建对等证书
cfssl gencert \
-ca=ca.pem \
-ca-key=ca-key.pem \
-config=ca-config.json \
-hostname="node1,node2,node3,localhost,127.0.0.1" \
peer-csr.json | cfssljson -bare peer
# 创建客户端证书
cfssl gencert \
-ca=ca.pem \
-ca-key=ca-key.pem \
-config=ca-config.json \
client-csr.json | cfssljson -bare client配置 TLS
bash
etcd \
--name node1 \
--client-cert-auth \
--trusted-ca-file /etc/etcd/ca.pem \
--cert-file /etc/etcd/server.pem \
--key-file /etc/etcd/server-key.pem \
--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.pem使用 TLS 连接
bash
# 使用客户端证书
etcdctl \
--endpoints=https://node1:2379 \
--cacert=/etc/etcd/ca.pem \
--cert=/etc/etcd/client.pem \
--key=/etc/etcd/client-key.pem \
put /foo barRBAC 认证
bash
# 启用认证
etcdctl auth enable
# 创建用户
etcdctl user add root
etcdctl user add app-user
# 创建角色
etcdctl role add app-role
# 授权角色访问键范围
etcdctl role grant-permission app-role read /app/
etcdctl role grant-permission app-role write /app/
# 为用户分配角色
etcdctl user grant-role app-user app-role
# 用户登录
etcdctl --user app-user:password get /app/config故障处理
集群健康检查
bash
# 检查集群健康
etcdctl endpoint health --cluster
# 输出
http://node1:2379 is healthy: successfully committed proposal: took = 1.2ms
http://node2:2379 is healthy: successfully committed proposal: took = 2.3ms
http://node3:2379 is healthy: successfully committed proposal: took = 1.8ms数据备份
bash
# 创建快照
etcdctl snapshot save backup.db
# 查看快照状态
etcdctl snapshot status backup.db -w table
# 输出
+----------+----------+------------+------------+
| HASH | REVISION | TOTAL KEYS | TOTAL SIZE |
+----------+----------+------------+------------+
| 2a56c3e8 | 1024 | 256 | 1.2 MB |
+----------+----------+------------+------------+数据恢复
bash
# 从快照恢复集群
# 1. 停止所有 etcd 节点
# 2. 在每个节点上恢复数据
etcdctl snapshot restore backup.db \
--name node1 \
--data-dir /var/lib/etcd-node1 \
--initial-cluster node1=http://node1:2380,node2=http://node2:2380,node3=http://node3:2380 \
--initial-cluster-token my-etcd-cluster
etcdctl snapshot restore backup.db \
--name node2 \
--data-dir /var/lib/etcd-node2 \
--initial-cluster node1=http://node1:2380,node2=http://node2:2380,node3=http://node3:2380 \
--initial-cluster-token my-etcd-cluster
etcdctl snapshot restore backup.db \
--name node3 \
--data-dir /var/lib/etcd-node3 \
--initial-cluster node1=http://node1:2380,node2=http://node2:2380,node3=http://node3:2380 \
--initial-cluster-token my-etcd-cluster
# 3. 启动所有节点(使用 --initial-cluster-state new)运维操作
bash
# 数据压缩(删除历史版本)
etcdctl compact 1000
# 碎片整理
etcdctl defrag --endpoints=http://node1:2379
# 检查数据完整性
etcdctl check perf
etcdctl check datascale监控指标
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
# Raft 指标
etcd_raft_commit_index
etcd_raft_applied_index
etcd_raft_proposal_failed_total
# 网络
etcd_network_peer_received_bytes_total
etcd_network_peer_sent_bytes_totalGrafana Dashboard
使用官方 Grafana Dashboard 监控 etcd:
运维最佳实践
集群规划
- 生产环境至少 3 个节点
- 跨机房部署时考虑网络延迟
- 节点数量保持奇数
硬件要求
- CPU: 2-4 核
- 内存: 8-16 GB
- 存储: SSD,至少 10GB(建议 50GB+)
- 网络: 低延迟(<10ms)
安全加固
- 启用 TLS 加密通信
- 启用 RBAC 认证
- 定期更新证书
备份策略
- 定期创建快照(每天或每周)
- 快照存储到远程存储
- 定期验证恢复流程
监控告警
- 监控 Leader 变更次数
- 监控数据库大小
- 监控请求延迟和吞吐量
总结
etcd 集群管理涉及:
- 集群搭建:静态配置、动态发现、Kubernetes 部署
- 成员管理:添加、删除、更新成员
- 安全配置:TLS 加密、RBAC 认证
- 故障处理:备份恢复、数据压缩
- 监控运维:健康检查、性能监控
掌握这些运维技能是保障 etcd 集群稳定运行的关键。在下一章中,我们将学习如何使用 Go 客户端连接和操作 etcd。