在 Kubernetes 中部署 有状态且不依赖固定 IP 的 etcd 集群,需解决两个核心矛盾:
- etcd 强依赖稳定的成员通信地址(集群初始化需指定
initial-cluster
列表); - K8s Pod IP 动态变化(重启或迁移后 IP 变更)。
以下是经过生产验证的解决方案,平衡可用性与自动化:
一、架构设计核心思路
方案对比
方案 | 原理 | 优点 | 缺点 |
---|---|---|---|
StatefulSet + Headless Service | 通过 FQDN 稳定解析 Pod | IP 变化无感知 | 依赖 K8s DNS 稳定性 |
Operator 自动发现 | 使用 etcd Operator 管理集群 | 自动扩缩/故障恢复 | 复杂度高 |
动态 DNS 注册 | Pod 启动时注册自定义域名 | 灵活跨集群 | 需维护外部 DNS 系统 |
推荐组合:StatefulSet + Headless Service + 启动脚本自动化(平衡简单性与可靠性)
二、具体部署步骤(StatefulSet 方案)
1. 关键资源配置
# Headless Service 提供稳定 DNS 记录
apiVersion: v1
kind: Service
metadata:
name: etcd
spec:
clusterIP: None # Headless 模式
ports:
- port: 2379
name: client
- port: 2380
name: peer
selector:
app: etcd
---
# StatefulSet 保证有序性和持久存储
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: etcd
spec:
serviceName: "etcd" # 关联 Headless Service
replicas: 3
podManagementPolicy: Parallel # 允许并行启动加速
selector:
matchLabels:
app: etcd
template:
metadata:
labels:
app: etcd
spec:
terminationGracePeriodSeconds: 10
containers:
- name: etcd
image: quay.io/coreos/etcd:v3.5.6
command: ["/bin/sh", "-c"]
args:
- >
# 动态生成 initial-cluster 参数
IPS=$(hostname -i);
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 $(hostname) \
--listen-peer-urls http://0.0.0.0:2380 \
--listen-client-urls http://0.0.0.0:2379 \
--advertise-client-urls http://$(hostname).etcd:2379 \
--initial-advertise-peer-urls http://$(hostname).etcd:2380 \
--initial-cluster $PEERS \
--initial-cluster-state new \
--data-dir /var/lib/etcd
ports:
- containerPort: 2379
- containerPort: 2380
volumeMounts:
- name: etcd-data
mountPath: /var/lib/etcd
volumeClaimTemplates: # 持久化存储
- metadata:
name: etcd-data
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "ssd" # 必须使用 SSD
resources:
requests:
storage: 10Gi
2. 方案核心要点
- DNS 稳定性:
Pod 通过 FQDN<pod-name>.<svc>.<namespace>.svc.cluster.local
通信(如etcd-0.etcd.default.svc.cluster.local
),IP 变化无影响。 - 动态参数生成:
启动脚本自动拼接--initial-cluster
参数,避免硬编码。 - 存储持久化:
volumeClaimTemplates
确保 Pod 重建后数据不丢失。
三、生产环境增强设计
1. 高可用优化
# 反亲和性避免单点故障
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: "app"
operator: In
values: ["etcd"]
topologyKey: "kubernetes.io/hostname"
2. 安全加固
- TLS 加密通信:
使用 cert-manager 自动签发证书,配置--cert-file
、--key-file
等参数。 - RBAC 限制访问:
创建专属 ServiceAccount 并限制权限。
3. 监控与自愈
- 健康检查:
livenessProbe: exec: command: ["etcdctl", "endpoint", "health"] initialDelaySeconds: 10 periodSeconds: 30
- 告警规则:
监控 etcd 实例数、写入延迟、存储空间(如 Prometheus + Grafana)。
四、替代方案:etcd Operator(适用于复杂场景)
操作流程
- 部署 etcd Operator:
kubectl create -f https://raw.githubusercontent.com/coreos/etcd-operator/master/example/deployment.yaml
- 声明 etcd 集群:
apiVersion: etcd.database.coreos.com/v1beta2 kind: EtcdCluster metadata: name: etcd-cluster spec: size: 3 version: "3.5.6" storage: volumeClaimTemplate: spec: storageClassName: ssd resources: requests: storage: 10Gi
Operator 优势
- 自动故障恢复:节点宕机后自动重建并加入集群;
- 无缝扩缩容:调整
spec.size
即可扩容; - 备份管理:集成 S3 自动备份。
五、关键避坑指南
问题 | 解决方案 |
---|---|
首次启动死锁 | 确保 initial-cluster-state=new 仅第一次启动使用,后续改为 existing |
跨节点通信失败 | 检查网络插件(Calico/Cilium)是否允许 Pod 间流量,禁用防火墙规则 |
存储性能瓶颈 | 必须使用 SSD,禁用交换分区,设置 --auto-compaction-retention=1h 定期压缩 |
集群脑裂 | 配置 quorum 策略(N/2+1 存活),奇数节点部署(如 3/5) |
六、验证集群状态
# 查看 etcd 成员列表
kubectl exec etcd-0 -- etcdctl member list --endpoints=http://localhost:2379
# 检查集群健康状态
kubectl exec etcd-0 -- etcdctl endpoint health --cluster
总结:
通过 StatefulSet + Headless Service + 启动脚本自动化,可在非固定 IP 环境下稳定运行 etcd 集群。对于需要自动化运维的场景,etcd Operator 是更优解。无论何种方案,务必确保:
- 存储持久化且高性能(SSD);
- 网络策略允许 2379/2380 端口通信;
- 监控覆盖核心指标(节点数、延迟、存储)。