etcd-cluster 集群部署

摘要

本文部分内容来源于网络,个人收集整理,请勿传播

etcd 是一个分布式一致性k-v存储系统,可用于服务注册发现与共享配置,具有以下优点。

  • 简单:相比于晦涩难懂的paxos算法,etcd基于相对简单且易实现的raft算法实现一致性,并通过gRPC提供接口调用
  • 安全:支持TLS通信,并可以针对不同的用户进行对key的读写控制
  • 高性能:10,000 /秒的写性能

安装etcd

1
2
3
4
5
6
7
8
9
ETCD_VER="v3.2.4"
DOWNLOAD_URL="https://github.com/coreos/etcd/releases/download"
LOCAL_DIR="/data/soft"
mkdir ${LOCAL_DIR}
curl -L ${DOWNLOAD_URL}/${ETCD_VER}/etcd-${ETCD_VER}-linux-amd64.tar.gz -o ${LOCAL_DIR}/etcd-${ETCD_VER}-linux-amd64.tar.gz
mkdir -p ${LOCAL_DIR}/etcd && tar xzvf ${LOCAL_DIR}/etcd-${ETCD_VER}-linux-amd64.tar.gz -C ${LOCAL_DIR}/etcd --strip-components=1

cd ${LOCAL_DIR}/etcd/ && cp etcd etcdctl /usr/local/bin
etcd -version

单机模式

使用默认配置运行etcd,监听本地的2379端口,用于与client端交互,监听2380用于etcd内部交互,当然,这里单机不会使用到。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
localip=`ifconfig eth0  | grep "inet" | awk '{print $2}'`
etcd --name infra0 -data-dir /data/default.etcd \
--initial-advertise-peer-urls http://${localip}:2380 \
--listen-peer-urls http://${localip}:2380 \
--listen-client-urls http://${localip}:2329,http://127.0.0.1:2329 \
--advertise-client-urls http://${localip}:2329 &

etcdctl set hello world
world

etcdctl get hello
world

通过etcdctl工具进行测试,以上表示单机可以工作。

etcdctl 使用请移步etcd基本操作方式

配置项说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
--name
# etcd集群中的节点名,这里可以随意,可区分且不重复就行
--listen-peer-urls
# 监听的用于节点之间通信的url,可监听多个,集群内部将通过这些url进行数据交互(如选举,数据同步等)
--initial-advertise-peer-urls
# 建议用于节点之间通信的url,节点间将以该值进行通信。
--listen-client-urls
# 监听的用于客户端通信的url,同样可以监听多个。
--advertise-client-urls
# 建议使用的客户端通信url,该值用于etcd代理或etcd成员与etcd节点通信。
--initial-cluster-token etcd-cluster-1
# 节点的token值,设置该值后集群将生成唯一id,并为每个节点也生成唯一id,当使用相同配置文件再启动一个集群时,只要该token值不一样,etcd集群就不会相互影响。
--initial-cluster
# 也就是集群中所有的initial-advertise-peer-urls 的合集
--initial-cluster-state new
# 新建集群的标志

etcd集群模式

集群搭建有三种方式,分别是

  • 静态配置
  • etcd发现
  • dns发现

静态模式

本文将在三台节点主机搭建etcd集群

静态配置主要预先将集群的配置信息分配好,然后将集群分布启动,集群将根据配置信息组成集群。这里按如下的配置信息分别启动三个etcd。

节点配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 基本配置 在每个节点都要添加
NAME_1=infra1
NAME_2=infra2
NAME_3=infra3
HOST_1=172.16.7.1
HOST_2=172.16.7.2
HOST_3=172.16.7.3

ETCD_DATA_DIR="/data/infra.etcd/"
# 这里需要根据不同节点修改
ETCD_NAME="${NAME_1}"
ETCD_IP="${HOST_1}"

ETCD_LISTEN_PEER_URLS="http://${ETCD_IP}:2380"
ETCD_LISTEN_CLIENT_URLS="http://${ETCD_IP}:2379,http://127.0.0.1:2379"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://${ETCD_IP}":2380
ETCD_INITIAL_CLUSTER=${NAME_1}=http://${HOST_1}:2380,${NAME_2}=http://${HOST_2}:2380,${NAME_3}=http://${HOST_3}:2380
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster-test"
ETCD_ADVERTISE_CLIENT_URLS="http://${ETCD_IP}:2379"

etcd --name ${ETCD_NAME} --data-dir ${ETCD_DATA_DIR} \
--listen-peer-urls ${ETCD_LISTEN_PEER_URLS} \
--listen-client-urls ${ETCD_LISTEN_CLIENT_URLS} \
--initial-advertise-peer-urls ${ETCD_INITIAL_ADVERTISE_PEER_URLS} \
--advertise-client-urls ${ETCD_ADVERTISE_CLIENT_URLS} \
--initial-cluster ${ETCD_INITIAL_CLUSTER} \
--initial-cluster-state ${ETCD_INITIAL_CLUSTER_STATE} \
--initial-cluster-token ${ETCD_INITIAL_CLUSTER_TOKEN}

客户端配置

1
2
3
4
5
6
export ETCDCTL_API=3
export HOST_1=172.16.7.1
export HOST_2=172.16.7.2
export HOST_3=172.16.7.3
export ENDPOINTS=$HOST_1:2379,$HOST_2:2379,$HOST_3:2379
alias etcdctl='etcdctl --endpoints=$ENDPOINTS'

集群测试

按如上配置分别启动集群,启动集群后,将会进入集群选举状态,若出现大量超时,则需要检查主机的防火墙是否关闭,或主机之间是否能通过2380端口通信,集群建立后通过以下命令检查集群状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
etcdctl member list
45eebb14ca4227e4: name=infra2 peerURLs=http://172.16.7.2:2380 clientURLs=http://172.16.7.2:2379 isLeader=false
6a50d44f947522d1: name=infra3 peerURLs=http://172.16.7.3:2380 clientURLs=http://172.16.7.3:2379 isLeader=false
75c1b1800f01ef51: name=infra1 peerURLs=http://172.16.7.1:2380 clientURLs=http://172.16.7.1:2379 isLeader=true

# api2
etcdctl cluster-health
member 45eebb14ca4227e4 is healthy: got healthy result from http://172.16.7.2:2379
member 6a50d44f947522d1 is healthy: got healthy result from http://172.16.7.3:2379
member 75c1b1800f01ef51 is healthy: got healthy result from http://172.16.7.1:2379
cluster is healthy

# api3
etcdctl endpoint health
172.16.7.1:2379 is healthy: successfully committed proposal: took = 2.580148ms
172.16.7.2:2379 is healthy: successfully committed proposal: took = 2.862738ms
172.16.7.3:2379 is healthy: successfully committed proposal: took = 2.981795ms

在其中一个节点执行

1
2
3
4
5
6
# api2
etcdctl set my xxx
xxx
# api3
etcdctl put my xxx
OK

其他节点执行有正常返回结果说明集群搭建成功

1
2
etcdctl get my
xxx

静态配置的节点扩容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
curl -XPOST http://127.0.0.1:2379/v2/members \
-H "Content-Type: application/json" \
-d '{"peerURLs": ["http://172.16.7.4:2380"]}'

NAME_1=infra1
NAME_2=infra2
NAME_3=infra3
NAME_4=infra4
HOST_1=172.16.7.1
HOST_2=172.16.7.2
HOST_3=172.16.7.3
HOST_4=172.16.7.4

ETCD_DATA_DIR="/data/infra.etcd/"
ETCD_NAME="${NAME_4}"
ETCD_IP="${HOST_4}"

ETCD_LISTEN_PEER_URLS="http://${ETCD_IP}:2380"
ETCD_LISTEN_CLIENT_URLS="http://${ETCD_IP}:2379,http://127.0.0.1:2379"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://${ETCD_IP}":2380
ETCD_INITIAL_CLUSTER=${NAME_1}=http://${HOST_1}:2380,${NAME_2}=http://${HOST_2}:2380,${NAME_3}=http://${HOST_3}:2380,$
ETCD_INITIAL_CLUSTER_STATE="existing"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster-test"
ETCD_ADVERTISE_CLIENT_URLS="http://${ETCD_IP}:2379"

# For machine 4
etcd --name ${ETCD_NAME} --data-dir ${ETCD_DATA_DIR} \
--listen-peer-urls ${ETCD_LISTEN_PEER_URLS} \
--listen-client-urls ${ETCD_LISTEN_CLIENT_URLS} \
--initial-advertise-peer-urls ${ETCD_INITIAL_ADVERTISE_PEER_URLS} \
--advertise-client-urls ${ETCD_ADVERTISE_CLIENT_URLS} \
--initial-cluster ${ETCD_INITIAL_CLUSTER} \
--initial-cluster-state ${ETCD_INITIAL_CLUSTER_STATE} \
--initial-cluster-token ${ETCD_INITIAL_CLUSTER_TOKEN}

使用supervisord管理etcd进程

supervisord的安装配置详细说明请移步supervisord安装配置

使用三种方式,个人使用第一种方式

  • 根据现有启动命令脚本
  • systemd配置service
  • 完全配置到supervisor里面

创建目录

1
2
mkdir -p /etc/supervisor/conf.d/
mkdir -p /data/logs/supervisor/

根据现有脚本

配置 /etc/supervisor/supervisord.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[unix_http_server]
file=/var/run/supervisor.sock ; (the path to the socket file)
chmod=0700 ; sockef file mode (default 0700)

[supervisord]
logfile=/data/logs/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log)
pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
childlogdir=/data/logs/supervisor ; ('AUTO' child log dir, default $TEMP)
logfile_maxbytes=50MB ; (max main logfile bytes b4 rotation;default 50MB)
logfile_backups=10 ; (num of main logfile rotation backups;default 10)
loglevel=info ; (log level;default info; others: debug,warn,trace)
nodaemon=false ; (start in foreground if true;default false)
minfds=1024 ; (min. avail startup file descriptors;default 1024)

[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface

[supervisorctl]
serverurl=unix:///var/run/supervisor.sock ; use a unix:// URL for a unix socket

[include]
files = /etc/supervisor/conf.d/*.conf

配置 /etc/supervisor/conf.d/etcd.conf

1
2
3
4
5
6
7
8
[program:etcd]
directory = /data/bin/
command = /bin/sh etcd.sh
user = root
autostart = true
autorestart = true
stdout_logfile = /data/logs/supervisor/etcd.log
stderr_logfile = /data/logs/supervisor/etcd_err.log

启动服务

1
2
3
4
supervisord -c /etc/supervisor/supervisord.conf

supervisorctl status etcd
etcd RUNNING pid 18721, uptime 0:01:45

systemd配置service

分别配置不同节点的etcd配置文件

1
mkdir /etc/etcd/ && vim /etc/etcd/etcd.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
tee /etc/etcd/etcd.conf <<-'EOF'
# [member]
ETCD_NAME="infra1"
ETCD_IP="172.16.7.1"
ETCD_DATA_DIR="/data/infra.etcd/"
#ETCD_WAL_DIR=""
#ETCD_SNAPSHOT_COUNT="10000"
#ETCD_HEARTBEAT_INTERVAL="100"
#ETCD_ELECTION_TIMEOUT="1000"
ETCD_LISTEN_PEER_URLS="http://172.16.7.1:2380"
ETCD_LISTEN_CLIENT_URLS="http://172.16.7.1:2379,http://127.0.0.1:2379"
#ETCD_MAX_SNAPSHOTS="5"
#ETCD_MAX_WALS="5"
#ETCD_CORS=""

# [cluster]
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://172.16.7.1:2380"
ETCD_INITIAL_CLUSTER="infra1=http://172.16.7.1:2380,infra2=http://172.16.7.2:2380,infra3=http://172.16.7.3:2380"
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster-test"
ETCD_ADVERTISE_CLIENT_URLS="http://172.16.7.1:2379"
#ETCD_DISCOVERY=""
#ETCD_DISCOVERY_SRV=""
#ETCD_DISCOVERY_FALLBACK="proxy"
#ETCD_DISCOVERY_PROXY=""

# [proxy]
#ETCD_PROXY="off"
#ETCD_PROXY_FAILURE_WAIT="5000"
#ETCD_PROXY_REFRESH_INTERVAL="30000"
#ETCD_PROXY_DIAL_TIMEOUT="1000"
#ETCD_PROXY_WRITE_TIMEOUT="5000"
#ETCD_PROXY_READ_TIMEOUT="0"

# [security]
#ETCD_CERT_FILE=""
#ETCD_KEY_FILE=""
#ETCD_CLIENT_CERT_AUTH="false"
#ETCD_TRUSTED_CA_FILE=""
#ETCD_PEER_CERT_FILE=""
#ETCD_PEER_KEY_FILE=""
#ETCD_PEER_CLIENT_CERT_AUTH="false"
#ETCD_PEER_TRUSTED_CA_FILE=""

# [logging]
#ETCD_DEBUG="false"
# examples for -log-package-levels etcdserver=WARNING,security=DEBUG
#ETCD_LOG_PACKAGE_LEVELS=""
EOF

修改 /usr/lib/systemd/system/etcd.service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
tee  /usr/lib/systemd/system/etcd.service <<-'EOF'
[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target

[Service]
Type=notify
NotifyAccess=all
WorkingDirectory=/
EnvironmentFile=-/etc/etcd/etcd.conf
User=root
# set GOMAXPROCS to number of processors
ExecStart=/bin/bash -c "GOMAXPROCS=$(nproc) /usr/local/bin/etcd --name=\"${ETCD_NAME}\" --data-dir=\"${ETCD_DATA_DIR}\" --listen-client-urls=\"${ETCD_LISTEN_CLIENT_URLS}\" --listen-peer-urls=\"${ETCD_LISTEN_PEER_URLS}\" --advertise-client-urls=\"${ETCD_ADVERTISE_CLIENT_URLS}\" --initial-advertise-peer-urls=\"${ETCD_INITIAL_ADVERTISE_PEER_URLS}\" --initial-cluster=\"${ETCD_INITIAL_CLUSTER}\" --initial-cluster-state=\"${ETCD_INITIAL_CLUSTER_STATE}\" --initial-cluster-token=\"${ETCD_INITIAL_CLUSTER_TOKEN}\""
Restart=on-failure
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF

添加服务

1
systemctl enable etcd.service

启动服务

1
systemctl start etcd.service

完全配置supervisor

实验失败了,暂时使用其他方法吧

etcd发现模式

静态配置前提是在搭建集群之前已经提前知道各节点的信息,而实际应用中可能存在预先并不知道各节点ip的情况,这时可通过已经搭建的etcd来辅助搭建新的etcd集群,具体过程如下,

基于现有etcd

首先需要在已经搭建的etcd中创建用于发现的url

1
2
3
4
curl -X PUT http://10.0.1.33:2379/v2/keys/discovery/etcd-cluster-1/_config/size -d value=3

返回:
{"action":"set","node":{"key":"/discovery/etcd-cluster-1/_config/size","value":"3","modifiedIndex":170010,"createdIndex":170010}}

如上表示创建一个集群大小为3的etcd发现url,创建成功后按如下配置启动各节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# master
localip=`ifconfig eth0 | grep "inet" | awk '{print $2}'`
etcd --name infra0 -data-dir /data/bin/default.etcd \
--initial-advertise-peer-urls http://${localip}:2382 \
--listen-peer-urls http://${localip}:2382 \
--listen-client-urls http://${localip}:2381,http://127.0.0.1:2381 \
--advertise-client-urls http://${localip}:2381 &

sleep 1
curl -X PUT http://127.0.0.1:2381/v2/keys/discovery/etcd-cluster-1/_config/size -d value=3

# base
NAME_1=infra1
NAME_2=infra2
NAME_3=infra3
NAME_4=infra4
HOST_1=172.16.7.1
HOST_2=172.16.7.2
HOST_3=172.16.7.3
HOST_4=172.16.7.4

ETCD_DATA_DIR="/data/infra.etcd/"
# 这里需要根据不同节点修改
# ETCD_NAME="${NAME_1}"
# ETCD_IP="${HOST_1}"

ETCD_LISTEN_PEER_URLS="http://${ETCD_IP}:2380"
ETCD_LISTEN_CLIENT_URLS="http://${ETCD_IP}:2379,http://127.0.0.1:2379"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://${ETCD_IP}":2380
ETCD_INITIAL_CLUSTER=${NAME_1}=http://${HOST_1}:2380,${NAME_2}=http://${HOST_2}:2380,${NAME_3}=http://${HOST_3}:2380,$
ETCD_INITIAL_CLUSTER_STATE="existing"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster-test"
ETCD_ADVERTISE_CLIENT_URLS="http://${ETCD_IP}:2379"
ETCD_DISCOVERY="http://172.16.7.1:2381/v2/keys/discovery/${ETCD_INITIAL_CLUSTER_TOKEN}"

# For machine 1
ETCD_NAME="${NAME_1}"
ETCD_IP="${HOST_1}"
etcd --name ${ETCD_NAME} --data-dir ${ETCD_DATA_DIR} \
--listen-peer-urls ${ETCD_LISTEN_PEER_URLS} \
--listen-client-urls ${ETCD_LISTEN_CLIENT_URLS} \
--initial-advertise-peer-urls ${ETCD_INITIAL_ADVERTISE_PEER_URLS} \
--advertise-client-urls ${ETCD_ADVERTISE_CLIENT_URLS} \
--discovery ${ETCD_DISCOVERY} \
--initial-cluster-state ${ETCD_INITIAL_CLUSTER_STATE} \
--initial-cluster-token ${ETCD_INITIAL_CLUSTER_TOKEN}

# For machine 2
ETCD_NAME="${NAME_2}"
ETCD_IP="${HOST_2}"
etcd --name ${ETCD_NAME} --data-dir ${ETCD_DATA_DIR} \
--listen-peer-urls ${ETCD_LISTEN_PEER_URLS} \
--listen-client-urls ${ETCD_LISTEN_CLIENT_URLS} \
--initial-advertise-peer-urls ${ETCD_INITIAL_ADVERTISE_PEER_URLS} \
--advertise-client-urls ${ETCD_ADVERTISE_CLIENT_URLS} \
--discovery ${ETCD_DISCOVERY} \
--initial-cluster-state ${ETCD_INITIAL_CLUSTER_STATE} \
--initial-cluster-token ${ETCD_INITIAL_CLUSTER_TOKEN}

# For machine 3
ETCD_NAME="${NAME_3}"
ETCD_IP="${HOST_3}"
etcd --name ${ETCD_NAME} --data-dir ${ETCD_DATA_DIR} \
--listen-peer-urls ${ETCD_LISTEN_PEER_URLS} \
--listen-client-urls ${ETCD_LISTEN_CLIENT_URLS} \
--initial-advertise-peer-urls ${ETCD_INITIAL_ADVERTISE_PEER_URLS} \
--advertise-client-urls ${ETCD_ADVERTISE_CLIENT_URLS} \
--discovery ${ETCD_DISCOVERY} \
--initial-cluster-state ${ETCD_INITIAL_CLUSTER_STATE} \
--initial-cluster-token ${ETCD_INITIAL_CLUSTER_TOKEN}

如上当所有etcd均注册到用于发现的url后,独立的各节点将形成集群。

另一方面,如果没有搭建好的etcd集群用于注册和发现,可使用etcd公有服务来进行服务注册发现。

基于公有etcd

在公有etcd服务上创建用于发现的url:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
curl https://discovery.etcd.io/new?size=3
https://discovery.etcd.io/a81b5818e67a6ea83e9d4daea5ecbc92

# grab this token
TOKEN=token-01
CLUSTER_STATE=new
NAME_1=machine-1
NAME_2=machine-2
NAME_3=machine-3
HOST_1=10.240.0.17
HOST_2=10.240.0.18
HOST_3=10.240.0.19
DATA_DIR=/data/infra.etcd
DISCOVERY=https://discovery.etcd.io/a81b5818e67a6ea83e9d4daea5ecbc92

# For machine 1
THIS_NAME=${NAME_1}
THIS_IP=${HOST_1}
etcd --name ${THIS_NAME} --data-dir ${DATA_DIR} \
--initial-advertise-peer-urls http://${THIS_IP}:2380 \
--listen-peer-urls http://${THIS_IP}:2380 \
--advertise-client-urls http://${THIS_IP}:2379 \
--listen-client-urls http://${THIS_IP}:2379,http://127.0.0.1:2379 \
--discovery ${DISCOVERY} \
--initial-cluster-state ${CLUSTER_STATE} \
--initial-cluster-token ${TOKEN}

# For machine 2
THIS_NAME=${NAME_2}
THIS_IP=${HOST_2}
etcd --name ${THIS_NAME} --data-dir ${DATA_DIR} \
--initial-advertise-peer-urls http://${THIS_IP}:2380 \
--listen-peer-urls http://${THIS_IP}:2380 \
--advertise-client-urls http://${THIS_IP}:2379 \
--listen-client-urls http://${THIS_IP}:2379,http://127.0.0.1:2379 \
--discovery ${DISCOVERY} \
--initial-cluster-state ${CLUSTER_STATE} \
--initial-cluster-token ${TOKEN}

# For machine 3
THIS_NAME=${NAME_3}
THIS_IP=${HOST_3}
etcd --name ${THIS_NAME} --data-dir ${DATA_DIR} \
--initial-advertise-peer-urls http://${THIS_IP}:2380 \
--listen-peer-urls http://${THIS_IP}:2380 \
--advertise-client-urls http://${THIS_IP}:2379 \
--listen-client-urls http://${THIS_IP}:2379,http://127.0.0.1:2379 \
--discovery ${DISCOVERY} \
--initial-cluster-state ${CLUSTER_STATE} \
--initial-cluster-token ${TOKEN}

将返回的url替换上面的 –discovery部分,启动各个节点etcd,建立集群。

dns发现模式

dns 发现主要通过dns服务来记录集群中各节点的域名信息,各节点到dns服务中获取相互的地址信息,从而建立集群。etcd各节点通过–discovery-serv配置来获取域名信息,节点间将获取以下域名下的各节点域名,

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

如果_etcd-server-ssl._tcp.example.com下有值表示节点间将使用ssl协议,相反则使用非ssl。

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

另一方面,client端将获取以上域名下的节点域名,用于client端与etcd通信,ssl与非ssl的使用取决于以上那个域名下有值。

创建dns记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ 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.111
infra1.example.com. 300 IN A 10.0.1.109
infra2.example.com. 300 IN A 10.0.1.110

启动各个节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$ 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://infra0.example.com:2379 \
--listen-peer-urls http://infra0.example.com: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://infra1.example.com:2379 \
--listen-peer-urls http://infra1.example.com: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://infra2.example.com:2379 \
--listen-peer-urls http://infra2.example.com:2380

etcd接口访问

目前etcd已经支持很多语言的client端,目测主流语言均有对应的库, 具体见https://github.com/coreos/etcd/blob/master/Documentation/libraries-and-tools.md,不同语言只需要导入相应的库即可进行开发。

后续会有其他文章单独写这里的详细操作

etcd使用场景简述

说完etcd的搭建,这里简单的描述两个常用的etcd使用场景,服务注册发现以及共享配置

服务注册与发现

img

随着近来微服务概念的提出,服务的分解必然引入大量的服务之间的相互调用,而传统的服务调用一般通过配置文件读取ip进行调用,这里有诸多限制,如不灵活,无法感知服务的状态,实现服务调用负载均衡复杂等缺点,而引入etcd后,问题将大大化简,这里划分为几个步骤

服务启动后向etcd注册,并上报自己的监听的端口以及当前的权重因子等信息,且对该信息设置ttl值。
服务在ttl的时间内周期性上报权重因子等信息。

client端调用服务时向etcd获取信息,进行调用,同时监听该服务是否变化(通过watch方法实现)。
当新增服务时watch方法监听到变化,将服务加入代用列表,当服务挂掉时ttl失效,client端检测到变化,将服务踢出调用列表,从而实现服务的动态扩展。

另一方面,client端通过每次变化获取到的权重因子来进行client端的加权调用策略,从而保证后端服务的负载均衡。

共享配置

一般服务启动时需要加载一些配置信息,如数据库访问地址,连接配置,这些配置信息每个服务都差不多,如果通过读取配置文件进行配置会存在要写多份配置文件,且每次更改时这些配置文件都要更改,且更改配置后,需要重启服务后才能生效,这些无疑让配置极不灵活,如果将配置信息放入到etcd中,程序启动时进行加载并运行,同时监听配置文件的更改,当配置文件发生更改时,自动将旧值替换新值,这样无疑简化程序配置,更方便于服务部署。

总结

本文讲解了etcd集群的搭建,以及简述了一些应用场景,相比于zookeeper内部使用paxos算法保证一致性,而etcd则使用更简单的raft算法。另一方面,相比zookeeper, etcd算是新兴项目,因而在知名度及使用量来说和zookeeper有一定差距,不过,随着越来越多的知名项目在逐渐使用etcd(如docker),相信etcd将会在未来更多的出现在各种服务体系中。目前我们已经在生产环境中大量使用etcd,从使用效果来看,稳定性还是不错的,目前还没遇到什么大坑。

1
2
3
参考资料
https://coreos.com/etcd/
https://github.com/coreos/etcd