您的位置:首页 > 其它

consul简介

2016-06-26 18:20 761 查看
摘要: 简单记录了一下consul的基础用法。

产品环境的部署可以借鉴这篇文章: https://www.digitalocean.com/community/tutorials/how-to-configure-consul-in-a-production-environment-on-ubuntu-14-04

consul简介

这篇文档简单介绍一下consul这款软件的功能以及原理。

注: 本篇博客主要介绍简单的功能使用,在本地环境快速搭建起运行环境。如果要在产品环境部署,请参考这篇文章: https://www.digitalocean.com/community/tutorials/how-to-configure-consul-in-a-production-environment-on-ubuntu-14-04

HashiCorp的CTO在infoq上有一个分享,ppt在此(需爬墙): http://www.slideshare.net/InfoQ/consul-serviceoriented-at-scale 。极具参考价值。介绍了consul的用例,以及设计思想等等,强烈推荐一阅。看过这篇ppt以及下面的访谈记录,再看consul的文档就十分清晰了

consul是什么

consul是HashiCorp公司推出的一款开源工具,用于实现分布式系统的服务发现与配置。与其他类似产品相比,提供更“一站式”的解决方案。consul内置有KV存储,服务注册/发现,健康检查,HTTP+DNS API,Web UI等多种功能。

HashiCorp官方公布的一张consul的架构图如下:



consul的优势

使用 Raft 算法来保证一致性, 比复杂的 Paxos 算法更直接. 相比较而言, zookeeper 采用的是 Paxos, 而 etcd 使用的则是 Raft.

支持多数据中心,内外网的服务采用不同的端口进行监听。 多数据中心集群可以避免单数据中心的单点故障,而其部署则需要考虑网络延迟, 分片等情况等. zookeeper 和 etcd 均不提供多数据中心功能的支持.

支持健康检查. etcd 不提供此功能.

支持 http 和 dns 协议接口. zookeeper 的集成较为复杂, etcd 只支持 http 协议.

官方提供web管理界面, etcd 无此功能.

与其他同类型的产品详细对比,官方有一个比较详尽的文档: https://www.consul.io/intro/vs/zookeeper.html

简单来说,相比zookeeper,consul要更轻量,依赖轻(Go VS Java),Raft算法要比Paxos算法简单的多,而且效率高。

相比etcd,提供了更多的功能,比如DNS server,多数据中心同步,WebUI等等。

consul的简单使用

consul的使用非常简单,采用Go语言编写,编译出的文件无其他依赖。因此只需要从官方下载编译好的二进制可执行程序直接运行就可以了。

# consul
usage: consul [--version] [--help] <command> [<args>]

Available commands are:
agent          Runs a Consul agent
configtest     Validate config file
event          Fire a new event
exec           Executes a command on Consul nodes
force-leave    Forces a member of the cluster to enter the "left" state
info           Provides debugging information for operators
join           Tell Consul agent to join cluster
keygen         Generates a new encryption ke
7fe0
y
keyring        Manages gossip layer encryption keys
leave          Gracefully leaves the Consul cluster and shuts down
lock           Execute a command holding a lock
maint          Controls node or service maintenance mode
members        Lists the members of a Consul cluster
monitor        Stream logs from a Consul agent
reload         Triggers the agent to reload configuration files
rtt            Estimates network round trip time between nodes
version        Prints the Consul version
watch          Watch for changes in Consul

consul的运行方式

consul以
agent
形式运行。agent有两种模式:
server
client


server的作用是提供一致性的保证,存储着Raft信息。几乎可以认为server是数据存储中心,绝大多数的运行数据都保存在server。每个数据中心至少要保证一个server节点。官方建议每个数据中心保持3,5或7个server节点,以保证高可用。以server方式运行:

consul agent -server -data-dir /tmp/consul

client就比server轻量的多,基本上只提供和server交互的接口,作为访问server的代理。以client方式运行:

# 去掉-server参数就是client模式,并且要join到一个cluster中。
# 也可以使用consul join命令手工加入到一个集群中
consul agent -data-dir /tmp/consul -join X.X.X.X

以下功能演示均需要有server节点,因此使用以下命令启动server:

consul agent -server -ui -bootstrap -client=0.0.0.0 -data-dir /tmp/consul

加上
-ui
参数可以启用内置的WebUI,使用浏览器访问
http://localhost:8500
即可打开这个WebUI。

服务注册

服务需要先进行注册,才能实现健康检查,服务发现等这些功能。

服务注册的方法有两种,一种是写到配置文件中,启动时加载。另一种是在consul启动之后通过HTTP API动态添加。

服务注册的方法相当简单,写一个json配置文件,定义服务名即可,以定义一个
rtds
服务为例:

{
"service": {
"name": "rtds"
}
}

保存为
rtds.json
,然后重启consul并加载这个配置文件:

consul agent -server -ui -bootstrap -client=0.0.0.0 -data-dir /tmp/consul -config-file rtds.json

打开webui(8500端口)就可以看到这个service了。也可以通过HTTP API列出这个service:

$ curl 172.16.250.11:8500/v1/agent/services?pretty
{
"consul": {
"ID": "consul",
"Service": "consul",
"Tags": [],
"Address": "",
"Port": 8300,
"EnableTagOverride": false,
"CreateIndex": 0,
"ModifyIndex": 0
},
"rtds": {
"ID": "rtds",
"Service": "rtds",
"Tags": null,
"Address": "",
"Port": 0,
"EnableTagOverride": false,
"CreateIndex": 0,
"ModifyIndex": 0
}
}

服务动态注册的方式,向HTTP API发起PUT请求注册新服务,body部分和json配置文件格式一致:

$ curl 172.16.250.11:8500/v1/agent/services?pretty
{
"consul": {
"ID": "consul",
"Service": "consul",
"Tags": [],
"Address": "",
"Port": 8300,
"EnableTagOverride": false,
"CreateIndex": 0,
"ModifyIndex": 0
}
}

$ curl -XPUT -d '{"name":"rtds"}' 172.16.250.11:8500/v1/agent/service/register
$ curl 172.16.250.11:8500/v1/agent/services?pretty { "consul": { "ID": "consul", "Service": "consul", "Tags": [], "Address": "", "Port": 8300, "EnableTagOverride": false, "CreateIndex": 0, "ModifyIndex": 0 }, "rtds": { "ID": "rtds", "Service": "rtds", "Tags": null, "Address": "", "Port": 0, "EnableTagOverride": false, "CreateIndex": 0, "ModifyIndex": 0 } }

服务发现

consul对服务发现提供两种接口: HTTP API和DNS查询。

先看下HTTP API。列出已注册的服务GET请求
/v1/catalog/services
即可列出。追加
?dc=<dc_name>
可以列出指定数据中心的注册服务。
用GET请求
/v1/catalog/service/<service_name>
即可列出注册此服务的全部节点信息,同样可以追加
?dc=
参数:

$ curl 172.16.250.11:8500/v1/catalog/service/rtds?pretty
[
{
"Node": "shifudaotest",
"Address": "172.16.250.11",
"ServiceID": "rtds",
"ServiceName": "rtds",
"ServiceTags": [],
"ServiceAddress": "",
"ServicePort": 0,
"ServiceEnableTagOverride": false,
"CreateIndex": 276,
"ModifyIndex": 277
}
]

DNS API: consul会占用一个DNS服务器端口
8600
,提供DNS查询服务。每一个注册的服务,会在consul提供一条
NAME.service.consul
的解析记录。用DNS查询工具就可以进行查询:

$ dig @172.16.250.11 -p 8600 rtds.service.consul        # 使用dig工具查询rtds.service.consul解析记录

; <<>> DiG 9.9.5-3ubuntu0.8-Ubuntu <<>> @172.16.250.11 -p 8600 rtds.service.consul
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 20558
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; WARNING: recursion requested but not available

;; QUESTION SECTION:
;rtds.service.consul.		IN	A

;; ANSWER SECTION:
rtds.service.consul.	0	IN	A	172.16.250.11

;; Query time: 47 msec
;; SERVER: 172.16.250.11#8600(172.16.250.11)
;; WHEN: Fri May 06 20:13:58 CST 2016
;; MSG SIZE  rcvd: 72

可以看到rtds.service.consul有一条A记录,指向172.16.250.11。

现在把rtds服务注销掉。可以看到
rtds.service.consul
已经没有任何解析记录了。

$ curl 172.16.250.11:8500/v1/agent/service/deregister/rtds  # 将rtds服务注销
$ dig @172.16.250.11 -p 8600 rtds.service.consul

; <<>> DiG 9.9.5-3ubuntu0.8-Ubuntu <<>> @172.16.250.11 -p 8600 rtds.service.consul
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 62263
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0
;; WARNING: recursion requested but not available

;; QUESTION SECTION:
;rtds.service.consul.		IN	A

;; AUTHORITY SECTION:
consul.			0	IN	SOA	ns.consul. postmaster.consul. 1462537218 3600 600 86400 0

;; Query time: 5 msec
;; SERVER: 172.16.250.11#8600(172.16.250.11)
;; WHEN: Fri May 06 20:21:05 CST 2016
;; MSG SIZE  rcvd: 105

健康检查

consul对注册的服务都支持健康检查。方法是在
service
下面再嵌套一个
check
配置即可。

{
"service": {
"name": "service_name",
"check": {

}
}
}

consul支持5种check方式:

Script + Interval: 周期性运行某个可执行程序,根据程序退出码确定服务是否存活

HTTP + Interval: 周期性访问某个http地址,根据返回码是否为2xx确定服务是否存活。429将警告

TCP + Interval: 周期性发起TCP请求,根据是否成功建立连接TCP连接确定服务是否存活

Time to Live (TTL): 类似于心跳检测。服务状态是用过周期性向HTTP接口发起PUT请求确定的。超期没有更新数据就判断服务挂了

Docker + Interval: 通过docker的api检测docker内服务的状态

如果某个服务需要检测多项,可以使用
checks
配置:

{
"checks": [
{
"id": "chk1",
"name": "mem",
"script": "/bin/check_mem",
"interval": "5s"
},
{
"id": "chk2",
"name": "/health",
"http": "http://localhost:5000/health",
"interval": "15s"
},
{
"id": "chk3",
"name": "cpu",
"script": "/bin/check_cpu",
"interval": "10s"
},
...
]
}

比如rtds会监听TCP
3130
端口,我们通过周期检测3130端口的存活性判断rtds的存活,继续修改
rtds.json
如下:

{
"service": {
"name": "rtds",
"check": {
"name": "rtds TCP on port 3130",
"tcp": "localhost:3130",
"interval": "10s",
"timeout": "1s"
}
}
}

使用以下命令重启consul,加载
rtds.json
配置:

consul agent -server -ui -bootstrap -client=0.0.0.0 -data-dir /tmp/consul -config-file rtds.json

也可以像服务注册那样,不使用配置文件,启动之后通过HTTP API添加服务与健康检测策略。操作方法完全一样,这里不做演示。

rtds未启动时:

$ curl 172.16.250.11:8500/v1/health/checks/rtds?pretty
[
{
"Node": "shifudaotest",
"CheckID": "service:rtds",
"Name": "Service 'rtds' check",
"Status": "critical",  # 服务未启动,所以状态显示此服务挂了
"Notes": "",
"Output": "",
"ServiceID": "rtds",
"ServiceName": "rtds",
"CreateIndex": 444,
"ModifyIndex": 462
}
]

$ nslookup -port=8600 rtds.service.consul 172.16.250.11  # nslookup也是一个dns测试工具
Server:		172.16.250.11
Address:	172.16.250.11#8600

# 服务挂了,所以没有rtds.service.consul的解析记录

启动rtds,等上10秒(配置的检测周期为10秒):

$ curl 172.16.250.11:8500/v1/health/checks/rtds?pretty
[
{
"Node": "shifudaotest",
"CheckID": "service:rtds",
"Name": "Service 'rtds' check",
"Status": "passing",    # 3130端口可以成功建立TCP连接,于是passing了
"Notes": "",
"Output": "TCP connect localhost:3130: Success",
"ServiceID": "rtds",
"ServiceName": "rtds",
"CreateIndex": 444,
"ModifyIndex": 499
}
]

$ nslookup -port=8600 rtds.service.consul 172.16.250.11
Server:		172.16.250.11
Address:	172.16.250.11#8600

Name:	rtds.service.consul
Address: 172.16.250.11

KV存储

这个功能就没太多要说明的了,基本用法就跟redis的用法差不多。

KV的API路径是
/v1/kv/<key>
,支持
GET
,
PUT
,
DELETE
三种请求。如果
key
最后跟一个
/
,代表创建一级目录。

$ curl -X PUT -d 'test' http://localhost:8500/v1/kv/web/key1 true
$ curl -X PUT -d 'test' http://localhost:8500/v1/kv/web/key2?flags=42 true
$ curl -X PUT -d 'test'  http://localhost:8500/v1/kv/web/sub/key3 true
$ curl http://localhost:8500/v1/kv/?recurse [{"CreateIndex":97,"ModifyIndex":97,"Key":"web/key1","Flags":0,"Value":"dGVzdA=="},
{"CreateIndex":98,"ModifyIndex":98,"Key":"web/key2","Flags":42,"Value":"dGVzdA=="},
{"CreateIndex":99,"ModifyIndex":99,"Key":"web/sub/key3","Flags":0,"Value":"dGVzdA=="}]

需要注意的consul返回的value是
base64
编码,官方的解释是为了防止出现非UTF-8字符,所以统一编码成base64。第二个范例追加了一个
flags
参数,这个
flags
并非是由consul内部使用,而是提供给客户端的保留字段,客户端可以自定义其他含义。
如果追加
?raw
参数,将直接返回未经base64编码的
Value
值。

此外,consul的KV存储还支持
Check-And-Set
操作(当
ModifyIndex
匹配时才进行修改键值)。详情参考官方文档: https://www.consul.io/intro/getting-started/kv.html

ACL

consul提供访问控制列表(Access Control List)功能,通过ACL可以实现权限控制。consul的ACL是Capability-based security(能力基础安全)。

也就是这种ACL是每一级路径都可以而配置单独权限,默认策略是子权限继承父权限。比如
/kv/key/
的权限是
deny
,那么
/kv/key/sub1
这样的路径无法访问。如果再追加一条规则
/kv/key/sub2
的权限是
read
,那么
/kv/key/sub2/key
这样的key有只读权限,其余的key均无法访问。通过带上
?token=
参数验证ACL权限,ACL配置是针对每个token的。如果不带
token
参数,则默认
anonymous


启用ACL只能在配置文件中指定。创建一个
config.json
文件,写入以下内容:

{
"acl_datacenter": "dc1",
"acl_default_policy": "deny",
"acl_master_token": "master"
}

dc1
这个数据中心(默认的数据中心)启动ACL,默认的ACL规则是
deny
(即不指定权限时,默认为deny),拥有管理权限的token是
master


加载这个配置启动consul agent:

consul agent -server -ui -bootstrap -client=0.0.0.0 -data-dir /tmp/consul -config-file config.json

现在再请求
kv
,发现会返回404:

curl -v '172.16.250.11:8500/v1/kv/?recurse'  # -v参数可以看到返回码是404

带上master token再请求这个API,就没问题:

$ curl '172.16.250.11:8500/v1/kv/?token=master&recurse'
[{"LockIndex":0,"Key":"web/key1","Flags":0,"Value":"bW9kaWZpZWQ=","CreateIndex":633,"ModifyIndex":634}]

现在创建一个token
mytoken
,对
kv/web/
有只读权限,对
service/rtds
有读写权限,可以这么做:

$ curl -XPUT -d @- '172.16.250.11:8500/v1/acl/create?token=master' <<EOF
{
"Type": "client",
"Name": "mytoken",
"Rules": "service \"rtds\" {\n policy = \"write\"\n }\n key \"web/\" {\n policy = \"read\"\n }"
}
EOF
{"ID":"1f8799ce-6f45-427c-f8e6-3878f9eda582"}

consul会返回一个
ID
:
1f8799ce-6f45-427c-f8e6-3878f9eda582
。将这个值作为
token
参数传递给HTTP API就拥有了对应的权限。

$ curl '172.16.250.11:8500/v1/kv/?recurse&token=1f8799ce-6f45-427c-f8e6-3878f9eda582&pretty'
[
{
"LockIndex": 0,
"Key": "web/key1",
"Flags": 0,
"Value": "bW9kaWZpZWQ=",
"CreateIndex": 633,
"ModifyIndex": 634
}
]

可以看到带上这个token以后,就可以读取
web/key1
的值了,而之前是404。

其他功能

以上几个功能都是WebUI上可以可视化操作的功能,是最常见的功能。其他还有一些只能用API操作的功能。比如
consul exec
直接调用
RPC
接口,而非
HTTP
接口。
consul event
向消息总线发送自定义消息。
consul watch
监听消息总线异步响应,甚至还支持分布式锁等等。这些功能可以详细参考官方文档,用到的时候再查阅官方文档。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  consul