一、Consul简介

Consul 是一套开源的分布式服务发现和配置管理系统,由 HashiCorp 公司用 Go 语言开发。它具有很多优点。包括:基于 raft 协议,比较简洁; 支持健康检查, 同时支持 HTTP 和 DNS 协议 支持跨数据中心的 WAN(广域网) 集群 提供图形界面 跨平台,支持 Linux、Mac、Windows。

consul是使用go语言开发的服务发现、配置管理中心服务。内置了服务注册与发现框 架、分布一致性协议实现、健康检查、Key/Value存储、多数据中心方案,不再需要依赖其他工具(比如ZooKeeper等)。服务部署简单,只有一个可运行的二进制的包。每个节点都需要运行agent,他有两种运行模式server和client。每个数据中心官方建议需要3或5个server节点以保证数据安全,同时保证server-leader的选举能够正确的进行。

@client

CLIENT表示consul的client模式,就是客户端模式。是consul节点的一种模式,这种模式下,所有注册到当前节点的服务会被转发到SERVER,本身是不持久化这些信息。

@server

SERVER表示consul的server模式,表明这个consul是个server,这种模式下,功能和CLIENT都一样,唯一不同的是,它会把所有的信息持久化的本地,这样遇到故障,信息是可以被保留的。

@server-leader

中间那个SERVER下面有LEADER的字眼,表明这个SERVER是它们的老大,它和其它SERVER不一样的一点是,它需要负责同步注册的信息给其它的SERVER,同时也要负责各个节点的健康监测。

@raft(分布式一致性协议)

server节点之间的数据一致性保证,一致性协议使用的是raft,而zookeeper用的paxos,etcd采用的也是raft。

@服务发现协议

consul采用http和dns协议,etcd只支持http

@服务注册

consul支持两种方式实现服务注册,一种是通过consul的服务注册http API,由服务自己调用API实现注册,另一种方式是通过json个是的配置文件实现注册,将需要注册的服务以json格式的配置文件给出。consul官方建议使用第二种方式。

@服务发现

consul支持两种方式实现服务发现,一种是通过http API来查询有哪些服务,另外一种是通过consul agent 自带的DNS(8600端口),域名是以NAME.service.consul的形式给出,NAME即在定义的服务配置文件中,服务的名称。DNS方式可以通过check的方式检查服务。

@服务间的通信协议

Consul使用gossip协议管理成员关系、广播消息到整个集群,他有两个gossip pool(LAN pool和WAN pool),LAN pool是同一个数据中心内部通信的,WAN pool是多个数据中心通信的,LAN pool有多个,WAN pool只有一个。

二、基本概念

在描述架构之前,这里提供了一些术语来帮助声明正在探讨的东西:

  • Agent——agent是一直运行在Consul集群中每个成员上的守护进程。通过运行 consul agent 来启动。agent可以运行在client或者server模式。指定节点作为client或者server是非常简单的,除非有其他agent实例。所有的agent都能运行DNS或者HTTP接口,并负责运行时检查和保持服务同步。
  • Client——一个Client是一个转发所有RPC到server的代理。这个client是相对无状态的。client唯一执行的后台活动是加入LAN gossip池。这有一个最低的资源开销并且仅消耗少量的网络带宽。
  • Server——一个server是一个有一组扩展功能的代理,这些功能包括参与Raft选举,维护集群状态,响应RPC查询,与其他数据中心交互WAN gossip和转发查询给leader或者远程数据中心。
  • DataCenter——虽然数据中心的定义是显而易见的,但是有一些细微的细节必须考虑。例如,在EC2中,多个可用区域被认为组成一个数据中心?我们定义数据中心为一个私有的,低延迟和高带宽的一个网络环境。这不包括访问公共网络,但是对于我们而言,同一个EC2中的多个可用区域可以被认为是一个数据中心的一部分。
  • Consensus——在我们的文档中,我们使用Consensus来表明就leader选举和事务的顺序达成一致。由于这些事务都被应用到有限状态机上,Consensus暗示复制状态机的一致性。
  • Gossip——Consul建立在Serf的基础之上,它提供了一个用于多播目的的完整的gossip协议。Serf提供成员关系,故障检测和事件广播。更多的信息在gossip文档中描述。这足以知道gossip使用基于UDP的随机的点到点通信。
  • LAN Gossip——它包含所有位于同一个局域网或者数据中心的所有节点。
  • WAN Gossip——它只包含Server。这些server主要分布在不同的数据中心并且通常通过因特网或者广域网通信。
  • RPC——远程过程调用。这是一个允许client请求server的请求/响应机制。

Consul Architecture 架构图

image.png

拆解开这个体系,从每一个组件开始了解。首先,可以看到有两个数据中心,分别标记为“one”和“two”。Consul是支持多数据中心一流,并且是常用业务场景。

每个数据中心都是由Server和client组成。建议有3~5 Server——基于故障处理和性能的平衡之策。如果增加越多的机器,则Consensus会越来越慢。对client没有限制,可以很容易地扩展到成千上万或数万。

同一个数据中心的所有节点都要加入Gossip协议。这意味着gossip pool包含给定数据中心的所有节点。有以下目的:首先,没有必要为client配置服务器地址参数;发现是自动完成的。第二,节点故障检测的工作不是放置在服务器上,而是分布式的。这使故障检测比心跳机制更可扩展性。第三,可用来作为消息层通知重要的事件,如leader选举。

每个数据中心的服务器都是属于一个Raft peer。这意味着,他们一起工作,选出一个的Leader,Leader server是有额外的职责。负责处理所有的查询和事务。事务也必须通过Consensus协议复制到所有的伙伴。由于这一要求,当非Leader Server接收到一个RPC请求,会转发到集群的leader。

Server节点也是作为WAN gossip pool的一部分。这个pool是与LAN gossip pool是不同的,它为具有更高延迟的网络响应做了优化,并且可能包括其他consul集群的server节点。设计WANpool的目的是让数据中心能够以low-touch的方式发现彼此。将一个新的数据中心加入现有的WAN Gossip是很容易的。因为池中的所有Server都是可控制的,这也使跨数据中心的要求。当一个Serfer接收到不同的数据中心的要求时,它把这个请求转发给相应数据中心的任一Server。然后,接收到请求的Server可能会转发给Leader。

多个数据中心之间是低耦合,但由于故障检测、连接缓存复用、跨数据中心要求快速和可靠的响应。

三、Docker中创建Consul集群

1 使用docker下载consul镜像,默认下载最consul最新版本,目前版本号为1.4.0,如果需要其他版本请登录https://hub.docker.com/进行搜索
2 下载完毕后分别创建/home/docker/consul、consul-server1-data、consul-server2-data、consul-server3-data、consul-client-data、consul-server1-conf、consul-server2-conf、consul-server3-conf、consul-client-conf这九个文件夹

[root@localhost ~]# cd /home

[root@localhost home]# mkdir docker

[root@localhost home]# cd docker

[root@localhost docker]# mkdir consul

[root@localhost docker]# cd consul

[root@localhost consul]# mkdir consul-server1-data consul-server2-data consul-server3-data  consul-client-data consul-server1-conf consul-server2-conf consul-server3-conf consul-client-conf

3 创建Consul配置文件
3.1 在docker中每个Consul成员都是docker中的一个容器,docker会给每个容器分配容器的IP地址,容器IP地址只能用于容器之间内部通讯不能被宿主机直接访问,每个Consul容器IP同时也是Consul成员的Agentd守护进程的IP地址,创建Consul集群需要其他Consul容器加入同一个Consul容器的Agentd守护进程的IP地址,将该Consul容器作为Consul容器的leader,当该Consul容器挂掉时,Consul集群会从所有Agentd守护进程的IP地址中再选举出一个leader,但当宿主及重启,docker中所有容器的IP地址都会发生变化,Consul集群中的每个成员的IP地址也发生变化,原本是Consul容器的IP地址可能变成了Mysql容器的IP地址,这样每个Consul成员无法自动加入原来Consul容器的Agentd守护进程的IP地址,Consul集群就会报错,解决方案是在所有Consul节点服务的配置文件中,配置参数”retry_join”,将docker中所有容器的IP都作为加入同一个Consul容器的Agentd守护进程的IP地址,任何一个Consul成员的Agent守护进程只需要知道集群中任意一个节点即可,加入到集群之后,集群节点之间会根据GOSSIP协议互相发现彼此的关系
要先统计docker中所有容器已经被使用的IP地址,将没有被使用的空闲的IP地址作为Consul容器Agentd守护进程的IP地址
3.1.1 查询docker中所有容器IP地址

[root@bogon consul-server1-conf]# docker inspect -f '{{.NetworkSettings.IPAddress}}' $(docker ps -q)
172.17.0.2
172.17.0.5



172.17.0.8
172.17.0.7

3.1.2 统计出已经使用的IP地址后,将空闲的172.17.0.6、172.17.0.9、172.17.0.4、172.17.0.3这四个准备使用的IP地址,作为Consul容器的IP地址,并将所有docker容器中所有已经使用的IP地址和准备使用的IP地址写入每个Consul节点服务的配置文件的配置参数”retry_join”中, “retry_join”: [“172.17.0.2″,”172.17.0.3″,”172.17.0.4″,”172.17.0.5″,”172.17.0.6″,”172.17.0.7″,”172.17.0.8″,”172.17.0.9”]
3.2 创建consul-server1节点服务配置文件
3.2.1 进入consul-server1-conf文件夹创建consul-server1.json文件

[root@localhost consul]# cd consul-server1-conf/
[root@localhost consul-server1-conf]# touch consul-server1.json 

3.2.2 vi编辑consul-server1.json配置文件,复制下列代码

{
    "datacenter": "DC1",
    "data_dir": "/consul/data",
    "log_level": "INFO",
    "node_name": "consul-server1",
    "server": true,
    "bootstrap_expect": 1,
    "retry_join": ["172.17.0.2","172.17.0.3","172.17.0.4","172.17.0.5","172.17.0.6","172.17.0.7","172.17.0.8","172.17.0.9"],
    "retry_interval": "3s",
    "enable_debug": false,
    "rejoin_after_leave": true,
    "enable_syslog": false
}

3.3 创建consul-server2节点服务配置文件
3.3.1 进入consul-server2-conf文件夹创建consul-server2.json文件

[root@localhost consul]# cd consul-server2-conf/
[root@localhost consul-server2-conf]# touch consul-server2.json 

3.3.2 vi编辑consul-server2.json配置文件,复制下列代码

{
    "datacenter": "DC1",
    "data_dir": "/consul/data",
    "log_level": "INFO",
    "node_name": "consul-server2",
    "server": true,
    "bootstrap_expect": 2,
    "retry_join": ["172.17.0.2","172.17.0.3","172.17.0.4","172.17.0.5","172.17.0.6","172.17.0.7","172.17.0.8","172.17.0.9"],
    "retry_interval": "3s",
    "enable_debug": false,
    "rejoin_after_leave": true,
    "enable_syslog": false
}

3.4 创建consul-server3节点服务配置文件
3.4.1 进入consul-server3-conf文件夹创建consul-server3.json文件

[root@localhost consul]# cd consul-server3-conf/
[root@localhost consul-server3-conf]# touch consul-server3.json 

3.4.2 vi编辑consul-server3.json配置文件,复制下列代码

{
    "datacenter": "DC1",
    "data_dir": "/consul/data",
    "log_level": "INFO",
    "node_name": "consul-server3",
    "server": true,
    "bootstrap_expect": 2,
    "retry_join": ["172.17.0.2","172.17.0.3","172.17.0.4","172.17.0.5","172.17.0.6","172.17.0.7","172.17.0.8","172.17.0.9"],
    "retry_interval": "3s",
    "enable_debug": false,
    "rejoin_after_leave": true,
    "enable_syslog": false
}

3.4 创建consul-client节点服务配置文件
3.4.1 进入consul-client-conf文件夹创建consul-client.json文件

[root@localhost consul]# cd consul-client-conf/
[root@localhost consul-client-conf]# touch consul-client.json 

3.4.2 vi编辑consul-client.json配置文件,复制下列代码

{
  "datacenter": "DC1",             
  "data_dir": "/consul/data",
  "log_level": "INFO",
  "node_name": "consul-client",
  "server": false,
  "ui": true,
  "bootstrap_expect": 0,
  "bind_addr": "192.168.43.234",
  "client_addr": "192.168.43.234",
  "retry_join": ["172.17.0.2","172.17.0.3","172.17.0.4","172.17.0.5","172.17.0.6","172.17.0.7","172.17.0.8","172.17.0.9"],
  "retry_interval": "3s", 
  "enable_debug": false,
  "rejoin_after_leave": true,
  "enable_syslog": false
}

3.5 配置参数说明
datacenter: 数据中心名称
data_di:ConsulServer模式节点的数据目录
log_level: “INFO”:日志级别
node_name:当前节点名称
server:是否为 Server 模式,true 为 Server 模式,false 为 Client 模式
ui:是否开启 UI 访问
bootstrap_expect:启动时期望的就绪节点,1 代表启动为 bootstrap 模式,等待其他节点加入
bind_addr:绑定的 IP,ConsulServer模式无需指定,ConsulClient模式必须绑定宿主机IP地址,否则报错[Consul]Error starting agent: Failed to get advertise address: Multiple private IPs found.
client_addr:作为 Client 接受请求的绑定 IP地址,该IP地址必须为宿主机IP地址,否则访问宿主机无法访问到Client模式的Consul节点,端口使用了 HTTP: 8500, DNS: 8600
retry_join:尝试加入的其他节点
retry_interval:每次尝试间隔
raft_protocol:Raft 协议版本
enable_debug:是否开启 Debug 模式
rejoin_after_leave:允许重新加入集群
enable_syslog:是否开启 syslog
4 启动三个server模式的consul节点consul-server1、consul-server2、consul-server3,启动一个client模式的consul节点consul-client

docker run -d --name consul-server1 --restart=always -v /home/docker/consul/consul-server1-data:/consul/data -v /home/docker/consul/consul-server1-conf:/consul/config consul agent -data-dir /consul/data -config-dir /consul/config

docker run -d --name consul-server2 --restart=always -v /home/docker/consul/consul-server2-data:/consul/data -v /home/docker/consul/consul-server2-conf:/consul/config consul agent -data-dir /consul/data -config-dir /consul/config

docker run -d --name consul-server3 --restart=always -v /home/docker/consul/consul-server3-data:/consul/data -v /home/docker/consul/consul-server3-conf:/consul/config consul agent -data-dir /consul/data -config-dir /consul/config

docker run -d --net=host --name consul-client --restart=always -p 8400:8400 -p 8500:8500 -p 8600:53/udp -v /home/docker/consul/consul-client-data:/consul/data -v /home/docker/consul/consul-client-conf:/consul/config consul agent  -data-dir /consul/data -config-dir /consul/config

5 查看consul客户端、consul容器是否启动

[root@localhost ~]# docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                                        NAMES
e46bf7bae81d        consul              "docker-entrypoint..."   About an hour ago   Up About an hour                                                                 consul-client
954f366b5a9a        consul              "docker-entrypoint..."   About an hour ago   Up About an hour    8300-8302/tcp, 8500/tcp, 8301-8302/udp, 8600/tcp, 8600/udp   consul-server3
54feb6ee26c4        consul              "docker-entrypoint..."   About an hour ago   Up About an hour    8300-8302/tcp, 8500/tcp, 8301-8302/udp, 8600/tcp, 8600/udp   consul-server2
5beadc6c1bec        consul              "docker-entrypoint..."   About an hour ago   Up About an hour    8300-8302/tcp, 8500/tcp, 8301-8302/udp, 8600/tcp, 8600/udp   consul-server1

6 查看ConsulServer模式、Client模式节点是否启动成功

[root@localhost ~]# docker exec -it consul-server1 /bin/sh
/ # consul members
Node            Address              Status  Type    Build  Protocol  DC   Segment
consul-server1  172.17.0.4:8301      alive   server  1.4.0  2         dc1  <all>
consul-server2  172.17.0.9:8301      alive   server  1.4.0  2         dc1  <all>
consul-server3  172.17.0.6:8301      alive   server  1.4.0  2         dc1  <all>
consul-client   192.168.43.234:8301  alive   client  1.4.0  2         dc1  <default>

7 查看目前全部的consul节点的角色状态

/ # consul operator raft list-peers
Node            ID                                    Address          State     Voter  RaftProtocol
consul-server3  bce5f51e-fada-8a13-7639-e205da35efe6  172.17.0.6:8300  follower  true   3
consul-server2  0b4cbb28-b03a-948f-c4f2-a6e00b6e0d06  172.17.0.9:8300  leader    true   3
consul-server1  952d468c-0391-2f98-4959-f62965401551  172.17.0.4:8300  follower  true   3

8 consult集群容器启动成功,打开浏览器输入http://192.168.43.234:8500,consul默认页面ui端口号8500

image.png

可以看到Node Health为3,则说明consul集群配置成功

9 错误处理

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                     PORTS                                                        NAMES
79032d57a304        consul              "docker-entrypoint..."   3 seconds ago       Exited (1) 2 seconds ago                                                                consul-client
53ef8a6fdb56        consul              "docker-entrypoint..."   11 minutes ago      Up 11 minutes              8300-8302/tcp, 8500/tcp, 8301-8302/udp, 8600/tcp, 8600/udp   consul-server3
d1f7c98d07f5        consul              "docker-entrypoint..."   12 minutes ago      Up 12 minutes              8300-8302/tcp, 8500/tcp, 8301-8302/udp, 8600/tcp, 8600/udp   consul-server2
86e45d805eb8        consul              "docker-entrypoint..."   12 minutes ago      Up 12 minutes              8300-8302/tcp, 8500/tcp, 8301-8302/udp, 8600/tcp, 8600/udp   consul-server1

8.1 如果consul客户端、consul服务端容器是未能正常启动,则查看该consul容器日志

docker logs consulclient

9 命令说明
–net=host:指定 docker网络模式为host模式共享宿主机的网络,若采用默认的bridge模式,则会存在容器跨主机间通信失败的问题
-v /data/consul_data/data:/consul/data:主机的数据目录挂载到容器的/consul/data下,因为该容器默认的数据写入位置即是/consul/data
-v /data/consul_data/conf:/consul/config:主机的配置目录挂载到容器的/consul/conf下,因为该容器默认的数据写入位置即是/consul/conf
consul agent -server:consul的server启动模式
consul agent -client:consul的client启动模式
consul agent -bind=192.168.43.234:consul绑定到主机的ip上
consul agent -bootstrap-expect=3:server要想启动,需要至少3个server
consul agent -data-dir /consul/data:consul的数据目录
consul agent -config-dir /consul/config:consul的配置目录
consul agent -join:加入的consul-server1节点IP地址建立consul集群,启动之后,集群就开始了Vote(投票选Leader)的过程
–net=host docker参数, 使得docker容器越过了netnamespace的隔离,免去手动指定端口映射的步骤
-e或–env 使用-e设置的环境变量,容器内部的进程可以直接拿到
-server consul支持以server或client的模式运行, server是服务发现模块的核心, client主要用于转发请求
-client consul绑定在哪个client地址上,这个地址提供HTTP、DNS、RPC等服务,默认是127.0.0.1,0.0.0.0 表示任何地址可以访问
-node – 群集中此节点的名称。这在群集中必须是唯一的。默认情况下,这是计算机的主机名
-bootstrap-expect 指定consul集群中有多少代理
-retry-join 指定要加入的consul节点地址,失败会重试, 可多次指定不同的地址
-bind 绑定IP地址用来在集群内部的通讯,集群内的所有节点到地址都必须是可达的,默认是0.0.0.0,但当宿主机重启后所有docker容器IP地址会发生变化,-bind 绑定IP作用就会失效,集群无法找到leader报错,如果将集群单独部署在一个宿主机内可以使用
-allow_stale 设置为true, 表明可以从consul集群的任一server节点获取dns信息, false则表明每次请求都会经过consul server leader
–name DOCKER容器的名称
-ui 提供图形化的界面
其他命令请查看consul官方文档:https://www.consul.io/docs/agent/options.html#ports

作者:QIQIHAL
链接:https://www.jianshu.com/p/067154800683
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

发表回复

您的电子邮箱地址不会被公开。