Consul Service Discovery实践
Consul 是什么? 官方给出的答案是:
Consul is a service mesh solution providing a full featured control plane with service discovery, configuration, and segmentation functionality.
即提供服务发现,配置中心以及安全加密通信服务的Service Mesh解决方案。包含关键特性:
服务发现:Consul client注册服务,通过DNS或HTTP接口的形式访问Consul,获取服务列表;
健康检查:agent通过自定义的脚本检查service的健康,十分灵活,可以配合后端做负载均衡;
KV存储:多级的kv存储;
加密认证通信:service之间的通信经过TLS加密并认证,intentions机制可以实时控制service之间通信权限;
多数据中心:支持多数据中心
Consul 1.2版本之后 增加了connect特性,将agent拓展为sidecar,实现了一套Service Mesh的解决方案,本文未涉及到这一部分,只涉及Service Discovery部分。
2 Service Discovery 实践
2.1 Server Cluster 部署
Consul Agent以client或者server模式运行,每个数据中心配置一个server集群,包含至少一个server agent。我们选择部署三台机器 10.0.0.1
, 10.0.0.2
, 10.0.0.3
{ "datacenter" : "test_dc", "node_name" : "node1", "bind_addr": "10.0.0.1", "retry_join" : ["10.0.0.1","10.0.0.2","10.0.0.3"], "data_dir" : "data/", "server" : true, "bootstrap_expect" : 3, "log_level": "INFO", "ui": true, "ports":{ "http":8081 } }
配置文件中 node_name
为统一的前缀,方便后续acl策略控制, retry_join
设置为集群的server地址。在三台机器上分别启动server agent.
./consul agent -config-dir=config/ -client=0.0.0.0
启动之后可以看到service中有三个consul实例。
2.2 服务注册、健康检查、发现
(1)服务注册
Consul的服务注册通过client模式的agent进行。在service所在机器上启动client agent,加入到server集群中,该agent的存活状态是service的默认健康状态。
配置 consul_client.json
,启动client agent。
{ "datacenter" : "test_dc", "node_name" : "node4", "retry_join" : ["10.0.0.1","10.0.0.2","10.0.0.3"], "bind_addr" : "10.0.0.4", "data_dir" : "data/", "enable_script_checks": true, "log_level": "INFO" }
./consul agent -config-dir=config/
service通过配置文件的形式定义,这里定义一个名为 collector
的服务,设置 id
, name
, address
, port
。
service.json
{ "service": { "id": "collector", "name": "collector", "tags": ["public"], "address": "10.0.0.4", "meta": { "meta": "test meta" }, "port": 2203, "weights": { "passing": 1, "warning": 1 } } }
执行 reload
操作,此时UI可以看到service已经注册上来。
(2)健康检查
service中通过脚本做健康检查,可以添加任意的健康条件,示例中设置了三种状态检查,心跳、机器内存、服务负载。
service.json
{ "service": { "id": "collector", "name": "collector", "tags": ["public"], "address": "10.0.0.4", "meta": { "meta": "test meta" }, "port": 2203, "checks": [ { "args": ["scripts/check_status.sh", "10000", "95", "1000"], "interval": "5s" }, { "args": ["scripts/check_node.sh", "1"], "interval": "5s" }, { "args": ["scripts/check_heartbeat.sh"], "interval": "5s" } ], "weights": { "passing": 1, "warning": 1 } } }
check_heartbeat.sh
#!/bin/sh CODE=0 echo "check hearbeat" ret=`curl -sSL http://localhost:12125/heartbeat` echo $ret if [ "$ret" = "ok" ] then CODE=0 else CODE=-1 fi echo "exit code" $CODE exit $CODE
在上面配置了service之后,由于service未启动,健康检查不通过,service处于不可用状态。
启动service后,三项健康检查通过后,service处于可用状态。
(3)服务发现
服务发现可通过HTTP API或者DNS的形式获取。
GET /v1/health/node/:node GET /v1/health/checks/:service GET /v1/health/service/:service
2.3 KV存储
GET /v1/kv/:key PUT /v1/kv/:key DELETE /v1/kv/:key
2.4 ACL
Consul提供丰富的权限控制,用以控制数据访问,以及API读写权限。ACL的核心概念有policy和token,policy配置具体数据的读写权限,token则是应用于policy上,使用指定的token来执行对应的policy。
(1)bootstrap token
bootstrap token为管理员token,拥有最高权限,不要轻易将该token应用给某个policy。
开启ACL首先需要更改server配置文件,设置默认为 deny
{ "datacenter" : "test_dc", "node_name" : "node1", "bind_addr": "10.0.0.1", "data_dir" : "data/", "server" : true, "bootstrap_expect" : 1, "log_level": "INFO", "ui": true, "acl" : { "enabled" : true, "default_policy" : "deny", "enable_token_persistence" : true }, "ports":{ "http":8081 } }
启动其中一台server,在初始启动之后,生成bootstrap token。
./consul acl bootstrap -http-addr="http://10.0.0.1:8081"
将得到的bootstrap token写到server配置文件 acl_master_token
字段中,重新启动server。
{ "datacenter" : "test_dc", "node_name" : "node1", "bind_addr": "10.0.0.1", "retry_join" : ["10.0.0.1","10.0.0.2","10.0.0.3"], "acl_master_token" : "xxxxxxx-xxxxxx-xxxx-xxxx-xxxxxxxxx", "data_dir" : "data/", "server" : true, "bootstrap_expect" : 3, "log_level": "INFO", "ui": true, "acl" : { "enabled" : true, "default_policy" : "deny", "enable_token_persistence" : true }, "ports":{ "http":8081 } }
UI中输入该bootstrap token,获得管理员权限
(2) agent token
在开启了deny的策略后,agent之间通信也需要token。首先增加agent之间的访问策略,配置写权限,然后为该策略生成对应的token。
将token写到server配置文件 acl_agent_token
字段中,重新启动三个server agent。该token也需要配置在各个client agent中。
{ "datacenter" : "test_dc", "node_name" : "node1", "bind_addr": "10.0.0.1", "retry_join" : ["10.0.0.1","10.0.0.2","10.0.0.3"], "acl_agent_token" : "xxxxxxx-xxxxxx-xxxx-xxxx-xxxxxxxxx", "acl_master_token" : "xxxxxxx-xxxxxx-xxxx-xxxx-xxxxxxxxx", "data_dir" : "data/", "server" : true, "bootstrap_expect" : 3, "log_level": "INFO", "ui": true, "acl" : { "enabled" : true, "default_policy" : "deny", "enable_token_persistence" : true }, "ports":{ "http":8081 } }
(3)service token
service token用于client agent注册服务。如需要注册 collector
,则为collector分配写权限和token
service "collector" { policy = "write" }
在collector的描述文件中加入service token
{ "service": { "id": "collector", "name": "collector", "tags": ["public"], "address": "10.0.0.4", "token":"xxxxxxx-xxxxxx-xxxx-xxxx-xxxxxxxxx", "meta": { "meta": "test meta" }, "port": 2203, "enable_tag_override": false, "weights": { "passing": 1, "warning": 1 } } }
(4)anonymous token
配置ACL后,命令行和http请求访问均需要带上对应的token才能访问对应的数据,但某些场景下我们可能不方便保管token,这时可以使用anonymous token开放某些权限。
匿名token是系统的内置不设防的令牌。比如,我们将kv的读权限开放,便可以使用匿名token。首先配置kv策略(注意还需要开放node读权限),然后将匿名token应用在该策略上。
node_prefix "" { policy = "read" } key_prefix "" { policy = "read" }
参考
- Introduction to Consul – https://www.consul.io/intro/index.html
- HashiCorp Consul 1.2: Service Mesh – https://www.hashicorp.com/blog/consul-1-2-service-mesh/
- Secure Consul with ACLs – https://learn.hashicorp.com/consul/security-networking/production-acls