基于Docker的Consul集群实现服务发现

 

服务发现
html

其实简单说,服务发现就是解耦服务与IP地址之间的硬绑定关系,
以典型的集群为例,对于集群来讲,是有多个节点的,这些节点对应多个IP(或者同一个IP的不一样端口号),集群中不一样节点责任是不同的。
好比说一个数据集群中,能够分为读节点或者写节点,写节点和读节点都是相对的,不是硬绑定的,某一个逻辑节点,随着故障转移及恢复,是能够变换身份的(写变读,读变写;主降从,从升主等等)
集群对外提供服务的时候,对于外界来讲,集群中节点身份变换的时候须要对外透明,外界无需由于集群节点的身份变换而更改配置,这就须要一个解耦合的服务。
Consul,zookeeper等中间件,就是作这个透明转换的,也就是服务发现。这里简单测试consul做为服务发现的实现。
Consul是一种服务解耦解决方案(service mesh solution,纠结了很久不知道怎么翻译)提供具备服务发现配置和分段功能的全功能控制系统(control plane)
这些功能中的每个均可以根据须要单独使用也能够一块儿使用以构建完整的服务解耦 即使是用了谷歌翻译的状况下,这段翻译纠结了半天,不知道怎么翻译合适。

以下是按照本身对consul作服务发现的理解,简单整理的逻辑结构图,其原理仍是比较容易理解的。
Consul is a service mesh solution providing a full featured control plane with service discovery, configuration, and segmentation functionality. Each of these features can be used individually as needed, or they can be used together to build a full service mesh. Consul requires a data plane and supports both a proxy and native integration model. Consul ships with a simple built-in proxy so that everything works out of the box, but also supports 3rd party proxy integrations such as Envoy. https://www.consul.io/intro/index.html
它提供以下几个关键功能
服务发现
  Consul的某些客户端能够提供一个服务例如api或者mysql其它客户端可使用Consul去发现这个服务的提供者
  使用DNS或者HTTP应用能够很容易的找到他们所依赖的服务
健康检查
  Consul客户端能够提供一些健康检查这些健康检查能够关联到一个指定的服务服务是否返回200 OK),也能够关联到本地节点内存使用率是否在90%如下)。
  这些信息能够被一个操做员用来监控集群的健康状态被服务发现组件路由时用来远离不健康的主机
键值存储 
  应用可使用Consul提供的分层键值存储用于一些目的包括动态配置特征标记协做leader选举等等经过一个简单的HTTP API能够很容易的使用这个组件
多数据中心 
  Consul对多数据中心有很是好的支持这意味着Consul用户没必要担忧因为建立更多抽象层而产生的多个区域
Consul被设计为对DevOps群体和应用开发者友好他很是适合现代的可伸缩的基础设施
 
 
本文基于docker来实现consul的服务发现配置,方法consul agent是经过json注册的模式实现服务注册,
其中consul的服务端是3节点的集群,客户点是6节点3主3从的redis服务器集群,consul实现redis集群中读写服务注册于发现。

尽管Redis cluster有多IP方式驱动链接,这里仅仅为了测试“服务发现”的。
其实原本想测试MySQL单主模式的MGR,实现读写分离的服务发现,可是MySQL有点过重了,机器配置不够,因此作了Redis的集群来测试服务发现
 
 
consul服务端集群安装配置
做为服务发现的载体,consul是可使用单节点运行的,做为解析服务的载体,是一个很是重要的角色,集群化具备更强的抗灾性,所以更多的时候是以多节点集群的方式运行解析服务的这个载体。

这里使用三个节点做为consul的集群服务端来运行,三个consul的服务节点IP分别是:172.18.0.11 ,172.18.0.12,172.18.0.13,须要固定IP
docker network create --subnet=172.18.0.11/16 mynetwork 
docker run -itd --name consul01 --net mynetwork --ip 172.18.0.11 -v /usr/local/docker_file/consul01/:/usr/local/ centos  
docker run -itd --name consul02 --net mynetwork --ip 172.18.0.12 -v /usr/local/docker_file/consul02/:/usr/local/ centos  
docker run -itd --name consul03 --net mynetwork --ip 172.18.0.13 -v /usr/local/docker_file/consul03/:/usr/local/ centos  
分别在每一个容器中建立consul服务(unzip consul_1.6.2_linux_amd64.zip解压缩便可,很是简单)
三个容器节点的server.json节点配置文件以下,惟一的区别就是bind_addr指定为当前节点的IP
以下是172.18.0.11节点的配置,不一样节点仅需修改bind_addr为对应机器(容器)的IP

/usr/local/server.json 
{ "datacenter": "dc1", "data_dir": "/usr/local/", "log_level": "INFO", "server": true, "bootstrap_expect": 3, "bind_addr": "172.18.0.11", "client_addr": "0.0.0.0", "start_join": ["172.18.0.11","172.18.0.12","172.18.0.13"], "ui":true }
依次登陆三个容器中,以server模式启动consul服务
./consul agent -server -config-dir=/usr/local > /usr/local/consul.log &
因为配置文件中制定了集群的IP列表,所以无需显式加入集群(cluster join),正常状况下,启动三个节点后,会自动组成一个集群,而且自动选举出来一个leader。
consul 集群服务的状态
./consul members --http-addr 172.18.0.11:8500
./consul operator raft list-peers -http-addr=172.18.0.12:8500


consul客户端安装配置
容器客户端节点安装,6个节点IP分别是:172.18.0.21,172.18.0.22,172.18.0.23,172.18.0.24,172.18.0.25,172.18.0.26
docker run -itd --name redis01 --net mynetwork --ip 172.18.0.21 -v /usr/local/docker_file/redis01/:/usr/local/ centos 
docker run -itd --name redis02 --net mynetwork --ip 172.18.0.22 -v /usr/local/docker_file/redis02/:/usr/local/ centos 
docker run -itd --name redis03 --net mynetwork --ip 172.18.0.23 -v /usr/local/docker_file/redis03/:/usr/local/ centos 
docker run -itd --name redis04 --net mynetwork --ip 172.18.0.24 -v /usr/local/docker_file/redis04/:/usr/local/ centos 
docker run -itd --name redis05 --net mynetwork --ip 172.18.0.25 -v /usr/local/docker_file/redis05/:/usr/local/ centos 
docker run -itd --name redis06 --net mynetwork --ip 172.18.0.26 -v /usr/local/docker_file/redis06/:/usr/local/ centos
 
6个client节点的配置以及服务定义,服务探测脚本以下
以下是172.18.0.21节点的配置,不一样节点仅需修改bind_addr为对应机器(容器)的IP

client.json
{
  "data_dir": "usr/local/consuldata",
  "enable_script_checks": true,
  "bind_addr": "172.18.0.21",
  "retry_join": ["172.18.0.11","172.18.0.12","172.18.0.13"],
  "retry_interval": "30s",
  "rejoin_after_leave": true,
  "start_join": ["172.18.0.11","172.18.0.12","172.18.0.13"]
}
分别启动三个client节点的consul服务,以client的模式运行,启动后,正常状况下会自动加入到consul的服务端集群中。
./consul agent -config-dir=/usr/local/consuldata > /usr/local/consuldata/consul.log &
./consul members --http-addr 172.18.0.11:8500
 
 
consul客户端代理服务注册
6个容器节点依次安装redis,作成一个集群(步骤略),这里的consul客户端代理的是一个3中3从的Redis集群,这里不列出来Redis集群的安装。
Redis集群安装参考http://www.javashuo.com/article/p-gndkpqts-d.html,仍是很是方便的,在本地(容器节点)一键建立6个节点3主3从的集群。
其中主节点是172.18.0.21,172.18.0.22,172.18.0.23,从节点是172.18.0.24,172.18.0.25,172.18.0.26

这里是使用 w-master-redis-8888.service.consul名字做为三个redis集群节点的服务代理。
172.18.0.21节点上的redis-master-8888.json(172.18.0.22,172.18.0.23,172.18.0.24,172.18.0.25,172.18.0.26 类同,仅需修改address)
{
  "services": 
  [
    {
      "name": "w-master-redis-8888",
      "tags": [
        "master"
      ],
      "address": "172.18.0.21",
      "port": 8888,
      "checks": [
        {
         "args":["sh","-c","/usr/local/consuldata/check_redis_master.sh 172.18.0.21 8888 ******"],
         "Shell":"/bin/bash",
         "interval": "15s"
        }
      ]
    }
  ]
}

redis-slave-8888.json mysql

{
  "services": 
  [
    {
      "name": "r-slave-redis-8888",
      "tags": [
        "master"
      ],
      "address": "172.18.0.21",
      "port": 8888,
      "checks": [
        {
         "args":["sh","-c","/usr/local/consuldata/check_redis_slave.sh 172.18.0.21 8888 ******"],
         "Shell":"/bin/bash",
         "interval": "15s"
        }
      ]
    }
  ]
}

Consul client节点的Redis主节点(写节点)服务检查脚本check_redis_master.sh
如下脚原本源于http://www.javashuo.com/article/p-xrsvsuad-m.html,作了简单的修改,在节点的身份判断逻辑上须要增强。
linux

#!/bin/bash host=$1 myport=$2 auth=$3
if [ ! -n "$auth" ] then auth='\"\"'
fi comm="/usr/local/redis_instance/redis8888/bin/redis-cli -h $host -p $myport -a $auth " role=`echo 'INFO Replication'|$comm |grep -Ec 'role:master'` echo 'INFO Replication'|$comm if [ $role -ne 1 ] then exit 2
fi

Consul client节点的Redis从节点服务检查脚本check_redis_slave.sh
redis

#!/bin/bash
host=$1
myport=$2
auth=$3
if [ ! -n "$auth" ]
then
auth='\"\"'
fi
comm="/usr/local/redis_instance/redis8888/bin/redis-cli -h $host -p $myport -a $auth "
role=`echo 'INFO Replication'|$comm |grep -Ec 'role:slave'`
echo $role
echo 'INFO Replication'|$comm


if [ $role -ne 1 ]
then
    exit 2
fi

 

Consul服务发现sql

redis集群配置成功后,从新加载代理服务,consul reload,一切正常的话,consul服务端就能够解析配置的服务了。
以下注册了两个服务,分别是r-slave-redis-8888,w-master-redis-8888,分别表明Redis集群的读写节点。
docker

能够看到,成功地解析了 w-master-redis-8888.service.consul这个服务,映射到172.18.0.21,172.18.0.22,172.18.0.23三个节点。
须要注意的是,这三个节点都是写节点,这里仅仅是为了实现服务发现(尽管redis 有多IP的驱动支持)

r-slave-redis-8888.service.consul服务的解析,指向了三个从节点,172.18.0.24,172.18.0.25,172.18.0.26shell

故障转移以后的服务发现:模拟主节点故障,对172.18.0.21节点手动故障转移,如今172.18.0.21与172.18.0.24角色交换数据库

Redis集群故障转之后的服务发现解析结果 对于w-master-redis-8888.service.consul这个服务,成功解析到172.18.0.24,172.18.0.22,172.18.0.23三个主节点

json

Redis集群故障转之后的服务发现解析结果 对于w-master-redis-8888.service.consul这个服务,成功解析到172.18.0.24,172.18.0.22,172.18.0.23三个主节点
bootstrap

 

遇到的问题:
1,cosnul服务端集群的时候,clustercenter一开始自定义了一个名称myconsule_datacenter,致使client节点死活加不进来,按照默认的dc1就没有问题
目前还不理解这个datacenter的命名规则是什么?
2,容器节点中的shell脚本要授予可执行权限chmod +x check_XXX.sh
3,其余异常问题,必定要看日志,搜索一下基本上都有结果。
如下纯粹是Redis集群的问题,与Consul没有直接关系,仅做为本测试中遇到的问题。
4,容器节点的Redis集群时,须要移除bind_ip的127.0.0.1节点,直接配置docker建立容器时候的IP,建立集群的时候会一致等待,waiting for the cluster to join
这一点redis-cli --cluster作的很扯淡,明明找不到节点,还要死等,不人为终止的话,他会一直waiting
5,Redis集群时候,由于主从都是相对的,须要相互识别对方,主从节点都要指定“masterauth”和“requirepass”,且密码一致,不然执行cluster  failover提示成功,但故障转移不成功
6,遇到一个灵异的问题(以前单机多实例的时候也遇到过),在启动容器上的Redis服务的时候,若是使用绝对路径启动,在建立集群的时候会出现从节点没法添加到集群中去的状况,中止服务,以相对路径方式重启以后就没有这个问题


总的来讲consul这个中间件使用起来还算是比较简单,配置也很清爽,不像某些中间件使人做呕的配置结构(mycat???)
这里没有配置多数据中心模式,仅配置了单数据中心模式,做为一款服务发现的中间件,是彻底没有问题的,尤为是做为MySQL集群不支持多IP链接驱动的数据库链接。


参考:

相关文章
相关标签/搜索