21

Consul Service Discovery实践 | 大栗子菜市场

 2 years ago
source link: https://lidawn.github.io/2019/12/12/consul-service-discovery/?
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Consul Service Discovery实践

Posted on 2019-12-12

| 0

| Visitors: 472

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系统结构

上图是Consul的系统架构,每个数据中心构建一个consul server集群,通过raft协议选举出leader,并保持数据一致性。Server之间通过gossip协议进行通信和数据同步。为了保证可靠性和性能,server数量为3到5台。Client主要负责本地服务的健康检查,向server注册服务,转发查询,数量可以任意拓展。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"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.

1
./consul agent -config-dir=config/ -client=0.0.0.0

启动之后可以看到service中有三个consul实例。

UI

2.2 服务注册、健康检查、发现

(1)服务注册

Consul的服务注册通过client模式的agent进行。在service所在机器上启动client agent,加入到server集群中,该agent的存活状态是service的默认健康状态。

配置consul_client.json,启动client agent。

1
2
3
4
5
6
7
8
9
{
"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"
}



1
./consul agent -config-dir=config/

service通过配置文件的形式定义,这里定义一个名为collector的服务,设置id,name,address,port

service.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"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已经注册上来。

collector 默认状态

(2)健康检查

service中通过脚本做健康检查,可以添加任意的健康条件,示例中设置了三种状态检查,心跳、机器内存、服务负载。

service.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
{
"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

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/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处于不可用状态。

collector健康状况

启动service后,三项健康检查通过后,service处于可用状态。

collector健康状况

(3)服务发现

服务发现可通过HTTP API或者DNS的形式获取。

1
2
3
GET /v1/health/node/:node
GET /v1/health/checks/:service
GET /v1/health/service/:service

HTTP API

DNS

2.3 KV存储

1
2
3
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"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。

1
./consul acl bootstrap -http-addr="http://10.0.0.1:8081"

将得到的bootstrap token写到server配置文件acl_master_token字段中,重新启动server。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"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,获得管理员权限

UI

(2) agent token

在开启了deny的策略后,agent之间通信也需要token。首先增加agent之间的访问策略,配置写权限,然后为该策略生成对应的token。

配置agent策略


应用token到agent策略


将token写到server配置文件acl_agent_token字段中,重新启动三个server agent。该token也需要配置在各个client agent中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
"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

1
2
3
service "collector" {
policy = "write"
}

在collector的描述文件中加入service token

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"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应用在该策略上。

1
2
3
4
5
6
7
node_prefix "" {
policy = "read"
}

key_prefix "" {
policy = "read"
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK