consul简介

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 key
    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有两种模式: serverclient

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监听消息总线异步响应,甚至还支持分布式锁等等。这些功能可以详细参考官方文档,用到的时候再查阅官方文档。

转载于:https://my.oschina.net/abcfy2/blog/675665

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值