3. Etcd集群部署:在K8s中部署高可用Etcd集群(3节点),配置TLS

本章将指导你在Kubernetes环境中,通过Etcd Operator或StatefulSet + Headless Service方式,部署一个3节点的高可用Etcd集群,并启用双向TLS认证。这是后续压测沙盘与Istio访问日志采集的基础设施层。

3.1 架构概览

高可用Etcd集群在K8s中的典型部署模型如下:

K8s 高可用 Etcd 集群部署架构 Kubernetes 集群 etcd-0 Pod IP: 10.1.0.10 etcd: 2379/2380 zone-a etcd-1 Pod IP: 10.1.1.10 etcd: 2379/2380 zone-b etcd-2 Pod IP: 10.1.2.10 etcd: 2379/2380 zone-c Raft 共识:Leader 选举 & 日志复制 Headless Service: etcd-hs Client (Istio/App)

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,开始访问日志的采集与分析。