集群指南

启动 etcd 集群:静态方式、etcd 发现和 DNS 发现

概述

静态启动 etcd 集群需要每个成员都了解集群中的其他成员。在某些情况下,集群成员的 IP 地址可能事先未知。在这种情况下,可以借助发现服务来引导 etcd 集群。

一旦 etcd 集群启动并运行,添加或移除成员可以通过运行时重新配置来完成。为了更好地理解运行时重新配置的设计,我们建议阅读运行时配置设计文档

本指南将涵盖以下用于引导 etcd 集群的机制:

每种引导机制都将用于创建一个包含三台机器的 etcd 集群,具体细节如下:

名称地址主机名
infra010.0.1.10infra0.example.com
infra110.0.1.11infra1.example.com
infra210.0.1.12infra2.example.com

静态

由于我们在启动前已经知道集群成员、它们的地址和集群的大小,因此可以通过设置initial-cluster标志来进行离线引导配置。每台机器将获得以下环境变量或命令行参数:

ETCD_INITIAL_CLUSTER="infra0=http://10.0.1.10:2380,infra1=http://10.0.1.11:2380,infra2=http://10.0.1.12:2380"
ETCD_INITIAL_CLUSTER_STATE=new
--initial-cluster infra0=http://10.0.1.10:2380,infra1=http://10.0.1.11:2380,infra2=http://10.0.1.12:2380 \
--initial-cluster-state new

请注意,在initial-cluster中指定的 URL 是公布的对等 URL,即它们应与相应节点上的initial-advertise-peer-urls值匹配。

如果出于测试目的使用相同的配置启动多个集群(或创建和销毁单个集群),强烈建议为每个集群提供唯一的initial-cluster-token。通过这样做,即使这些集群具有完全相同的配置,etcd 也可以为它们生成唯一的集群 ID 和成员 ID。这可以防止跨集群交互,从而避免集群被破坏。

etcd 监听listen-client-urls以接受客户端流量。etcd 成员会向其他成员、代理和客户端公布在advertise-client-urls中指定的 URL。请确保advertise-client-urls可以从预期的客户端访问。常见的错误是将advertise-client-urls设置为 localhost 或保持默认值,而远程客户端应该能够访问 etcd。

在每台机器上,使用这些标志启动 etcd:

$ etcd --name infra0 --initial-advertise-peer-urls http://10.0.1.10:2380 \
  --listen-peer-urls http://10.0.1.10:2380 \
  --listen-client-urls http://10.0.1.10:2379,http://127.0.0.1:2379 \
  --advertise-client-urls http://10.0.1.10:2379 \
  --initial-cluster-token etcd-cluster-1 \
  --initial-cluster infra0=http://10.0.1.10:2380,infra1=http://10.0.1.11:2380,infra2=http://10.0.1.12:2380 \
  --initial-cluster-state new
$ etcd --name infra1 --initial-advertise-peer-urls http://10.0.1.11:2380 \
  --listen-peer-urls http://10.0.1.11:2380 \
  --listen-client-urls http://10.0.1.11:2379,http://127.0.0.1:2379 \
  --advertise-client-urls http://10.0.1.11:2379 \
  --initial-cluster-token etcd-cluster-1 \
  --initial-cluster infra0=http://10.0.1.10:2380,infra1=http://10.0.1.11:2380,infra2=http://10.0.1.12:2380 \
  --initial-cluster-state new
$ etcd --name infra2 --initial-advertise-peer-urls http://10.0.1.12:2380 \
  --listen-peer-urls http://10.0.1.12:2380 \
  --listen-client-urls http://10.0.1.12:2379,http://127.0.0.1:2379 \
  --advertise-client-urls http://10.0.1.12:2379 \
  --initial-cluster-token etcd-cluster-1 \
  --initial-cluster infra0=http://10.0.1.10:2380,infra1=http://10.0.1.11:2380,infra2=http://10.0.1.12:2380 \
  --initial-cluster-state new

--initial-cluster开头的命令行参数将在后续运行 etcd 时被忽略。初始引导过程完成后,可以自由删除环境变量或命令行标志。如果以后需要更改配置(例如,向集群添加或从集群中移除成员),请参阅运行时配置指南。

TLS

etcd 支持通过 TLS 协议进行加密通信。TLS 通道可用于对等节点之间的内部集群通信以及客户端流量的加密。本节提供了设置具有对等和客户端 TLS 的集群的示例。有关 etcd 的 TLS 支持的详细信息,请参阅安全指南

自签名证书

使用自签名证书的集群既加密了流量,又对其连接进行了身份验证。要使用自签名证书启动集群,每个集群成员应具有由共享集群 CA 证书 (ca.crt) 签名的独特密钥对 (member.crt, member.key),用于对等连接和客户端连接。可以按照 etcd 的TLS 设置示例生成证书。

在每台机器上,etcd 将使用这些标志启动:

$ etcd --name infra0 --initial-advertise-peer-urls https://10.0.1.10:2380 \
  --listen-peer-urls https://10.0.1.10:2380 \
  --listen-client-urls https://10.0.1.10:2379,https://127.0.0.1:2379 \
  --advertise-client-urls https://10.0.1.10:2379 \
  --initial-cluster-token etcd-cluster-1 \
  --initial-cluster infra0=https://10.0.1.10:2380,infra1=https://10.0.1.11:2380,infra2=https://10.0.1.12:2380 \
  --initial-cluster-state new \
  --client-cert-auth --trusted-ca-file=/path/to/ca-client.crt \
  --cert-file=/path/to/infra0-client.crt --key-file=/path/to/infra0-client.key \
  --peer-client-cert-auth --peer-trusted-ca-file=ca-peer.crt \
  --peer-cert-file=/path/to/infra0-peer.crt --peer-key-file=/path/to/infra0-peer.key
$ etcd --name infra1 --initial-advertise-peer-urls https://10.0.1.11:2380 \
  --listen-peer-urls https://10.0.1.11:2380 \
  --listen-client-urls https://10.0.1.11:2379,https://127.0.0.1:2379 \
  --advertise-client-urls https://10.0.1.11:2379 \
  --initial-cluster-token etcd-cluster-1 \
  --initial-cluster infra0=https://10.0.1.10:2380,infra1=https://10.0.1.11:2380,infra2=https://10.0.1.12:2380 \
  --initial-cluster-state new \
  --client-cert-auth --trusted-ca-file=/path/to/ca-client.crt \
  --cert-file=/path/to/infra1-client.crt --key-file=/path/to/infra1-client.key \
  --peer-client-cert-auth --peer-trusted-ca-file=ca-peer.crt \
  --peer-cert-file=/path/to/infra1-peer.crt --peer-key-file=/path/to/infra1-peer.key
$ etcd --name infra2 --initial-advertise-peer-urls https://10.0.1.12:2380 \
  --listen-peer-urls https://10.0.1.12:2380 \
  --listen-client-urls https://10.0.1.12:2379,https://127.0.0.1:2379 \
  --advertise-client-urls https://10.0.1.12:2379 \
  --initial-cluster-token etcd-cluster-1 \
  --initial-cluster infra0=https://10.0.1.10:2380,infra1=https://10.0.1.11:2380,infra2=https://10.0.1.12:2380 \
  --initial-cluster-state new \
  --client-cert-auth --trusted-ca-file=/path/to/ca-client.crt \
  --cert-file=/path/to/infra2-client.crt --key-file=/path/to/infra2-client.key \
  --peer-client-cert-auth --peer-trusted-ca-file=ca-peer.crt \
  --peer-cert-file=/path/to/infra2-peer.crt --peer-key-file=/path/to/infra2-peer.key

自动证书

如果集群需要加密通信但不需要经过身份验证的连接,则可以配置 etcd 自动生成其密钥。在初始化时,每个成员会根据其公布的 IP 地址和主机创建自己的一组密钥。

在每台机器上,etcd 将使用这些标志启动:

$ etcd --name infra0 --initial-advertise-peer-urls https://10.0.1.10:2380 \
  --listen-peer-urls https://10.0.1.10:2380 \
  --listen-client-urls https://10.0.1.10:2379,https://127.0.0.1:2379 \
  --advertise-client-urls https://10.0.1.10:2379 \
  --initial-cluster-token etcd-cluster-1 \
  --initial-cluster infra0=https://10.0.1.10:2380,infra1=https://10.0.1.11:2380,infra2=https://10.0.1.12:2380 \
  --initial-cluster-state new \
  --auto-tls \
  --peer-auto-tls
$ etcd --name infra1 --initial-advertise-peer-urls https://10.0.1.11:2380 \
  --listen-peer-urls https://10.0.1.11:2380 \
  --listen-client-urls https://10.0.1.11:2379,https://127.0.0.1:2379 \
  --advertise-client-urls https://10.0.1.11:2379 \
  --initial-cluster-token etcd-cluster-1 \
  --initial-cluster infra0=https://10.0.1.10:2380,infra1=https://10.0.1.11:2380,infra2=https://10.0.1.12:2380 \
  --initial-cluster-state new \
  --auto-tls \
  --peer-auto-tls
$ etcd --name infra2 --initial-advertise-peer-urls https://10.0.1.12:2380 \
  --listen-peer-urls https://10.0.1.12:2380 \
  --listen-client-urls https://10.0.1.12:2379,https://127.0.0.1:2379 \
  --advertise-client-urls https://10.0.1.12:2379 \
  --initial-cluster-token etcd-cluster-1 \
  --initial-cluster infra0=https://10.0.1.10:2380,infra1=https://10.0.1.11:2380,infra2=https://10.0.1.12:2380 \
  --initial-cluster-state new \
  --auto-tls \
  --peer-auto-tls

错误情况

在以下示例中,我们没有将新主机包含在枚举节点列表中。如果这是一个新集群,则必须将该节点添加到初始集群成员列表中。

$ etcd --name infra1 --initial-advertise-peer-urls http://10.0.1.11:2380 \
  --listen-peer-urls https://10.0.1.11:2380 \
  --listen-client-urls http://10.0.1.11:2379,http://127.0.0.1:2379 \
  --advertise-client-urls http://10.0.1.11:2379 \
  --initial-cluster infra0=http://10.0.1.10:2380 \
  --initial-cluster-state new
etcd: infra1 not listed in the initial cluster config
exit 1

在此示例中,我们试图将一个节点 (infra0) 映射到与其在集群列表中的枚举地址 (10.0.1.10:2380) 不同的地址 (127.0.0.1:2380)。如果此节点要监听多个地址,则所有地址都必须反映在“initial-cluster”配置指令中。

$ etcd --name infra0 --initial-advertise-peer-urls http://127.0.0.1:2380 \
  --listen-peer-urls http://10.0.1.10:2380 \
  --listen-client-urls http://10.0.1.10:2379,http://127.0.0.1:2379 \
  --advertise-client-urls http://10.0.1.10:2379 \
  --initial-cluster infra0=http://10.0.1.10:2380,infra1=http://10.0.1.11:2380,infra2=http://10.0.1.12:2380 \
  --initial-cluster-state=new
etcd: error setting up initial cluster: infra0 has different advertised URLs in the cluster and advertised peer URLs list
exit 1

如果某个对等节点使用不同的配置参数集并尝试加入此集群,etcd 将报告集群 ID 不匹配并退出。

$ etcd --name infra3 --initial-advertise-peer-urls http://10.0.1.13:2380 \
  --listen-peer-urls http://10.0.1.13:2380 \
  --listen-client-urls http://10.0.1.13:2379,http://127.0.0.1:2379 \
  --advertise-client-urls http://10.0.1.13:2379 \
  --initial-cluster infra0=http://10.0.1.10:2380,infra1=http://10.0.1.11:2380,infra3=http://10.0.1.13:2380 \
  --initial-cluster-state=new
etcd: conflicting cluster ID to the target cluster (c6ab534d07e8fcc4 != bc25ea2a74fb18b0). Exiting.
exit 1

发现

在许多情况下,可能无法提前知道集群对等节点的 IP 地址。这在使用云提供商或网络使用 DHCP 时很常见。在这种情况下,而不是指定静态配置,可以使用现有的 etcd 集群来引导新的集群。这个过程称为“发现”。

有两种方法可以用于发现:

  • etcd 发现服务
  • DNS SRV 记录

etcd 发现

为了更好地理解发现服务协议的设计,建议阅读发现服务协议文档

发现 URL 的生命周期

发现 URL 标识一个唯一的 etcd 集群。不要重用现有的发现 URL,而是让每个 etcd 实例共享一个新的发现 URL 来引导新集群。

此外,发现 URL 应仅用于集群的初始引导。要在集群已经运行后更改集群成员,请参阅运行时重新配置指南。

自定义 etcd 发现服务

发现使用现有集群来引导自身。如果使用私有 etcd 集群,请创建如下 URL:

$ curl -X PUT https://myetcd.local/v2/keys/discovery/6c007a14875d53d9bf0ef5a6fc0257c817f0fb83/_config/size -d value=3

通过将 size 键设置为 URL,创建了一个预期集群大小为 3 的发现 URL。

在这种情况下使用的 URL 将是 https://myetcd.local/v2/keys/discovery/6c007a14875d53d9bf0ef5a6fc0257c817f0fb83,并且 etcd 成员将在启动时使用 https://myetcd.local/v2/keys/discovery/6c007a14875d53d9bf0ef5a6fc0257c817f0fb83 目录进行注册。

每个成员必须指定不同的名称标志。可以使用Hostnamemachine-id作为选择。否则,由于名称重复,发现过程将失败。

现在我们为每个成员启动带有相关标志的 etcd:

$ etcd --name infra0 --initial-advertise-peer-urls http://10.0.1.10:2380 \
  --listen-peer-urls http://10.0.1.10:2380 \
  --listen-client-urls http://10.0.1.10:2379,http://127.0.0.1:2379 \
  --advertise-client-urls http://10.0.1.10:2379 \
  --discovery https://myetcd.local/v2/keys/discovery/6c007a14875d53d9bf0ef5a6fc0257c817f0fb83
$ etcd --name infra1 --initial-advertise-peer-urls http://10.0.1.11:2380 \
  --listen-peer-urls http://10.0.1.11:2380 \
  --listen-client-urls http://10.0.1.11:2379,http://127.0.0.1:2379 \
  --advertise-client-urls http://10.0.1.11:2379 \
  --discovery https://myetcd.local/v2/keys/discovery/6c007a14875d53d9bf0ef5a6fc0257c817f0fb83
$ etcd --name infra2 --initial-advertise-peer-urls http://10.0.1.12:2380 \
  --listen-peer-urls http://10.0.1.12:2380 \
  --listen-client-urls http://10.0.1.12:2379,http://127.0.0.1:2379 \
  --advertise-client-urls http://10.0.1.12:2379 \
  --discovery https://myetcd.local/v2/keys/discovery/6c007a14875d53d9bf0ef5a6fc0257c817f0fb83

这将导致每个成员向自定义的 etcd 发现服务注册自己,并在所有机器注册后开始集群。

公共 etcd 发现服务

如果没有可用的现有集群,请使用托管在 discovery.etcd.io 的公共发现服务。要使用“new”端点创建私有发现 URL,请使用以下命令:

$ curl https://discovery.etcd.io/new?size=3
https://discovery.etcd.io/3e86b59982e49066c5d813af1c2e2579cbf573de

这将创建一个初始大小为 3 个成员的集群。如果未指定大小,则默认使用 3。

ETCD_DISCOVERY=https://discovery.etcd.io/3e86b59982e49066c5d813af1c2e2579cbf573de
--discovery https://discovery.etcd.io/3e86b59982e49066c5d813af1c2e2579cbf573de

每个成员必须指定不同的名称标志,否则由于名称重复,发现过程将失败。可以使用Hostnamemachine-id作为选择。

现在我们为每个成员启动带有相关标志的 etcd:

$ etcd --name infra0 --initial-advertise-peer-urls http://10.0.1.10:2380 \
  --listen-peer-urls http://10.0.1.10:2380 \
  --listen-client-urls http://10.0.1.10:2379,http://127.0.0.1:2379 \
  --advertise-client-urls http://10.0.1.10:2379 \
  --discovery https://discovery.etcd.io/3e86b59982e49066c5d813af1c2e2579cbf573de
$ etcd --name infra1 --initial-advertise-peer-urls http://10.0.1.11:2380 \
  --listen-peer-urls http://10.0.1.11:2380 \
  --listen-client-urls http://10.0.1.11:2379,http://127.0.0.1:2379 \
  --advertise-client-urls http://10.0.1.11:2379 \
  --discovery https://discovery.etcd.io/3e86b59982e49066c5d813af1c2e2579cbf573de
$ etcd --name infra2 --initial-advertise-peer-urls http://10.0.1.12:2380 \
  --listen-peer-urls http://10.0.1.12:2380 \
  --listen-client-urls http://10.0.1.12:2379,http://127.0.0.1:2379 \
  --advertise-client-urls http://10.0.1.12:2379 \
  --discovery https://discovery.etcd.io/3e86b59982e49066c5d813af1c2e2579cbf573de

这将导致每个成员向发现服务注册自己,并在所有成员注册后开始集群。

使用环境变量 ETCD_DISCOVERY_PROXY 可以使 etcd 使用 HTTP 代理连接到发现服务。

错误和警告情况

发现服务器错误
$ etcd --name infra0 --initial-advertise-peer-urls http://10.0.1.10:2380 \
  --listen-peer-urls http://10.0.1.10:2380 \
  --listen-client-urls http://10.0.1.10:2379,http://127.0.0.1:2379 \
  --advertise-client-urls http://10.0.1.10:2379 \
  --discovery https://discovery.etcd.io/3e86b59982e49066c5d813af1c2e2579cbf573de
etcd: error: the cluster doesn’t have a size configuration value in https://discovery.etcd.io/3e86b59982e49066c5d813af1c2e2579cbf573de/_config
exit 1
警告

这是一个无害的警告,表示此机器将忽略发现 URL。

$ etcd --name infra0 --initial-advertise-peer-urls http://10.0.1.10:2380 \
  --listen-peer-urls http://10.0.1.10:2380 \
  --listen-client-urls http://10.0.1.10:2379,http://127.0.0.1:2379 \
  --advertise-client-urls http://10.0.1.10:2379 \
  --discovery https://discovery.etcd.io/3e86b59982e49066c5d813af1c2e2579cbf573de
etcdserver: discovery token ignored since a cluster has already been initialized. Valid log found at /var/lib/etcd

DNS 发现

DNS SRV 记录可以用作发现机制。--discovery-srv 标志可用于设置包含发现 SRV 记录的 DNS 域名。设置 --discovery-srv example.com 将按以下顺序查找 DNS SRV 记录:

  • _etcd-server-ssl._tcp.example.com
  • _etcd-server._tcp.example.com

如果找到 _etcd-server-ssl._tcp.example.com,则 etcd 将尝试通过 TLS 进行引导过程。

为了帮助客户端发现 etcd 集群,将按以下顺序查找以下 DNS SRV 记录:

  • _etcd-client._tcp.example.com
  • _etcd-client-ssl._tcp.example.com

如果找到 _etcd-client-ssl._tcp.example.com,客户端将尝试通过 SSL/TLS 与 etcd 集群通信。

如果 etcd 使用 TLS,则发现 SRV 记录(例如 example.com)必须包含在 SSL 证书的 DNS SAN 中,连同主机名一起,否则集群将失败并显示类似如下的日志消息:

[...] rejected connection from "10.0.1.11:53162" (error "remote error: tls: bad certificate", ServerName "example.com")

如果 etcd 使用没有自定义证书颁发机构的 TLS,则发现域(例如 example.com)必须与 SRV 记录域(例如 infra1.example.com)匹配。这是为了防止攻击者伪造 SRV 记录指向不同的域;该域可能在 PKI 下具有有效的证书,但由未知第三方控制。

-discovery-srv-name 标志还配置了在发现过程中查询的 SRV 名称的后缀。使用此标志来区分同一域名下的多个 etcd 集群。例如,如果设置了 discovery-srv=example.com-discovery-srv-name=foo,则会进行以下 DNS SRV 查询:

  • _etcd-server-ssl-foo._tcp.example.com
  • _etcd-server-foo._tcp.example.com

创建 DNS SRV 记录

$ dig +noall +answer SRV _etcd-server._tcp.example.com
_etcd-server._tcp.example.com. 300 IN  SRV  0 0 2380 infra0.example.com.
_etcd-server._tcp.example.com. 300 IN  SRV  0 0 2380 infra1.example.com.
_etcd-server._tcp.example.com. 300 IN  SRV  0 0 2380 infra2.example.com.
$ dig +noall +answer SRV _etcd-client._tcp.example.com
_etcd-client._tcp.example.com. 300 IN SRV 0 0 2379 infra0.example.com.
_etcd-client._tcp.example.com. 300 IN SRV 0 0 2379 infra1.example.com.
_etcd-client._tcp.example.com. 300 IN SRV 0 0 2379 infra2.example.com.
$ dig +noall +answer infra0.example.com infra1.example.com infra2.example.com
infra0.example.com.  300  IN  A  10.0.1.10
infra1.example.com.  300  IN  A  10.0.1.11
infra2.example.com.  300  IN  A  10.0.1.12

使用 DNS 启动 etcd 集群

etcd 集群成员可以广播域名或 IP 地址,引导过程将解析 DNS A 记录。从 3.2 版本开始(3.1 版本会打印警告),--listen-peer-urls--listen-client-urls 将拒绝用于网络接口绑定的域名。

--initial-advertise-peer-urls 中解析的地址 必须匹配 SRV 目标中解析的地址之一。etcd 成员读取解析的地址以确定其是否属于 SRV 记录中定义的集群。

$ etcd --name infra0 \
--discovery-srv example.com \
--initial-advertise-peer-urls http://infra0.example.com:2380 \
--initial-cluster-token etcd-cluster-1 \
--initial-cluster-state new \
--advertise-client-urls http://infra0.example.com:2379 \
--listen-client-urls http://0.0.0.0:2379 \
--listen-peer-urls http://0.0.0.0:2380
$ etcd --name infra1 \
--discovery-srv example.com \
--initial-advertise-peer-urls http://infra1.example.com:2380 \
--initial-cluster-token etcd-cluster-1 \
--initial-cluster-state new \
--advertise-client-urls http://infra1.example.com:2379 \
--listen-client-urls http://0.0.0.0:2379 \
--listen-peer-urls http://0.0.0.0:2380
$ etcd --name infra2 \
--discovery-srv example.com \
--initial-advertise-peer-urls http://infra2.example.com:2380 \
--initial-cluster-token etcd-cluster-1 \
--initial-cluster-state new \
--advertise-client-urls http://infra2.example.com:2379 \
--listen-client-urls http://0.0.0.0:2379 \
--listen-peer-urls http://0.0.0.0:2380

集群也可以使用 IP 地址而不是域名进行引导:

$ etcd --name infra0 \
--discovery-srv example.com \
--initial-advertise-peer-urls http://10.0.1.10:2380 \
--initial-cluster-token etcd-cluster-1 \
--initial-cluster-state new \
--advertise-client-urls http://10.0.1.10:2379 \
--listen-client-urls http://10.0.1.10:2379 \
--listen-peer-urls http://10.0.1.10:2380
$ etcd --name infra1 \
--discovery-srv example.com \
--initial-advertise-peer-urls http://10.0.1.11:2380 \
--initial-cluster-token etcd-cluster-1 \
--initial-cluster-state new \
--advertise-client-urls http://10.0.1.11:2379 \
--listen-client-urls http://10.0.1.11:2379 \
--listen-peer-urls http://10.0.1.11:2380
$ etcd --name infra2 \
--discovery-srv example.com \
--initial-advertise-peer-urls http://10.0.1.12:2380 \
--initial-cluster-token etcd-cluster-1 \
--initial-cluster-state new \
--advertise-client-urls http://10.0.1.12:2379 \
--listen-client-urls http://10.0.1.12:2379 \
--listen-peer-urls http://10.0.1.12:2380

从 v3.1.0 版本开始(v3.2.9 除外),当 etcd --discovery-srv=example.com 配置了 TLS 时,服务器仅在提供的证书具有根域名 example.com 作为主题备用名称 (SAN) 字段中的条目时才会对对等/客户端进行身份验证。请参阅DNS SRV 注意事项

网关

etcd 网关是一个简单的 TCP 代理,它将网络数据转发到 etcd 集群。请阅读网关指南以获取更多信息。

代理

当设置了 --proxy 标志时,etcd 以代理模式运行。此代理模式仅支持 etcd v2 API;目前没有计划支持 v3 API。相反,对于 v3 API 支持,将在 etcd 3.0 发布后提供一个具有增强功能的新代理。

要设置带有 v2 API 代理的 etcd 集群,请阅读etcd 2.3 版本中的集群文档


最后更新于 2025 年 6 月 3 日:递归地将 v3.6 的内容复制到 v3.7(a90b2a6)