3. Etcd集群部署:在K8s中部署高可用Etcd集群(3节点),配置TLS
本章将指导你在Kubernetes环境中,通过Etcd Operator或StatefulSet + Headless Service方式,部署一个3节点的高可用Etcd集群,并启用双向TLS认证。这是后续压测沙盘与Istio访问日志采集的基础设施层。
3.1 架构概览
高可用Etcd集群在K8s中的典型部署模型如下:
3.2 前置条件
- Kubernetes 集群版本 ≥ 1.22,已配置 StorageClass 支持动态PV。
- 已安装 cert-manager(推荐)或具备手动签发TLS证书的能力。
- 节点间网络互通,Pod CIDR 无冲突。
3.3 生成TLS证书
Etcd 双向TLS需要三组证书:CA证书、服务端证书(含SAN)、客户端证书。以下使用 cfssl 工具链生成。
关键配置:服务端证书的 SAN 必须包含每个 etcd Pod 的 DNS 名称和 ClusterIP,否则 TLS 握手会失败。
3.3.1 创建 CA 配置
cat <<EOF > ca-config.json
{
"signing": {
"default": { "expiry": "87600h", "usages": ["signing","key encipherment","server auth","client auth"] },
"profiles": { "etcd": { "expiry": "87600h", "usages": ["signing","key encipherment","server auth","client auth"] } }
}
}
EOF
cat <<EOF > ca-csr.json
{
"CN": "etcd-ca",
"key": { "algo": "rsa", "size": 2048 },
"names": [ { "O": "etcd", "OU": "SRE", "L": "Beijing", "ST": "Beijing", "C": "CN" } ]
}
EOF
cfssl gencert -initca ca-csr.json | cfssljson -bare ca
3.3.2 生成服务端证书(含SAN)
cat <<EOF > etcd-server-csr.json
{
"CN": "etcd-server",
"key": { "algo": "rsa", "size": 2048 },
"hosts": [
"127.0.0.1",
"localhost",
"etcd-hs.etcd-cluster.svc.cluster.local",
"etcd-0.etcd-hs.etcd-cluster.svc.cluster.local",
"etcd-1.etcd-hs.etcd-cluster.svc.cluster.local",
"etcd-2.etcd-hs.etcd-cluster.svc.cluster.local",
"10.1.0.10", "10.1.1.10", "10.1.2.10"
],
"names": [ { "O": "etcd", "OU": "SRE" } ]
}
EOF
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=etcd etcd-server-csr.json | cfssljson -bare etcd-server
3.3.3 生成客户端证书
cat <<EOF > etcd-client-csr.json
{
"CN": "etcd-client",
"key": { "algo": "rsa", "size": 2048 },
"hosts": [],
"names": [ { "O": "etcd", "OU": "SRE" } ]
}
EOF
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=etcd etcd-client-csr.json | cfssljson -bare etcd-client
3.4 创建K8s Secret存储证书
kubectl create ns etcd-cluster
kubectl -n etcd-cluster create secret tls etcd-server-tls \
--cert=etcd-server.pem --key=etcd-server-key.pem
kubectl -n etcd-cluster create secret tls etcd-client-tls \
--cert=etcd-client.pem --key=etcd-client-key.pem
kubectl -n etcd-cluster create secret generic etcd-ca \
--from-file=ca.pem
3.5 部署Etcd集群(StatefulSet + Headless Service)
使用 StatefulSet 保证每个 Pod 有稳定的网络标识,配合 Headless Service 实现 DNS 解析。
3.5.1 Headless Service
apiVersion: v1
kind: Service
metadata:
name: etcd-hs
namespace: etcd-cluster
labels: { app: etcd }
spec:
clusterIP: None
ports:
- name: client
port: 2379
targetPort: 2379
- name: peer
port: 2380
targetPort: 2380
selector: { app: etcd }
3.5.2 StatefulSet 定义(核心片段)
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: etcd
namespace: etcd-cluster
spec:
serviceName: etcd-hs
replicas: 3
selector:
matchLabels: { app: etcd }
template:
metadata:
labels: { app: etcd }
spec:
containers:
- name: etcd
image: quay.io/coreos/etcd:v3.5.12
ports:
- containerPort: 2379
name: client
- containerPort: 2380
name: peer
volumeMounts:
- name: data
mountPath: /var/run/etcd
- name: tls
mountPath: /etc/etcd/tls
readOnly: true
env:
- name: ETCD_NAME
valueFrom:
fieldRef: { fieldPath: metadata.name }
- name: ETCD_INITIAL_CLUSTER
value: "etcd-0=https://etcd-0.etcd-hs.etcd-cluster.svc:2380,etcd-1=https://etcd-1.etcd-hs.etcd-cluster.svc:2380,etcd-2=https://etcd-2.etcd-hs.etcd-cluster.svc:2380"
- name: ETCD_INITIAL_CLUSTER_STATE
value: "new"
- name: ETCD_INITIAL_CLUSTER_
value: "etcd-cluster-"
- name: ETCD_LISTEN_PEER_URLS
value: "https://0.0.0.0:2380"
- name: ETCD_LISTEN_CLIENT_URLS
value: "https://0.0.0.0:2379"
- name: ETCD_ADVERTISE_CLIENT_URLS
value: "https://$(ETCD_NAME).etcd-hs.etcd-cluster.svc:2379"
- name: ETCD_TRUSTED_CA_FILE
value: "/etc/etcd/tls/ca.pem"
- name: ETCD_CERT_FILE
value: "/etc/etcd/tls/tls.crt"
- name: ETCD_KEY_FILE
value: "/etc/etcd/tls/tls.key"
- name: ETCD_PEER_TRUSTED_CA_FILE
value: "/etc/etcd/tls/ca.pem"
- name: ETCD_PEER_CERT_FILE
value: "/etc/etcd/tls/tls.crt"
- name: ETCD_PEER_KEY_FILE
value: "/etc/etcd/tls/tls.key"
volumes:
- name: tls
secret:
secretName: etcd-server-tls
items:
- key: tls.crt
path: tls.crt
- key: tls.key
path: tls.key
- name: ca
secret:
secretName: etcd-ca
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 10Gi
storageClassName: standard
关键参数说明:
ETCD_INITIAL_CLUSTER使用 Headless Service DNS 名称,确保 Pod 重启后 IP 变化不影响集群发现。ETCD_ADVERTISE_CLIENT_URLS使用$(ETCD_NAME).etcd-hs...格式,保证客户端通过稳定域名访问。- 所有 etcd 端口均启用 HTTPS,CA/服务端证书通过 Secret 挂载。
3.6 验证集群状态
部署完成后,通过客户端证书验证集群健康状态:
# 进入一个 etcd Pod
kubectl -n etcd-cluster exec -it etcd-0 -- sh
# 使用 etcdctl 检查成员列表
etcdctl --endpoints=https://127.0.0.1:2379 \
--cacert=/etc/etcd/tls/ca.pem \
--cert=/etc/etcd/tls/tls.crt \
--key=/etc/etcd/tls/tls.key \
member list
# 预期输出 3 个成员,状态均为 started
# 检查集群健康
etcdctl --endpoints=https://127.0.0.1:2379 \
--cacert=/etc/etcd/tls/ca.pem \
--cert=/etc/etcd/tls/tls.crt \
--key=/etc/etcd/tls/tls.key \
endpoint health --cluster
3.7 关键参数对比表
| 参数 | 作用 | 生产建议值 |
|---|---|---|
--quota-backend-bytes |
etcd 存储配额 | 8GB(默认 2GB) |
--auto-compaction-mode |
自动压缩模式 | revision |
--auto-compaction-retention |
保留的历史版本数 | 1000 |
--max-request-bytes |
单个请求最大字节数 | 1572864 (1.5MB) |
--snapshot-count |
触发快照的事务数 | 100000 |
3.8 常见问题与避坑
⚠️ 部署避坑清单:
- 证书 SAN 遗漏: 服务端证书必须包含所有 etcd Pod 的 DNS 名称和 ClusterIP,否则 TLS 握手报错
x509: certificate is valid for ... not ...。 - 存储类未配置: 如果集群没有默认 StorageClass,StatefulSet 的 PVC 会 Pending,导致 Pod 无法启动。
- 初始集群状态错误: 首次部署使用
new,集群已存在后重建必须改为existing,否则会报成员冲突。 - Pod 间网络不通: 检查 NetworkPolicy 或 Calico 规则是否阻止 2380 端口通信。
3.9 小结
至此,一个3节点、启用双向TLS的高可用Etcd集群已在K8s中成功部署。该集群将作为后续压测沙盘的数据存储后端,并为Istio服务网格提供可靠的配置与状态存储。下一阶段我们将在此集群上部署压测工具与Istio Sidecar,开始访问日志的采集与分析。