一、简介
etcd是一个高可用的分布式键值(key-value)数据库。etcd内部采用raft协议作为一致性算法,etcd基于Go语言实现。
提供配置共享和服务发现的系统比较多,其中最为大家熟知的是[Zookeeper](后文简称ZK),而ETCD可以算得上是后起之秀了。在项目实现,一致性协议易理解性,运维,安全等多个维度上,ETCD相比Zookeeper都占据优势。
etcd是一个服务发现系统,具备以下的特点:
- 简单:安装配置简单,而且提供了HTTP API进行交互,使用也很简单
- 安全:支持SSL证书验证
- 快速:根据官方提供的benchmark数据,单实例支持每秒2k+读操作
- 可靠:采用raft算法,实现分布式系统数据的可用性和一致性
二、ETCD vs ZK
本文选取ZK作为典型代表与ETCD进行比较,而不考虑[Consul]项目作为比较对象,原因为Consul的可靠性和稳定性还需要时间来验证(项目发起方自身服务并未使用Consul, 自己都不用)。
- 一致性协议: ETCD使用[Raft]协议, ZK使用ZAB(类PAXOS协议),前者容易理解,方便工程实现;
- 运维方面:ETCD方便运维,ZK难以运维;
- 项目活跃度:ETCD社区与开发活跃,ZK已经快死了;
- API:ETCD提供HTTP+JSON, gRPC接口,跨平台跨语言,ZK需要使用其客户端;
- 访问安全方面:ETCD支持HTTPS访问,ZK在这方面缺失;
三、应用场景
和ZK类似,ETCD有很多使用场景,包括:
- 配置管理
- 服务注册于发现
- 选主
- 应用调度
- 分布式队列
- 分布式锁
四、读写性能
按照官网给出的[Benchmark], 在2CPU,1.8G内存,SSD磁盘这样的配置下,单节点的写性能可以达到16K QPS, 而先写后读也能达到12K QPS。这个性能还是相当可观的。
五、工作原理
ETCD使用Raft协议来维护集群内各个节点状态的一致性。简单说,ETCD集群是一个分布式系统,由多个节点相互通信构成整体对外服务,每个节点都存储了完整的数据,并且通过Raft协议保证每个节点维护的数据是一致的。
如图所示,每个ETCD节点都维护了一个状态机,并且,任意时刻至多存在一个有效的主节点。主节点处理所有来自客户端写操作,通过Raft协议保证写操作对状态机的改动会可靠的同步到其他节点。
ETCD工作原理核心部分在于Raft协议。本节接下来将简要介绍Raft协议,具体细节请参考其[论文]。
Raft协议正如论文所述,确实方便理解。主要分为三个部分:选主,日志复制,安全性。
选主
Raft协议是用于维护一组服务节点数据一致性的协议。这一组服务节点构成一个集群,并且有一个主节点来对外提供服务。当集群初始化,或者主节点挂掉后,面临一个选主问题。集群中每个节点,任意时刻处于Leader, Follower, Candidate这三个角色之一。选举特点如下:
- 当集群初始化时候,每个节点都是Follower角色;
- 集群中存在至多1个有效的主节点,通过心跳与其他节点同步数据;
- 当Follower在一定时间内没有收到来自主节点的心跳,会将自己角色改变为Candidate,并发起一次选主投票;当收到包括自己在内超过半数节点赞成后,选举成功;当收到票数不足半数选举失败,或者选举超时。若本轮未选出主节点,将进行下一轮选举(出现这种情况,是由于多个节点同时选举,所有节点均为获得过半选票)。
-
Candidate节点收到来自主节点的信息后,会立即终止选举过程,进入Follower角色。
为了避免陷入选主失败循环,每个节点未收到心跳发起选举的时间是一定范围内的随机值,这样能够避免2个节点同时发起选主。
日志复制
所谓日志复制,是指主节点将每次操作形成日志条目,并持久化到本地磁盘,然后通过网络IO发送给其他节点。其他节点根据日志的逻辑时钟(TERM)和日志编号(INDEX)来判断是否将该日志记录持久化到本地。当主节点收到包括自己在内超过半数节点成功返回,那么认为该日志是可提交的(committed),并将日志输入到状态机,将结果返回给客户端。
这里需要注意的是,每次选主都会形成一个唯一的TERM编号,相当于逻辑时钟。每一条日志都有全局唯一的编号。
主节点通过网络IO向其他节点追加日志。若某节点收到日志追加的消息,首先判断该日志的TERM是否过期,以及该日志条目的INDEX是否比当前以及提交的日志的INDEX跟早。若已过期,或者比提交的日志更早,那么就拒绝追加,并返回该节点当前的已提交的日志的编号。否则,将日志追加,并返回成功。
当主节点收到其他节点关于日志追加的回复后,若发现有拒绝,则根据该节点返回的已提交日志编号,发生其编号下一条日志。
主节点像其他节点同步日志,还作了拥塞控制。具体地说,主节点发现日志复制的目标节点拒绝了某次日志追加消息,将进入日志探测阶段,一条一条发送日志,直到目标节点接受日志,然后进入快速复制阶段,可进行批量日志追加。
按照日志复制的逻辑,我们可以看到,集群中慢节点不影响整个集群的性能。另外一个特点是,数据只从主节点复制到Follower节点,这样大大简化了逻辑流程。
安全性
截止此刻,选主以及日志复制并不能保证节点间数据一致。试想,当一个某个节点挂掉了,一段时间后再次重启,并当选为主节点。而在其挂掉这段时间内,集群若有超过半数节点存活,集群会正常工作,那么会有日志提交。这些提交的日志无法传递给挂掉的节点。当挂掉的节点再次当选主节点,它将缺失部分已提交的日志。在这样场景下,按Raft协议,它将自己日志复制给其他节点,会将集群已经提交的日志给覆盖掉。
这显然是不可接受的。
其他协议解决这个问题的办法是,新当选的主节点会询问其他节点,和自己数据对比,确定出集群已提交数据,然后将缺失的数据同步过来。这个方案有明显缺陷,增加了集群恢复服务的时间(集群在选举阶段不可服务),并且增加了协议的复杂度。
Raft解决的办法是,在选主逻辑中,对能够成为主的节点加以限制,确保选出的节点已定包含了集群已经提交的所有日志。如果新选出的主节点已经包含了集群所有提交的日志,那就不需要从和其他节点比对数据了。简化了流程,缩短了集群恢复服务的时间。
这里存在一个问题,加以这样限制之后,还能否选出主呢?答案是:只要仍然有超过半数节点存活,这样的主一定能够选出。因为已经提交的日志必然被集群中超过半数节点持久化,显然前一个主节点提交的最后一条日志也被集群中大部分节点持久化。当主节点挂掉后,集群中仍有大部分节点存活,那这存活的节点中一定存在一个节点包含了已经提交的日志了。
至此,关于Raft协议的简介就全部结束了。
六、使用案例
据公开资料显示,至少有CoreOS, Google Kubernetes, Cloud Foundry, 以及在Github上超过500个项目在使用ETCD。
七、接口
ETCD提供HTTP协议,在最新版本中支持Google gRPC方式访问。具体支持接口情况如下:
- ETCD是一个高可靠的KV存储系统,支持PUT/GET/DELETE接口;
- 为了支持服务注册与发现,支持WATCH接口(通过http long poll实现);
- 支持KEY持有TTL属性;
- CAS(compare and swap)操作;
- 支持多key的事务操作;
- 支持目录操作
八、正式安装(单节点)
etcd在生产环境中一般推荐集群方式部署。在这里,主要讲讲单节点安装和基本使用。
因为etcd是go语言编写的,安装只需要下载对应的二进制文件,并放到合适的路径就行。
下载软件包
访问下载链接:
https://github.com/etcd-io/etcd/releases
目前最新版本是3.3.10,所以完整的下载链接如下:
https://github.com/etcd-io/etcd/releases/download/v3.3.10/etcd-v3.3.10-linux-amd64.tar.gz
安装
本文所使用的系统为: ubuntu-16.04.5-server-amd64
wget https://github.com/etcd-io/etcd/releases/download/v3.3.10/etcd-v3.3.10-linux-amd64.tar.gz tar zxvf etcd-v3.3.10-linux-amd64.tar.gz mv etcd-v3.3.10-linux-amd64 /opt/etcd-v3.3.10
解压后的文件如下所示:
root@ubuntu:/opt/etcd-v3.3.10# ls default.etcd Documentation etcd etcdctl README-etcdctl.md README.md READMEv2-etcdctl.md
其中etcd是server端,etcdctl是客户端,操作之后会生成一个default.etcd,主要用来存储etct数据。
启动一个单节点的etcd服务,只需要运行etcd命令就行。不过有可能会出现以下问题:
root@ubuntu:/opt/etcd-v3.3.10# ./etcd bash: ./etcd: 权限不够
这个时候需要提高文件的权限,采用如下方法:
root@ubuntu:/opt/etcd-v3.3.10# chmod 755 etcd
再次启动etcd
root@ubuntu:/opt/etcd-v3.3.10# ./etcd
成功后可以看见以下提示:
2018-11-11 15:46:43.134431 I | etcdmain: etcd Version: 3.3.10 2018-11-11 15:46:43.134941 I | etcdmain: Git SHA: 27fc7e2 2018-11-11 15:46:43.135324 I | etcdmain: Go Version: go1.10.4 2018-11-11 15:46:43.135572 I | etcdmain: Go OS/Arch: linux/amd64 2018-11-11 15:46:43.135781 I | etcdmain: setting maximum number of CPUs to 1, total number of available CPUs is1 2018-11-11 15:46:43.136055 W | etcdmain: no data-dir provided, using default data-dir ./default.etcd 2018-11-11 15:46:43.136331 N | etcdmain: the server is already initialized as member before, starting as etcd member... 2018-11-11 15:46:43.136847 I | embed: listening for peers on http://localhost:2380 2018-11-11 15:46:43.137159 I | embed: listening for client requests on localhost:2379 2018-11-11 15:46:43.138055 I | etcdserver: name = default 2018-11-11 15:46:43.138328 I | etcdserver: data dir = default.etcd 2018-11-11 15:46:43.138718 I | etcdserver: member dir = default.etcd/member 2018-11-11 15:46:43.139011 I | etcdserver: heartbeat = 100ms 2018-11-11 15:46:43.139280 I | etcdserver: election = 1000ms 2018-11-11 15:46:43.139545 I | etcdserver: snapshot count = 100000 2018-11-11 15:46:43.139839 I | etcdserver: advertise client URLs = http://localhost:2379 2018-11-11 15:46:43.141035 I | etcdserver: restarting member 8e9e05c52164694d in cluster cdf818194e3a8c32 at commit index 46 2018-11-11 15:46:43.141923 I | raft: 8e9e05c52164694d became follower at term 2 2018-11-11 15:46:43.142228 I | raft: newRaft 8e9e05c52164694d [peers: [], term: 2, commit: 46, applied: 0, lastindex: 46, lastterm: 2] 2018-11-11 15:46:43.143985 W | auth: simple token is not cryptographically signed 2018-11-11 15:46:43.145713 I | etcdserver: starting server... [version: 3.3.10, cluster version: to_be_decided] 2018-11-11 15:46:43.148015 I | etcdserver/membership: added member 8e9e05c52164694d [http://localhost:2380] to cluster cdf818194e3a8c32 2018-11-11 15:46:43.149041 N | etcdserver/membership: set the initial cluster version to 3.3 2018-11-11 15:46:43.149478 I | etcdserver/api: enabled capabilities for version 3.3 2018-11-11 15:46:45.043137 I | raft: 8e9e05c52164694d is starting a new election at term 2 2018-11-11 15:46:45.043461 I | raft: 8e9e05c52164694d became candidate at term 3 2018-11-11 15:46:45.043495 I | raft: 8e9e05c52164694d received MsgVoteResp from 8e9e05c52164694d at term 3 2018-11-11 15:46:45.043519 I | raft: 8e9e05c52164694d became leader at term 3 2018-11-11 15:46:45.043535 I | raft: raft.node: 8e9e05c52164694d elected leader 8e9e05c52164694d at term 3 2018-11-11 15:46:45.044348 I | etcdserver: published {Name:default ClientURLs:[http://localhost:2379]} to cluster cdf818194e3a8c32 2018-11-11 15:46:45.044593 E | etcdmain: forgot to set Type=notify in systemd service file? 2018-11-11 15:46:45.044737 I | embed: ready to serve client requests 2018-11-11 15:46:45.045232 N | embed: serving insecure client requests on 127.0.0.1:2379, this is strongly discouraged!
从上面的输出中,我们可以看到很多信息。以下是几个比较重要的信息:
2018-11-11 15:46:43.138055 I | etcdserver: name = default
name表示节点名称,默认为default。
2018-11-11 15:46:43.138328 I | etcdserver: data dir = default.etcd
data-dir 保存日志和快照的目录,默认为当前工作目录default.etcd/目录下。
2018-11-11 15:46:43.148015 I | etcdserver/membership: added member 8e9e05c52164694d [http://localhost:2380] to cluster cdf818194e3a8c32
在http://localhost:2380和集群中其他节点通信。
2018-11-11 15:46:43.139839 I | etcdserver: advertise client URLs = http://localhost:2379
在http://localhost:2379提供HTTP API服务,供客户端交互。
2018-11-11 15:46:43.139011 I | etcdserver: heartbeat = 100ms
heartbeat为100ms,该参数的作用是leader多久发送一次心跳到followers,默认值是100ms。
2018-11-11 15:46:43.139280 I | etcdserver: election = 1000ms
election为1000ms,该参数的作用是重新投票的超时时间,如果follow在该时间间隔没有收到心跳包,会触发重新投票,默认为1000ms。
2018-11-11 15:46:43.139545 I | etcdserver: snapshot count = 100000
snapshot count为10000,该参数的作用是指定有多少事务被提交时,触发截取快照保存到磁盘。
集群和每个节点都会生成一个uuid。
启动的时候会运行raft,选举出leader。
采用这种方式启动的etcd只是一个程序,如果启动etcd的窗口被关闭的话则etcd便会被关闭
,所以如果要长期使用的话最好是为etcd开启一个服务,此处便不提供开启服务的方法,如果有需要读者可以自行百度。
打开另一个窗口输入:
root@ubuntu:/opt/etcd-v3.3.10# ./etcd -version etcd Version: 3.3.10 Git SHA: 27fc7e2 Go Version: go1.10.4 Go OS/Arch: linux/amd64
九、使用etcd
etcdctl客户端
etcd厂商为我们提供提供了一个命令行客户端—etcdctl,供用户直接跟etcd服务打交道,而无需基于 HTTP API方式。可以方便我们在对服务进行测试或者手动修改数据库内容。
etcdctl支持的命令大体上分为数据库操作和非数据库操作两类。
可以使用 ./etcdctl -h 查看etcdctl的用法:
root@ubuntu:/opt/etcd-v3.3.10# ./etcdctl -h
CRUD
注意:etcd的数据库操作围绕对键值和目录的CRUD完整生命周期的管理。
etcd在键的组织上采用了层次化的空间结构(类似于文件系统中目录的概念),用户指定的键可以为单独的名字,如:testkey,此时实际上放在根目录/下面,也可以为指定目录结构,如/cluster1/node2/testkey,则将创建相应的目录结构。
set
指定某个键的值
语法:
-ttl '0' 该键值的超时时间(单位为秒),不配置(默认为0)则永不超时 –swap-with-value value 若该键现在的值是value,则进行设置操作 –swap-with-index '0' 若该键现在的索引值是指定索引,则进行设置操作
例如:
root@ubuntu:/opt/etcd-v3.3.10# ./etcdctl set --ttl '5' key "Hello world" Hello world root@ubuntu:/opt/etcd-v3.3.10# ./etcdctl get key Hello world # 等待几秒,再执行 root@ubuntu:/opt/etcd-v3.3.10# ./etcdctl get key Error: 100: Key not found (/key) [8]
第一个get是5秒内的操作,第二get是5秒后的操作,此刻key的值已经消失了。
update
对指定键进行修改
语法:
–ttl '0' 超时时间(单位为秒),不配置(默认为 0)则永不超时。
举例:
# 先设置一个5秒的值 root@ubuntu:/opt/etcd-v3.3.10# ./etcdctl set --ttl '5' key "Hello world" Hello world # 再修改值 root@ubuntu:/opt/etcd-v3.3.10# ./etcdctl update key "Hello world2" Hello world2 # 等待10秒,再次执行 root@ubuntu:/opt/etcd-v3.3.10# ./etcdctl get key Hello world2
可以发现,即使10秒,也可以get到。说明ttl和value同时更新了!
rm
删除某个键值。
语法:
–dir 如果键是个空目录或者键值对则删除 –recursive 删除目录和所有子键 –with-value 检查现有的值是否匹配 –with-index ‘0’检查现有的index是否匹配
举例:
# 删除 root@ubuntu:/opt/etcd-v3.3.10# ./etcdctl rm key PrevNode.Value: Hello world2 # 再次获取 root@ubuntu:/opt/etcd-v3.3.10# ./etcdctl rm key Error: 100: Key not found (/key) [11]
mk
如果给定的键不存在,则创建一个新的键值。
语法:
–ttl '0' 超时时间(单位为秒),不配置(默认为 0)。则永不超时
举例:
root@ubuntu:/opt/etcd-v3.3.10# ./etcdctl mk /test/key "Hello world" Hello world
当键存在的时候,执行该命令会报错,例如:
root@ubuntu:/opt/etcd-v3.3.10# ./etcdctl mk /test/key "Hello world" Error: 105: Key already exists (/test/key) [33]
mkdir
如果给定的键目录不存在,则创建一个新的键目录。
语法:
–ttl '0' 超时时间(单位为秒),不配置(默认为0)则永不超时。
举例:
root@ubuntu:/opt/etcd-v3.3.10# ./etcdctl mkdir dir2
当键目录存在的时候,执行该命令会报错,例如:
root@ubuntu:/opt/etcd-v3.3.10# ./etcdctl mkdir dir2 Error: 105: Key already exists (/dir2) [13]
setdir
创建一个键目录。如果目录不存在就创建,如果目录存在更新目录TTL。
语法:
–ttl '0' 超时时间(单位为秒),不配置(默认为0)则永不超时。
举例:
root@ubuntu:/opt/etcd-v3.3.10# ./etcdctl setdir dir3
如果重复执行,会报错
root@ubuntu:/opt/etcd-v3.3.10# ./etcdctl setdir dir3 Error: 102: Not a file (/dir3) [34]
updatedir
更新一个已经存在的目录。
语法:
–ttl '0' 超时时间(单位为秒),不配置(默认为0)则永不超时。
举例:
root@ubuntu:/opt/etcd-v3.3.10# ./etcdctl updatedir dir2
如果重复执行,不会报错!
rmdir
删除一个空目录,或者键值对
root@ubuntu:/opt/etcd-v3.3.10# ./etcdctl rmdir dir2
如果重复执行,会报错
root@ubuntu:/opt/etcd-v3.3.10# ./etcdctl rmdir dir2 Error: 100: Key not found (/dir2) [36]
若目录不空会报错,例如:
root@ubuntu:/opt/etcd-v3.3.10# ./etcdctl set /dir/key hi hi root@ubuntu:/opt/etcd-v3.3.10# ./etcdctl rmdir /dir Error: 108: Directory not empty (/dir) [37]
ls
列出目录(默认为根目录)下的键或者子目录,默认不显示子目录中内容。
语法:
–sort 将输出结果排序 –recursive 如果目录下有子目录,则递归输出其中的内容 -p 对于输出为目录,在最后添加/进行区分
例如:
root@ubuntu:/opt/etcd-v3.3.10# ./etcdctl ls /test /dir2 /dir3
如果有值,则输出,否则不输出!
root@ubuntu:/opt/etcd-v3.3.10# ./etcdctl ls test /test/key
非数据库操作
非数据库操作包括:备份、监测、节点管理等
backup
备份etcd的数据。
语法:
–data-dir etcd的数据目录 –backup-dir 备份到指定路径
例如:
root@ubuntu:/opt/etcd-v3.3.10# ./etcdctl backup --data-dir default.etcd --backup-dir /xx/xx 2018-11-11 16:43:34.119969 I | failed creating backup snapshot dir /xx/xx/member/snap: expected "/xx/xx/member/snap" to be empty, got ["db"]
提示 /xx/xx 目录不存在!
那换一个存在的目录,比如/opt/backup。注意:bakcup这个目录可以不用创建,它会自动创建!
root@ubuntu:/opt/etcd-v3.3.10# ./etcdctl backup --data-dir default.etcd --backup-dir /opt/backup 2018-11-11 16:44:44.845409 I | ignoring EntryConfChange raft entry 2018-11-11 16:44:44.845901 I | ignoring member attribute update on /0/members/8e9e05c52164694d/attributes 2018-11-11 16:44:44.846307 I | ignoring member attribute update on /0/members/8e9e05c52164694d/attributes
查看备份目录/opt/backup/
root@ubuntu:/opt/etcd-v3.3.10# ll /opt/backup/ total 12 drwx------ 3 root root 4096 Nov 11 16:44 ./ drwxr-xr-x 4 root root 4096 Nov 11 16:44 ../ drwx------ 4 root root 4096 Nov 11 16:44 member/
watch
监测一个键值的变化,一旦键值发生更新,就会输出最新的值并退出。
exec-watch
监测一个键值的变化,一旦键值发生更新,就执行给定命令。
关于 watch 和 exec-watch,请参考链接:
https://blog.csdn.net/mnasd/article/details/79621155
我没有做出来,主要是因为,开起新的窗口之后,get key无法获取到值
设置一个新的值
./etcdctl set key "Hello world"
执行报错:
Error: unknown command "set" for "etcdctl" Did you mean this? get put del user Run 'etcdctl --help' for usage. Error: unknown command "set" for "etcdctl" Did you mean this? get put del user
原来的窗口是可以执行的,但是新的窗口一直报错,各种无赖ing...
member
list 列出etcd实例
add 添加etcd实例
remove 删除etcd实例
查看集群中存在的节点,例如:
root@ubuntu:/opt/etcd-v3.3.10# ./etcdctl member list 1d64cbbe0759c8f8: name=ubuntu peerURLs=http://192.168.75.129:2380 clientURLs=http://192.168.75.129:2379 isLeader=true
删除集群中存在的节点,例如:
root@ubuntu:/opt/etcd-v3.3.10# ./etcdctl member remove 1d64cbbe0759c8f8 Received an error trying to remove member 1d64cbbe0759c8f8: client: etcd cluster is unavailable or misconfigured; error #0: client: etcd member http://192.168.75.129:2379 has no leader
提示报错,集群中没有leader
向集群中新加节点,例如:
root@ubuntu:/opt/etcd-v3.3.10# ./etcdctl member add etcd3 http://192.168.75.129:2380 Added member named etcd3 with ID 6c40942fac2f358f to cluster ETCD_NAME="etcd3" ETCD_INITIAL_CLUSTER="etcd3=http://192.168.75.129:2380,default=http://localhost:2380" ETCD_INITIAL_CLUSTER_STATE="existing"
针对以上配置参数做些解释:
ETCD_NAME :ETCD的节点名,在集群中应该保持唯一,可以使用 hostname。 ETCD_DATA_DIR:ETCD的数据存储目录,服务运行数据保存的路径,默认为 ${name}.etcd。 ETCD_SNAPSHOT_COUNTER:多少次的事务提交将触发一次快照,指定有多少事务(transaction)被提交时,触发截取快照保存到磁盘。 ETCD_HEARTBEAT_INTERVAL:ETCD节点之间心跳传输的间隔,单位毫秒,leader 多久发送一次心跳到 followers。默认值是 100ms。 ETCD_ELECTION_TIMEOUT:该节点参与选举的最大超时时间,单位毫秒,重新投票的超时时间,如果 follow 在该时间间隔没有收到心跳包,会触发重新投票,默认为 1000 ms。 ETCD_LISTEN_PEER_URLS:该节点与其他节点通信时所监听的地址列表,多个地址使用逗号隔开,其格式可以划分为scheme://IP:PORT,这里的scheme可以是http、https。和同伴通信的地址,比如 http://ip:2380 ,如果有多个,使用逗号分隔。需要所有节点都能够访问,所以不要使用 localhost。 ETCD_LISTEN_CLIENT_URLS:该节点与客户端通信时监听的地址列表,对外提供服务的地址:比如 http://ip:2379 ,http://127.0.0.1:2379 ,客户端会连接到这里和 etcd 交互 ETCD_INITIAL_ADVERTISE_PEER_URLS:该成员节点在整个集群中的通信地址列表,这个地址用来传输集群数据的地址。因此这个地址必须是可以连接集群中所有的成员的。该节点同伴监听地址,这个值会告诉集群中其他节点。 ETCD_INITIAL_CLUSTER:配置集群内部所有成员地址,其格式为:ETCD_NAME=ETCD_INITIAL_ADVERTISE_PEER_URLS,如果有多个使用逗号隔开,集群中所有节点的信息,格式为 node1=http://ip1:2380 ,node2=http://ip2:2380 ,…。注意:这里的 node1 是节点的 –name 指定的名字;后面的 ip1:2380 是 –initial-advertise-peer-urls 指定的值 ETCD_ADVERTISE_CLIENT_URLS:广播给集群中其他成员自己的客户端地址列表 ETCD_INITIAL_CLUSTER_STATE:新建集群的时候,这个值为new;假如已经存在的集群,这个值为 existing。 ETCD_INITIAL_CLUSTER_TOKEN:初始化集群token,创建集群的token,这个值每个集群保持唯一。这样的话,如果你要重新创建集群,即使配置和之前一样,也会再次生成新的集群和节点 uuid;否则会导致多个集群之间的冲突,造成未知的错误。
注意:所有ETCD_MY_FLAG的配置参数也可以通过命令行参数进行设置,但是命令行指定的参数优先级更高,同时存在时会覆盖环境变量对应的值。
api接口
关于etcd api接口,请参考链接:
https://www.cnblogs.com/doscho/p/6227351.html
以上内容,本文参考链接:
https://www.cnblogs.com/softidea/p/6517959.html
https://blog.csdn.net/mnasd/article/details/79621155
十、一键安装脚本
说明:本脚本,只能在本地服务器安装。请确保etcd-v3.3.10-linux-amd64.tar.gz文件和shell脚本在同一目录下。
脚本附带了使用systemctl命令启动etcd服务
etcd_v3.3.10.sh
请仔细阅读开头部分的注意事项
#/bin/bash # 单击版etcd安装脚本 # 本脚本,只能在本地服务器安装。 # 请确保etcd-v3.3.10-linux-amd64.tar.gz文件和当前脚本在同一目录下。 # 务必使用root用户执行此脚本! # 确保可以直接执行python3,因为倒数第4行,有一个json格式化输出。如果不需要可以忽略 #set -e # 输入本机ip while true do echo '请输入本机ip' echo 'Example: 192.168.0.1' echo -e "etcd server ip=c" read ETCD_Server if [ "$ETCD_Server" == "" ];then echo 'No input etcd server IP' else #echo 'No input etcd server IP' break fi done # etcd启动服务 cat > /lib/systemd/system/etcd.service <<EOF [Unit] Description=etcd - highly-available key value store Documentation=https://github.com/coreos/etcd Documentation=man:etcd After=network.target Wants=network-online.target [Service] Environment=DAEMON_ARGS= Environment=ETCD_NAME=%H Environment=ETCD_DATA_DIR=/var/lib/etcd/default EnvironmentFile=-/etc/default/%p Type=notify User=etcd PermissionsStartOnly=true #ExecStart=/bin/sh -c "GOMAXPROCS=$(nproc) /usr/bin/etcd $DAEMON_ARGS" ExecStart=/usr/bin/etcd $DAEMON_ARGS Restart=on-abnormal #RestartSec=10s #LimitNOFILE=65536 [Install] WantedBy=multi-user.target Alias=etcd3.service EOF # 主机名 name=`hostname` # etcd的http连接地址 initial_cluster="http://$ETCD_Server:2380" # 判断进程是否启动 A=`ps -ef|grep /usr/bin/etcd|grep -v grep|wc -l` if [ $A -ne 0 ];then # 杀掉进程 killall etcd fi # 删除etcd相关文件 rm -rf /var/lib/etcd/* rm -rf /etc/default/etcd # 设置时区 ln -snf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime # 判断压缩文件 if [ ! -f "etcd-v3.3.10-linux-amd64.tar.gz" ];then echo "当前目录etcd-v3.3.10-linux-amd64.tar.gz文件不存在" exit fi # 安装etcd tar zxf etcd-v3.3.10-linux-amd64.tar.gz -C /tmp/ cp -f /tmp/etcd-v3.3.10-linux-amd64/etcd /usr/bin/ cp -f /tmp/etcd-v3.3.10-linux-amd64/etcdctl /usr/bin/ # etcd配置文件 cat > /etc/default/etcd <<EOF ETCD_NAME=$name ETCD_DATA_DIR="/var/lib/etcd/" ETCD_LISTEN_PEER_URLS="http://$ETCD_Server:2380" ETCD_LISTEN_CLIENT_URLS="http://$ETCD_Server:2379,http://127.0.0.1:4001" ETCD_INITIAL_ADVERTISE_PEER_URLS="http://$ETCD_Server:2380" ETCD_INITIAL_CLUSTER="$ETCD_Servernitial_cluster" ETCD_INITIAL_CLUSTER_STATE="new" ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster-sdn" ETCD_ADVERTISE_CLIENT_URLS="http://$ETCD_Server:2379" EOF # 临时脚本,添加用户和组 cat > /tmp/foruser <<EOF #!/bin/bash if [ \`cat /etc/group|grep etcd|wc -l\` -eq 0 ];then groupadd -g 217 etcd;fi if [ \`cat /etc/passwd|grep etcd|wc -l\` -eq 0 ];then mkdir -p /var/lib/etcd && useradd -g 217 -u 111 etcd -d /var/lib/etcd/ -s /bin/false;fi if [ \`cat /etc/profile|grep ETCDCTL_API|wc -l\` -eq 0 ];then bash -c "echo 'export ETCDCTL_API=3' >> /etc/profile" && bash -c "source /etc/profile";fi EOF # 执行脚本 bash /tmp/foruser # 启动服务 systemctl daemon-reload systemctl enable etcd.service chown -R etcd:etcd /var/lib/etcd systemctl restart etcd.service #netstat -anpt | grep 2379 # 查看版本 etcdctl -v # 访问API, -s 去掉curl的统计信息. python3 -m json.tool 表示json格式化 curl $initial_cluster/version -s | python3 -m json.tool # 删除临时文件 rm -rf /tmp/foruser /tmp/etcd-v3.3.10-linux-amd64
执行脚本,输出:
请输入本机ip Example: 192.168.0.1 etcd server ip=192.168.75.129 etcdctl version: 3.3.10 API version: 2 { "etcdserver": "3.3.10", "etcdcluster": "3.3.0" }
如果需要清空etcd的值,使用以下命令
rm -rf /var/lib/etcd/member/*
重启etcd
service etcd restart
查看etcd的所有的值,其中 --endpoints 用来指定etcd服务器地址
etcdctl get / --prefix --keys-only --endpoints=192.168.0.88:2379