最近在折腾服务发现这个功能,偶然发现了consul,发现国内资料很少(包括etcd),看了官方文档后,发现很厉害啊,consul是一个用来配置服务发现的工具,consul是分布式的、高可用、横向扩展的。consul提供的一些关键特性:
service discovery:consul通过DNS或者HTTP接口使服务注册和服务发现变的很容易,一些外部服务,例如saas提供的也可以一样注册。
health checking:健康检测使consul可以快速的告警在集群中的操作。和服务发现的集成,可以防止服务转发到故障的服务上面。
key/value storage:一个用来存储动态配置的系统。提供简单的HTTP接口,可以在任何地方操作。
multi-datacenter:无需复杂的配置,即可支持任意数量的区域。
下面初步的讲解一下consul的特性:
1 install consul
我的机器是ubuntu14.04系统,先下载consul软件包,consul官网已经有编译好的二进制包,支持各种平台:win、linux等等,下载符合你平台的软件包:在这里,下载包:0.4.1_linux_amd64.zip。解压完毕后只有一个consul文件。
2 run agent
consul安装完毕后,agent就可以启动了,agent可以运行在server或者client模式,每个数据中心至少有一个agent运行在server模式,一般建议是3或者5个server。部署单个server是非常不好的,因为在失败场景中出现数据丢失是不可避免的。本文涵盖的是创建一个新的数据中心,所有其他的agents都运行在client模式,这是一个非常轻量级的服务注册进程,它会运行健康监测,并将查询结果转发到服务。agent必须运行在集群中的每一个节点上。
我们先运行一个agent在server模式:
./consul agent -server -bootstrap-expect 1 -data-dir /tmp/consul
![](http://static.oschina.net/uploads/space/2014/1206/115408_W3Qq_123777.png)
正如你看到的一样,consul agent已经启动了,并且打印了一些日志到终端上,从日志中可以看到我们的agent已经运行在server模式了,并且已经是整个集群的领导节点。而且,本地成员已经被标记为集群中的健康成员了。这时候你在另一个终端中运行consul members就可以看到整个集群中的成员了。这时候你只能看到你自己,因为我们的集群中还没加入其他成员。
输出已经显示了你自己的节点信息,有地址信息、健康状况、在集群中的角色、以及一些版本信息,如果要查看一些metadata,则可以加入-detailed标记
consul members命令输出的信息是基于gossip协议产生的,并且最终一致的。也可以使用HTTP API来查看整个集群的强一致性视图信息。
除了使用HTTP API接口可以查看集群的视图信息外,也可以使用DNS接口来查看,要在你的节点名称后面加上node.consul字符串。
停止agent服务,在第一个终端中,你可以使用ctrl-c来优雅的停止agent,如果你停止的是client,当你优雅的离开后,consul会通知集群中的其他成员你这个节点以及处于left状态。如果你是强制killed掉agent,集群中的其他成员会认为你是failed了。当成员leaves后,该成员的services和checks会从catalog被移除,当成员fails后,该成员的健康状态会被简单的标记为critical,但是不会从catalog删除。consul会自动的尝试链接failed的节点,这样允许节点在某些网络状况中恢复,如果节点是left状态,则不会再联系该节点。
3 service
前面两节我们启动了第一个agent,并查看了集群中的成员,利用HTTP API查询了一些节点信息,在这一节,我们会注册我们的第一个服务,并查询该服务。
服务定义:一个服务可以通过提供服务定义配置文件或者通过调用HTTP API来注册。我们先通过配置服务定义配置文件来注册新服务,这是最普通的服务注册方法,首先为consul创建一个配置文件目录,按照linux的风格,一般建立在/etc/consul.d目录下,consul会加载在该目录下的所有文件(以json结尾),接着我们定义一个服务定义配置文件,我们这个要注册的服务是提供web服务的,运行在80端口,会给该服务打一些tag,因此这个配置文件就命名为web.json。配置完成后,我们再次重新启动agent,并在命令行提供配置文件目录。
mkdir /etc/consul.d
echo '{"service": {"name": "web", "tags": ["rails"], "port": 80}}' >/etc/consul.d/web.json
./consul agent -server -bootstrap-expect 1 -data-dir /tmp/consul -config-dir /etc/consul.d
你会注意到输出的日志中,最后有一行显示已经synced service web了,这表示已经从配置文件中加载了相关信息。如果你想注册多个服务,则可以创建多个配置文件。
服务查询:一旦agent启动后,并且服务已经同步,我们就可以使用DNS或者HTTP API来进行查询了。我们首先使用DNS来查询,在使用DNS查询时,services的名称是name.service.consul,所有的DNS names都在consul空间下面(consul空间是可以修改的),service关键字是告诉consul我们在查询services,name则是service的名称,我们的web服务注册后,我们则可以使用下面的名称进行查询:web.service.consul
你可以看到一个A记录,记录了服务可达的ip地址,A记录只能显示ip地址,你也可以使用DNS API来检索ip/port,只需要添加SRV记录即可:
SRV记录的返回结果说明web服务运行在Docker-3.node.dc1.consul节点的80端口上面,另外,我们也可是使用DNS API过滤出只符合tag标记的sevice,可以在dns查询时使用如下格式:tag.name.service.consul,tag则是你想过滤的tag。
下面我们使用HTTP API接口来查询一下服务:
curl -s http://localhost:8500/v1/catalog/service/web | python -m json.tool
服务升级:服务定义的升级可以通过先修改服务定义配置文件,然后给agent发送一个SIGHUP信号即可,这样允许你在升级服务时,而不会产生agent宕机时间或者服务不可达。或者通过HTTP API接口来动态的增加、删除、修改服务。
4 consul cluster
现在我们已经启动了第一个agent,注册了第一个服务,并用API接口做了一些查询,这已经显示了consul的易用性,但是我们还不知道要怎么横向扩展consul,在这一节我们创建一个多成员的集群。当你启动一个consul agent的时候,agent一开始并不知道其他节点,agent是集群中一个孤立的点,为了知道集群中的其他成员,agent必须加入一个集群中,加入一个集群后,agent会很快知道该集群中的其他成员,一个agent可以加入其他agent,它也不必运行在server模式。为了模拟真实的集群,我使用三台ubuntu14.04构建一个consul集群,机器信息如下:
192.168.1.100 Docker-1 server
192.168.1.101 Docker-2 client
192.168.1.102 Docker-3 client
我门先在第一台机器上启动agent,以server模式运行,并且指定一个node名称,一般以主机名为node名称,这个名称要唯一。我们同时提供要监听的地址,server的这个地址对于集群中的其他agent必须是可达的,下面我们启动:
./consul agent -server -bootstrap-expect 1 -data-dir /tmp/consul -node=Docker-1 -bind=192.168.1.100
![](http://static.oschina.net/uploads/space/2014/1206/143430_DzEa_123777.png)
在100上的server模式的agent启动后,我们来到101上启动我们的第二个agent,这个agent绑定101节点的ip地址。下面我们启动101上的节点,
./consul agent -data-dir /tmp/consul -node=Docker-2 -bind=192.168.1.101
101上的节点启动后,可以看到101在报错,之前说过一个集群中至少要有一个server agent,101启动的时候没有设置server模式,这时候就相当于101在它自己的集群中,但是该集群中没有server,只有一个client,我们有两个agent在运行,一个server模式,一个client模式,但是这两个节点彼此都互不知道,它们都运行在自己的集群中,你可以通过consul members来查看,我们下面就要把101的client加入到server的集群中。在100的server上面,通知101的agent加入server集群。这时候应该在agent的输出log上看到一些信息,这时候再执行consul members就会看到整个集群的成员了。
先看101的agent增加了哪些日志
可以看到该agent加入Docker-1的集群中了,Docker-1是集群的leader,再看看Docker-1的agent有哪些日志输出
agent Docker-2加入进来了,并标记Docker-2的状态为alive。
有个快捷的方法,在agent启动时就可以直接加入集群,在consul agent启动的时候使用-join参数,即可把agent加入集群中,我们就用这个方法把Docker-3直接加入Docker-1的集群中。
./consul agent -data-dir /tmp/consul -node=Docker-3 -join=192.168.1.100 -bind=192.168.1.102
![](http://static.oschina.net/uploads/space/2014/1206/144614_uOXd_123777.png)
再来看看集群中的成员,已经加入了Docker-3
而且集群中的成员都收到了Docker-3加入的信息,我们看看DOcker-2的agent打印出的log信息
节点查询,就像service查询一样,consul也提供DNS和HTTP API接口来查询节点,对于DNS查询,你可以使用name.node.consul或者name.datacenter.node.consul来查询,如果datacenter被省略,则默认查询本地datacenter。
离开集群,就像前面的方法一样,使用ctrl-c来离开集群,或者强制killed掉agent,当然这两种方法的优劣前面已经讲过了。
5 health check
现在我们已经知道怎么运行consul、增加节点和服务、查询节点和服务、以及创建集群,这一节我们增加节点和服务间的健康监测,这是服务发现的重要组成部分,因为它要阻止访问不健康的服务。
检测定义:就像服务定义一样,我们可以通过检测定义配置文件或者HTTP API接口来定义检测。我们定义检测配置就像配置服务定义一样,我们在Docker-2节点的consul配置目录增加两个配置文件,一个配置文件是host层面的检测,一个是server层面的检测。
host检测,每30s检测一次
echo '{"check": {"name": "ping", "script": "ping -c1 www.baidu.com >/dev/null", "interval": "30s"}}' >/etc/consul.d/ping.json
server检测,每10秒中检测一次。已经在Docker-2启动了apache服务
echo '{"service": {"name": "web", "tags": ["rails"], "port": 80,
"check": {"script": "curl localhost:80 >/dev/null 2>&1", "interval": "10s"}}}' >/etc/consul.d/web.json
然后重启agent或者给当前的agent进程发送一个SIGHUP信号(kill -s SIGHUP agent_pid),因为我们在启动agent的时候并没有添加-config-dir标记,所以agent并不知道consul的配置文件目录在哪里,所以我们要ctrl-c来重启agent,并添加配置文件目录
./consul agent -data-dir /tmp/consul -join=Docker-1 -node=Docker-2 -bind=192.168.1.101 -config-dir=/etc/consul.d
![](http://static.oschina.net/uploads/space/2014/1206/151732_JhQ7_123777.png)
检查健康状态,我们已经添加了一些健康检测的机制,现在我们可以使用HTTP API来检测了,我们先查看所有的检测。
curl -s http://localhost:8500/v1/health/state/any | python -m json.tool
![](http://static.oschina.net/uploads/space/2014/1206/152721_vNCk_123777.png)
也可以使用DNS接口来查询。
6 K/V data
上面章节我们已经实现了服务发现和健康检测,consul也提供了一个简单的K/V存储系统,这可以用来动态获取配置、进行服务协调、主节点选举,其他开发人员能想到的build过程等等。
为了演示怎么操作K/V系统,我们将会操作少量数据。我们在Docker-2节点上进行测试,首先要检测K/V系统中是否已经有key存在。
curl -v http://127.0.0.1:8500/v1/kv/?recurse
![](http://static.oschina.net/uploads/space/2014/1206/155420_xOUJ_123777.png)
可以看到目前K/V系统中并没有key,我们http返回的是404状态码,现在我们put一些数据进去:
curl -X PUT -d 'test' http://127.0.0.1:8500/v1/kv/web/key1
curl -X PUT -d 'test' http://127.0.0.1:8500/v1/kv/web/key2?flags=42
curl -X PUT -d 'test' http://127.0.0.1:8500/v1/kv/web/web/sub/key3
开始查看K/V系统中的key
curl -s http://127.0.0.1:8500/v1/kv/?recurse|python -m json.tool
![](http://static.oschina.net/uploads/space/2014/1206/160803_8nyz_123777.png)
我们创建了三个key,每个key的value都是test,在K/V系统中值都是base64加密过的,我们给'web/key2'这个key添加了一个tag,所有的key支持64bit的整形长度,在插入完毕后,可以用?recurse来查看所有的key,你也可以只查看单个key
curl -s http://127.0.0.1:8500/v1/kv/web/key1|python -m json.tool
![](http://static.oschina.net/uploads/space/2014/1206/161525_C5qs_123777.png)
删除key也是很容易的,我们可以指定全路径来删除单个key,也可以使用?recurse来删除所有key。
curl -s http://127.0.0.1:8500/v1/kv/web/key1|python -m json.tool
![](http://static.oschina.net/uploads/space/2014/1206/162031_uFP8_123777.png)
可以通过给一个key赋予新值来进行update,另外,consul会执行一个Check-And-Set的操作,确保更新操作的原子性。这可以通过提供?cas=参数来实现,cas的值是ModifyIndex的值。
curl -X PUT -d 'newval' http://127.0.0.1:8500/v1/kv/web/key1?cas=106
curl -X PUT -d 'newval' http://127.0.0.1:8500/v1/kv/web/key1?cas=106
curl -s http://127.0.0.1:8500/v1/kv/web/key1|python -m json.tool
![](http://static.oschina.net/uploads/space/2014/1206/163210_8J8H_123777.png)
在上面的情况可以看到,第一次CAS update成功了,因为上一次修改的时间是106,但是第二次CAS的操作失败了,因为ModifyIndex的大小小于106,。
7 WEB UI
consul同样也支持web界面,这个ui可以用来查看所有的服务和节点,所有的健康检测和它们当前的状态,读取设置K/V系统的值。ui默认自动支持多datacenter。这些ui是静态html和jsp文件,你不需要单独运行一个web服务器,consul agent本身可以配置一个web服务。我们在Docker-3上配置该UI服务。
下载UI组件:WEB UI
下载完成后是一个0.4.1_web_ui.zip压缩文件,解压后是一个dist目录。先ctrl-c掉Docker-3上的agent,然后添加-ui-dir参数和-client参数重新启动agent。
./consul agent -data-dir /tmp/consul -node=Docker-3 -join=192.168.1.100 -bind=192.168.1.102 -ui-dir=/opt/dist -client=192.168.1.102
![](http://static.oschina.net/uploads/space/2014/1206/165120_rbyn_123777.png)
在浏览器中输入http://192.168.1.102:8500,即可访问UI了
看着很不错,有services、nodes、K/V、acl、datacenter的管理,看起来比etcd好一些。