3. etcd 集群部署:单节点、静态集群、动态发现与 TLS 安全配置

etcd 作为分布式键值存储系统,其部署方式直接影响系统的可用性、扩展性和安全性。本章将系统讲解四种核心部署模式:单节点部署用于开发测试、静态集群部署用于生产环境、动态发现部署用于自动化场景,以及 TLS 安全配置用于生产加固。掌握这些部署方式,是后续进行压测脚本开发的基础。

3.1 单节点部署

单节点部署是 etcd 最简单的运行模式,适用于本地开发、功能验证和压测脚本调试。它不提供高可用能力,但启动速度快、配置简单。

适用场景: 本地开发环境、CI/CD 流水线中的集成测试、压测脚本的快速验证。

3.1.1 启动命令

# 下载 etcd 二进制后,直接启动单节点
etcd --name=etcd-single \
     --data-dir=/tmp/etcd-data \
     --listen-client-urls=http://0.0.0.0:2379 \
     --advertise-client-urls=http://127.0.0.1:2379 \
     --listen-peer-urls=http://0.0.0.0:2380 \
     --initial-advertise-peer-urls=http://127.0.0.1:2380 \
     --initial-cluster=etcd-single=http://127.0.0.1:2380 \
     --initial-cluster-=etcd-cluster-1 \
     --initial-cluster-state=new

3.1.2 关键参数说明

参数 说明 默认值
--name 节点名称,集群内唯一 default
--data-dir 数据存储目录 ${name}.etcd
--listen-client-urls 客户端监听地址 http://localhost:2379
--advertise-client-urls 对外公布的客户端地址 http://localhost:2379
--initial-cluster 初始集群成员列表 —
验证部署: 启动后使用 etcdctl endpoint health --endpoints=http://127.0.0.1:2379 检查节点健康状态,返回 healthy 即表示部署成功。

3.2 静态集群部署

静态集群部署是生产环境中最常用的方式,管理员在启动前预先确定所有节点的 IP 地址和端口,通过 --initial-cluster 参数一次性声明集群拓扑。这种方式配置明确、启动稳定,适合节点数量固定且网络环境可控的场景。

3.2.1 三节点集群配置示例

假设三台机器的 IP 分别为 192.168.1.10、192.168.1.11、192.168.1.12,每台机器上执行对应的启动命令:

# 节点 1 (192.168.1.10)
etcd --name=node1 \
     --data-dir=/var/lib/etcd \
     --listen-client-urls=http://0.0.0.0:2379 \
     --advertise-client-urls=http://192.168.1.10:2379 \
     --listen-peer-urls=http://0.0.0.0:2380 \
     --initial-advertise-peer-urls=http://192.168.1.10:2380 \
     --initial-cluster=node1=http://192.168.1.10:2380,node2=http://192.168.1.11:2380,node3=http://192.168.1.12:2380 \
     --initial-cluster-=etcd-cluster-prod \
     --initial-cluster-state=new

# 节点 2 (192.168.1.11) — 仅修改 name 和 IP 地址
etcd --name=node2 \
     --data-dir=/var/lib/etcd \
     --listen-client-urls=http://0.0.0.0:2379 \
     --advertise-client-urls=http://192.168.1.11:2379 \
     --listen-peer-urls=http://0.0.0.0:2380 \
     --initial-advertise-peer-urls=http://192.168.1.11:2380 \
     --initial-cluster=node1=http://192.168.1.10:2380,node2=http://192.168.1.11:2380,node3=http://192.168.1.12:2380 \
     --initial-cluster-=etcd-cluster-prod \
     --initial-cluster-state=new

# 节点 3 (192.168.1.12) — 仅修改 name 和 IP 地址
etcd --name=node3 \
     --data-dir=/var/lib/etcd \
     --listen-client-urls=http://0.0.0.0:2379 \
     --advertise-client-urls=http://192.168.1.12:2379 \
     --listen-peer-urls=http://0.0.0.0:2380 \
     --initial-advertise-peer-urls=http://192.168.1.12:2380 \
     --initial-cluster=node1=http://192.168.1.10:2380,node2=http://192.168.1.11:2380,node3=http://192.168.1.12:2380 \
     --initial-cluster-=etcd-cluster-prod \
     --initial-cluster-state=new

3.2.2 集群状态验证

# 任意节点上执行成员列表查询
etcdctl member list --endpoints=http://192.168.1.10:2379

# 输出示例
# 8211f1d0f64f3269, started, node1, http://192.168.1.10:2380, http://192.168.1.10:2379, false
# 91bc3c398fb3c146, started, node2, http://192.168.1.11:2380, http://192.168.1.11:2379, false
# fd422379fdaa503d, started, node3, http://192.168.1.12:2380, http://192.168.1.12:2379, false
注意事项: 静态集群部署要求所有节点在启动前网络互通,且 --initial-cluster-state 必须为 new。如果集群已存在,需要改为 existing,否则会导致数据冲突。

3.3 动态发现部署

动态发现部署通过一个发现服务(Discovery Service)自动注册集群成员,适合节点 IP 不固定或需要自动扩缩容的场景。etcd 官方提供了公共发现服务 https://discovery.etcd.io,也支持自建发现服务。

3.3.1 获取发现

# 使用公共发现服务生成一个 3 节点集群的 
curl https://discovery.etcd.io/new?size=3

# 返回类似:https://discovery.etcd.io/3e86b59922e3e5f8e3e5f8e3e5f8e3e5

3.3.2 使用发现 启动节点

# 所有节点使用相同的 discovery  启动
etcd --name=node1 \
     --data-dir=/var/lib/etcd \
     --listen-client-urls=http://0.0.0.0:2379 \
     --advertise-client-urls=http://192.168.1.10:2379 \
     --listen-peer-urls=http://0.0.0.0:2380 \
     --initial-advertise-peer-urls=http://192.168.1.10:2380 \
     --discovery=https://discovery.etcd.io/3e86b59922e3e5f8e3e5f8e3e5f8e3e5 \
     --initial-cluster-state=new

3.3.3 动态发现 vs 静态集群

对比维度 静态集群部署 动态发现部署
配置复杂度 低,所有信息在启动前已知 中,需要额外获取发现
IP 变更适应性 差,IP 变化需重新配置 好,节点自动注册
扩缩容支持 需手动更新集群配置 自动感知新节点加入
生产推荐度 高,适合固定基础设施 中,适合容器化/云原生环境
依赖外部服务 无 需要发现服务可用

3.4 TLS 安全配置

生产环境中的 etcd 集群必须启用 TLS 加密,防止中间人攻击和数据泄露。TLS 配置分为三个层级:客户端与服务端之间的加密(Client-to-Server)、节点之间的加密(Peer-to-Peer)、以及双向认证(mTLS)。

3.4.1 证书生成

使用 cfssl 工具生成 CA 证书、服务端证书和客户端证书:

# 1. 生成 CA 证书
cfssl gencert -initca ca-csr.json | cfssljson -bare ca

# 2. 生成服务端证书(包含所有节点 IP 和域名)
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json \
  -hostname="192.168.1.10,192.168.1.11,192.168.1.12,localhost,127.0.0.1" \
  -profile=server server-csr.json | cfssljson -bare server

# 3. 生成客户端证书
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json \
  -profile=client client-csr.json | cfssljson -bare client

3.4.2 启用 TLS 的启动命令

etcd --name=node1 \
     --data-dir=/var/lib/etcd \
     --listen-client-urls=https://0.0.0.0:2379 \
     --advertise-client-urls=https://192.168.1.10:2379 \
     --listen-peer-urls=https://0.0.0.0:2380 \
     --initial-advertise-peer-urls=https://192.168.1.10:2380 \
     --initial-cluster=node1=https://192.168.1.10:2380,node2=https://192.168.1.11:2380,node3=https://192.168.1.12:2380 \
     --initial-cluster-=etcd-cluster-tls \
     --initial-cluster-state=new \
     --cert-file=/etc/etcd/ssl/server.pem \
     --key-file=/etc/etcd/ssl/server-key.pem \
     --peer-cert-file=/etc/etcd/ssl/peer.pem \
     --peer-key-file=/etc/etcd/ssl/peer-key.pem \
     --trusted-ca-file=/etc/etcd/ssl/ca.pem \
     --peer-trusted-ca-file=/etc/etcd/ssl/ca.pem \
     --client-cert-auth=true \
     --peer-client-cert-auth=true

3.4.3 使用 TLS 连接集群

# 使用 etcdctl 通过 TLS 访问
etcdctl --endpoints=https://192.168.1.10:2379 \
        --cacert=/etc/etcd/ssl/ca.pem \
        --cert=/etc/etcd/ssl/client.pem \
        --key=/etc/etcd/ssl/client-key.pem \
        endpoint health
安全建议: 生产环境务必启用 --client-cert-auth=true 和 --peer-client-cert-auth=true,实现双向 TLS 认证。证书有效期建议不超过 1 年,并建立证书轮换机制。

3.5 部署模式对比与选择

部署模式 高可用 配置复杂度 推荐场景
单节点 否 低 开发测试、压测脚本调试
静态集群 是 中 生产环境、固定基础设施
动态发现 是 中高 容器化、云原生、自动扩缩容
TLS 安全集群 是 高 所有生产环境(必须)

3.6 部署架构总览

下图展示了三种部署模式的架构差异,以及 TLS 安全层在集群中的位置:

etcd 部署模式架构对比 单节点部署 etcd 单节点 :2379 (客户端) 无高可用 静态集群部署 Node1 Node2 Node3 Raft 共识 + 高可用 预配置 IP 列表 动态发现部署 Node1 Node2 Node3 发现服务 自动注册 TLS 安全层(所有生产集群必须启用) 客户端加密 --cert-file / --key-file 节点间加密 --peer-cert-file 双向认证 --client-cert-auth=true CA 信任链 --trusted-ca-file 压测脚本连接时,需根据部署模式配置 endpoints 和 TLS 证书 单节点:1 个 endpoint;集群:多个 endpoint 实现故障转移

3.7 压测脚本部署适配要点

在编写压测脚本时,需要根据集群部署方式调整客户端连接参数:

  • 单节点: 直接连接 http://127.0.0.1:2379,无需额外配置。
  • 静态集群: 在客户端配置多个 endpoint 列表,实现自动故障转移。
  • 动态发现: 先通过发现服务获取当前集群成员列表,再建立连接。
  • TLS 集群: 客户端必须加载 CA 证书、客户端证书和私钥,使用 HTTPS 协议。
压测脚本示例(Go 语言):
// 连接 TLS 集群的 etcd 客户端
import (
    "go.etcd.io/etcd/client/v3"
    "crypto/tls"
    "crypto/x509"
    "os"
)

func newTLSClient() (*clientv3.Client, error) {
    caCert, _ := os.ReadFile("/etc/etcd/ssl/ca.pem")
    caPool := x509.NewCertPool()
    caPool.AppendCertsFromPEM(caCert)

    cert, _ := tls.LoadX509KeyPair(
        "/etc/etcd/ssl/client.pem",
        "/etc/etcd/ssl/client-key.pem",
    )

    cfg := clientv3.Config{
        Endpoints: []string{
            "https://192.168.1.10:2379",
            "https://192.168.1.11:2379",
            "https://192.168.1.12:2379",
        },
        TLS: &tls.Config{
            RootCAs:      caPool,
            Certificates: []tls.Certificate{cert},
        },
    }
    return clientv3.New(cfg)
}
部署避坑指南:
  • 集群节点数量建议为奇数(3、5、7),避免脑裂时无法达成共识。
  • 生产环境禁止使用 --initial-cluster-state=new 重启已有集群,应改为 existing。
  • TLS 证书中的 SAN(Subject Alternative Name)必须包含所有节点的 IP 和域名。
  • 动态发现模式下,发现服务本身需要高可用,否则会成为单点故障。