Consul是HashiCorp出品的开源服务发现工具。也有人用etcd或者ZooKeeper做类似的事情,它们之间的区别可以看官方文档的对比Consul vs. ZooKeeper, doozerd, etcd
Consul提供了诸如服务发现,健康检查,KV数据库等功能,方便你使用它构建自己的服务集群。
基础概念
- Agent: agent就是实际运行的consul服务,启动时可选以server或者client模式运行,每个集群至少有1个server,由于使用了Raft算法,所以对于每个集群你应该把它的server数设置成3或5个。
- Server: 核心的consul服务,存储了所有服务注册的信息,响应查询操作,跨数据中心通信等。
- Client: 用来在集群中每个机器上运行,进行服务注册/健康检查的进程。
- Cluster: 集群,由多台共同提供服务的机器组成的集合称为集群,agent在集群的每个成员上都要运行。
- DataCenter: 数据中心。consul支持跨数据中心组成集群。
- Node: 安装了agent,接入集群的机器称为node。
- Service: 你的服务,即服务注册和服务发现之类操作的对象。通过提供config文件或者调用consul的HTTP API来定义一个服务。
使用
因为这玩意是用Go写的,所以你只要下个二进制就能跑了。从 https://www.consul.io/downloads.html 下载对应平台的二进制程序安装即可。
或者更加政治正确一些,可以使用docker容器
docker pull consul:latest
默认端口
consul默认使用下列端口
- 8300(tcp): Server RPC,server用于接受其他agent的请求
- 8301(tcp,udp): Serf LAN,数据中心内gossip交换数据用
- 8302(tcp,udp): Serf WAN,跨数据中心gossip交换数据用
- 8400(tcp): CLI RPC,接受命令行的RPC调用
- 8500(tcp): HTTP API及Web UI
- 8600(tcp udp): DNS服务,可以把它配置到53端口来响应dns请求
部署集群
以容器化部署为例。具体可参考docker hub上的文档
主要以下几点需要注意:
- 如果你没有丰富的网络知识,那么建议所有agent以容器化部署时,网络模式设置为host模式
- 容器内的
/consul/data
路径应挂个volume进去,以持久化agent状态 - consul配置在
/consul/config
路径下,也可以通过环境变量CONSUL_LOCAL_CONFIG
写一个配置的JSON字符串来修改配置 - 几台机器的host不能相同,否则无法组成集群
安装server
这个启动命令基本上是从官方文档上抄的,用命令参数进行配置显得并不十分优雅,最好还是弄个config文件。详细的配置参数见文档Configuration
$ docker run -d --net=host -e 'CONSUL_LOCAL_CONFIG={"skip_leave_on_interrupt": true}' consul agent -server -bind=<external ip> -retry-join=<root agent ip> -bootstrap-expect=<number of server agents> -data-dir=/consul/data -node=<node_name> -client=<client ip> -ui
安装client
$ docker run -d --net=host -e 'CONSUL_LOCAL_CONFIG={"skip_leave_on_interrupt": true}' consul agent -bind=<external ip> -retry-join=<root agent ip> -data-dir=/consul/data -node=<node_name> -client=<client interface ip> -client=<client ip> -ui
参数说明
- -bind: agent绑定到哪个ip(用于集群内部通讯),默认是0.0.0.0,为了安全最好设为内网ip
- -retry-join: server与集群失联后重新加入集群时请求的ip
- -bootstrap-expect: 集群server数量
- -data-dir: 数据目录的位置
- -client: 作为client提供服务时的ip
- -ui: 启动web ui
使用
更详细请参考官方API文档 这里只列几个我用到的。可以通过调用client的HTTP API来操作consul,也可以通过封装好的SDK,如python-consul。
列出所有节点
curl -X GET \
http://consul.rocks/v1/catelog/nodes
列出所有服务
curl -X GET \
http://consul.rocks/v1/catelog/services
列出服务的实例
curl -X GET \
http://consul.rocks/v1/catelog/service/<service-name>
注册服务
注册一个redis服务,并设置了每10秒钟一次的http健康检查
curl -X PUT \
http://192.168.5.36:8500/v1/agent/service/register \
-d '{
"ID": "my-redis",
"Name": "redis",
"Tags": [
"primary",
"v1"
],
"Address": "127.0.0.1",
"Port": 6379,
"Meta": {
"redis_version": "4.0"
},
"EnableTagOverride": false,
"Check": {
"DeregisterCriticalServiceAfter": "90m",
"HTTP": "http://localhost:5000/health",
"Interval": "10s"
}
}'
注销服务
curl -X PUT \
https://consul.rocks/v1/agent/service/deregister/<service-id>
Web UI
访问任意server的8500端口即可打开Web UI,界面还算精美,但功能比较简陋,可以查看集群内node和service的情况,设置ACL Token,增删改查KV数据库等,但无法对node和service进行进一步修改或删除操作。
Registrator
容器化部署最麻烦的一点是,在容器里的服务对自己所处的环境知之甚少,很难提供有效的信息(如地址端口等)用来进行服务注册,因此需要有上帝视角的外部工具来完成这项任务。Registrator就是这样的工具,它可以用于向etcd, consul, SkyDNS 2中注册服务。具体使用方式参考文档。
docker run -d \
--name=registrator \
--net=host \
--volume=/var/run/docker.sock:/tmp/docker.sock \
gliderlabs/registrator:latest \
consul://<client ip>:8500
服务注册
它会把当前机器启动的容器自动注册到consul里面去。Registrator注册的服务id是按照如下格式生成的
host:container_name:port
例如一台host为ubuntu的机器上的某个redis服务id可能就是
ubuntu:my_redis:6379
对于同一个容器暴露的不同端口,会分别注册服务。
健康检查
在需要进行健康检查的容器增加如下label或者环境变量,即可启动健康检查,其中80
要改成服务的端口
SERVICE_80_CHECK_HTTP=/health/endpoint/path
SERVICE_80_CHECK_INTERVAL=15s
SERVICE_80_CHECK_TIMEOUT=1s # optional, Consul default used otherwise
所以最终部署出来这一坨的东西基本上长成这个样子
找3台机器分别安装server,组成高可用consul集群,在需要服务注册的节点(node)上安装client和registrator。registrator读取docker的信息发送到当前节点的client进行服务注册。client负责将请求转发至server完成实际的注册工作。健康检查由client进行检查并上报到server。