一、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 架构图
拆解开这个体系,从每一个组件开始了解。首先,可以看到有两个数据中心,分别标记为“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@docker-02 ~]# cd /home/ [root@docker-02 home]# mkdir docker [root@docker-02 home]# cd docker [root@docker-02 docker]# mkdir consul [root@docker-02 docker]# cd consul [root@docker-02 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.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地址
3.2 创建consul-server1节点服务配置文件
3.2.1 进入consul-server1-conf文件夹创建consul-server1.json文件
[root@docker-02 consul]# cd consul-server1-conf/ [root@docker-02 consul-server1-conf]# touch consul-server1.json
3.2.2 vi编辑consul-server1.json配置文件,复制下列代码
[root@docker-02 consul-server1-conf]# cat 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@docker-02 consul-server1-conf]# cd .. [root@docker-02 consul]# cd consul-server2-conf/
3.3.2 vi编辑consul-server2.json配置文件,复制下列代码
[root@docker-02 consul-server2-conf]# cat 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@docker-02 consul-server2-conf]# cd ../consul-server3-conf/ [root@docker-02 consul-server3-conf]# vi consul-server3.json
3.4.2 vi编辑consul-server3.json配置文件,复制下列代码
[root@docker-02 consul-server3-conf]# cat 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@docker-02 consul-server3-conf]# cd ../consul-client-conf/ [root@docker-02 consul-client-conf]# touch consul-client.json
3.4.2 vi编辑consul-client.json配置文件,复制下列代码
[root@docker-02 consul-client-conf]# 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 }
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
[root@docker-02 consul-client-conf]# 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 Unable to find image 'consul:latest' locally latest: Pulling from library/consul e7c96db7181b: Pull complete 06ba64850324: Pull complete e2cfcbd06e76: Pull complete 211aae54ca69: Pull complete 1f22c1b42a0a: Pull complete 028c01a3f1b3: Pull complete Digest: sha256:a167e7222c84687c3e7f392f13b23d9f391cac80b6b839052e58617dab714805 Status: Downloaded newer image for consul:latest a0d30329efbf677e0924ec0a4f6ab79ac0e12187a8fcc91acbff363efd0f840c [root@docker-02 consul-client-conf]# 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 8b95ae0306473272a6e25329067c991c0a3f455121b74f2f189d46363f03b6b5 [root@docker-02 consul-client-conf]# 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 4eb530c9c155b4e361e4a002ccf521dc51baf72ef46a5be15b963e1efec3d420 [root@docker-02 consul-client-conf]# 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 WARNING: Published ports are discarded when using host network mode 6b0180f50dec54f0a83902c8335ddb18d0719b806dd9c42a04bd641885232186