在去年的.NET Core微服务系列文章中,初步学习了一下Consul服务发现,总结了两篇文章。本次基于Docker部署的方式,以一个Demo示例来搭建一个Consul的示例集群,最后给出一个HA的架构示范,也会更加贴近于实际应用环境。

一、示例整体架构

  此示例会由一个API Gateway, 一个Consul Client以及三个Consul Server组成,有关Consul的Client和Server这两种模式的Agent的背景知识,请移步我之前的文章加以了解:《.NET Core微服务之基于Consul实现服务治理》。其中,Consul的Client和Server节点共同构成一个Data Center,而API Gateway则从Consul中获取到服务的IP和端口号,并返回给服务消费者。这里的API Gateway是基于Ocelot来实现的,它不是这里的重点,也就不过多说明了,不了解的朋友请移步我的另一篇:《.NET Core微服务之基于Ocelot实现API网关服务》。

二、Consul集群搭建

2.1 Consul镜像拉取

docker pull consul:1.4.4

  验证:docker images

  

2.2 Consul Server实例创建

  以下我的实践是在一台机器上(CentOS 7)操作的,因此将三个实例分别使用了不同的端口号(区别于默认端口号8500)。实际环境中,建议多台机器部署。

  (1)Consul实例1

docker run -d -p 8510:8500 --restart=always -v /XiLife/consul/data/server1:/consul/data -v /XiLife/consul/conf/server1:/consul/config -e CONSUL_BIND_INTERFACE='eth0' --privileged=true --name=consul_server_1 consul:1.4.4 agent -server -bootstrap-expect=3 -ui -node=consul_server_1 -client='0.0.0.0' -data-dir /consul/data -config-dir /consul/config -datacenter=xdp_dc;

  (2)Consul实例2

  为了让Consul实例2加入集群,首先获取一下Consul实例1的IP地址:

  JOIN_IP="$(docker inspect -f '{{.NetworkSettings.IPAddress}}' consul_server_1)";

docker run -d -p 8520:8500 --restart=always -v /XiLife/consul/data/server2:/consul/data -v /XiLife/consul/conf/server2:/consul/config -e CONSUL_BIND_INTERFACE='eth0' --privileged=true --name=consul_server_2 consul:1.4.4 agent -server -ui -node=consul_server_2 -client='0.0.0.0' -datacenter=xdp_dc -data-dir /consul/data -config-dir /consul/config -join=$JOIN_IP;  

  (3)Consul实例3

docker run -d -p 8530:8500 --restart=always -v /XiLife/consul/data/server3:/consul/data -v /XiLife/consul/conf/server3:/consul/config -e CONSUL_BIND_INTERFACE='eth0' --privileged=true --name=consul_server_3 consul:1.4.4 agent -server -ui -node=consul_server_3 -client='0.0.0.0' -datacenter=xdp_dc -data-dir /consul/data -config-dir /consul/config -join=$JOIN_IP;

  验证1:docker exec consul_server_1 consul operator raft list-peers

  

  验证2:http://192.168.16.170:8500/

  

2.3 Consul Client实例创建

  (1)准备services.json配置文件,向Consul注册两个同样的Product API服务

  1. {
  2. "services": [
  3. {
  4. "id": "core.product-/192.168.16.170:8000",
  5. "name": "core.product",
  6. "tags": [ "xdp-/core.product" ],
  7. "address": "192.168.16.170",
  8. "port": 8000,
  9. "checks": [
  10. {
  11. "name": "core.product.check",
  12. "http": "http://192.168.16.170:8000/api/health",
  13. "interval": "10s",
  14. "timeout": "5s"
  15. }
  16. ]
  17. },
  18. {
  19. "id": "core.product-/192.168.16.170:8001",
  20. "name": "core.product",
  21. "tags": [ "xdp-/core.product" ],
  22. "address": "192.168.16.170",
  23. "port": 8001,
  24. "checks": [
  25. {
  26. "name": "core.product.check",
  27. "http": "http://192.168.16.170:8001/api/health",
  28. "interval": "10s",
  29. "timeout": "5s"
  30. }
  31. ]
  32. }
  33. ]
  34. }

  有关配置文件的细节,请移步另一篇文章:《.NET Core微服务之基于Consul实现服务治理(续)

  (2)Consul Client实例

docker run -d -p 8550:8500 --restart=always -v /XiLife/consul/conf/client1:/consul/config -e CONSUL_BIND_INTERFACE='eth0' --name=consul_client_1 consul:1.4.4 agent -node=consul_client_1 -join=$JOIN_IP -client='0.0.0.0' -datacenter=xdp_dc -config-dir /consul/config

  (3)验证

  

  

  

2.4 服务检查监控邮件提箱

  (1)为Client添加watches.json

  1. {
  2. "watches": [
  3. {
  4. "type": "checks",
  5. "handler_type": "http",
  6. "state": "critical",
  7. "http_handler_config": {
  8. "path": "http://192.168.16.170:6030/api/Notifications/consul",
  9. "method": "POST",
  10. "timeout": "10s",
  11. "header": { "Authorization": [ "token" ] }
  12. }
  13. }
  14. ]
  15. }

  *.这里的api接口 http://192.168.16.170:6030/api/Notifications/consul是我的一个通知服务接口,下面是实现的代码

  1. /// <summary>
  2. /// 发送Consul服务中心健康检查Email
  3. /// </summary>
  4. [HttpPost("consul")]
  5. public async Task SendConsulHealthCheckEmail()
  6. {
  7. using (var stream = new MemoryStream())
  8. {
  9. HttpContext.Request.Body.CopyTo(stream);
  10. var ary = stream.ToArray();
  11. var str = Encoding.UTF8.GetString(ary);
  12.  
  13. dynamic notifications = JsonConvert.DeserializeObject(str);
  14. if (notifications == null || notifications.Count == )
  15. {
  16. return;
  17. }
  18.  
  19. var title = "XDP服务中心健康检查通知";
  20. var emailBody = new StringBuilder($"<span style='font-weight:bold; color:red;'>{title}</span> : <br/>");
  21. foreach (var notification in notifications)
  22. {
  23. emailBody.AppendLine($"---------------------------------------------------------<br/>");
  24. emailBody.AppendLine($"<span style='font-weight:bold;'>节点</span>:{notification.Node}<br/>");
  25. emailBody.AppendLine($"<span style='font-weight:bold;'>服务ID</span>:{notification.ServiceID}<br/>");
  26. emailBody.AppendLine($"<span style='font-weight:bold;'>服务名称</span>:{notification.ServiceName}<br/>");
  27. emailBody.AppendLine($"<span style='font-weight:bold;'>检查ID</span>:{notification.CheckID}<br/>");
  28. emailBody.AppendLine($"<span style='font-weight:bold;'>检查名称</span>:{notification.Name}<br/>");
  29. emailBody.AppendLine($"<span style='font-weight:bold;'>检查状态</span>:{notification.Status}<br/>");
  30. emailBody.AppendLine($"<span style='font-weight:bold;'>检查输出</span>:{notification.Output}<br/>");
  31. emailBody.AppendLine($"---------------------------------------------------------<br/>");
  32. }
  33.  
  34. var email = new Email()
  35. {
  36. Username = _configuration["EmailSettings:Username"],
  37. Password = _configuration["EmailSettings:Password"],
  38. SmtpServerAddress = _configuration["EmailSettings:SmtpServerAddress"],
  39. SmtpPort = Convert.ToInt32(_configuration["EmailSettings:SmtpPort"]),
  40. Subject = title,
  41. Body = emailBody.ToString(),
  42. Recipients = _configuration["EmailSettings:Recipients"]
  43. };
  44.  
  45. email.Send();
  46. }
  47. }
  48.  
  49. /// <summary>
  50. /// 使用同步发送邮件
  51. /// </summary>
  52. public void Send()
  53. {
  54. using (SmtpClient smtpClient = GetSmtpClient)
  55. {
  56. using (MailMessage mailMessage = GetClient)
  57. {
  58. if (smtpClient == null || mailMessage == null) return;
  59. Subject = Subject;
  60. Body = Body;
  61. //EnableSsl = false;
  62. smtpClient.Send(mailMessage); //异步发送邮件,如果回调方法中参数不为"true"则表示发送失败
  63. }
  64. }
  65. }

  (2)验证

  

三、Ocelot网关配置

3.1 为Ocelot增加Consul支持

  (1)增加Nuget包:Ocelot.Provider.Consul

Nuget>> Install-Package Ocelot.Provider.Consul  

  (2)修改StartUp.cs,增加Consul支持

  1. s.AddOcelot()
  2. .AddConsul();

  更多内容,请移步:Ocelot官方文档-服务发现

3.2 修改Ocelot配置文件增加Consul配置

  1. "GlobalConfiguration": {
  2. "BaseUrl": "http://api.xique.com",
  3. "ServiceDiscoveryProvider": {
  4. "Host": "192.168.16.170",
  5. "Port": 8550,
  6. "Type": "Consul"
  7. }
  8. }

  *.这里指向的是Consul Client实例的地址

  此外,Ocelot默认策略是每次请求都去Consul中获取服务地址列表,如果想要提高性能,也可以使用PollConsul的策略,即Ocelot自己维护一份列表,然后定期从Consul中获取刷新,就不再是每次请求都去Consul中拿一趟了。例如下面的配置,它告诉Ocelot每2秒钟去Consul中拿一次。

  1. "Type": "PollConsul",
  2. "PollingInterval": 2000

3.3 Service配置

  1. // -- Service
  2. {
  3. "UseServiceDiscovery": true,
  4. "DownstreamPathTemplate": "/api/{url}",
  5. "DownstreamScheme": "http",
  6. "ServiceName": "core.product",
  7. "LoadBalancerOptions": {
  8. "Type": "RoundRobin"
  9. },
  10. "UpstreamPathTemplate": "/product/{url}",
  11. "UpstreamHttpMethod": [ "Get", "Post", "Put", "Delete" ]
  12. }

  这里配置了在Consul中配置的服务名(ServiceName),以及告诉Ocelot我们使用轮询策略(RoundRobin)做负载均衡。

3.4 验证

  第一次访问:

  

  第二次访问:

  

四、HA示例整体架构

  对于实际应用中,我们往往会考虑单点问题,因此会借助一些负载均衡技术来做高可用的架构,这里给出一个建议的HA示例的整体架构:

  对于一个API请求,首先会经历一个Load Balancer才会到达API Gateway,这个Load Balancer可以是基于硬件的F5,也可以是基于软件的Nginx或LVS再搭配Keepalived,一般来说大部分团队都会选择Nginx。然后API Gateway通过部署多个,来解决单点问题,也达到负载均衡的效果。而对于API Gateway和Consul Client之间的连接,我们往往也会增加一个Load Balancer来实现服务发现的高可用,这个Load Balancer也一般会基于Nginx/LVS搭配Keepalived,API Gateway只需要访问一个Virtual IP即可。而在Consul Data Center中,Consul Server会选择3或5个,Consul Client也会部署多个,刚刚提到的Virtual IP则会指向多个Consul Client,从而防止了Consul Client的单点问题。

  最后,祝大家端午安康!

  

  

作者:周旭龙

出处:http://edisonchou.cnblogs.com

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

基于Docker的Consul服务发现集群搭建的更多相关文章

  1. ActiveMQ此例简单介绍基于docker的activemq安装与集群搭建

    ActiveMQ拓展连接 此例简单介绍基于Docker的activemq安装与集群搭建 一 :安装 1.获取activemq镜像 docker pull webcenter/activemq 2.启动 ...

  2. 安装-consul服务发现集群

    centos 7.4.x consul  1.2.2 list: 172.16.16.103 172.16.16.112 172.16.16.115 下载: #cd /usr/local/ #wget ...

  3. 基于docker实现redis高可用集群

    基于docker实现redis高可用集群 yls 2019-9-20 简介 基于docker和docker-compose 使用redis集群和sentinel集群,达到redis高可用,为缓存做铺垫 ...

  4. 小D课堂 - 新版本微服务springcloud+Docker教程_6-06 zuul微服务网关集群搭建

    笔记 6.Zuul微服务网关集群搭建     简介:微服务网关Zull集群搭建 1.nginx+lvs+keepalive      https://www.cnblogs.com/liuyisai/ ...

  5. 分布式协调服务Zookeeper集群搭建

    分布式协调服务Zookeeper集群搭建 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.安装jdk环境 1>.操作环境 [root@node101.yinzhengjie ...

  6. 微服务Consul系列之集群搭建

    在上一篇中讲解了Consul的安装.部署.基本的使用,使得大家有一个基本的了解,本节开始重点Consul集群搭建,官方推荐3-5台Server,因为在异常处理中,如果出现Leader挂了,只要有超过一 ...

  7. 基于Kubernetes v1.24.0的集群搭建(二)

    上一篇文章主要是介绍了,每台虚拟机的环境配置.接下来我们开始有关K8S的相关部署. 另外补充一下上一篇文章中的K8S的change​log链接: https://github.com/kubernet ...

  8. 搜索服务Solr集群搭建 使用ZooKeeper作为代理层

    上篇文章搭建了zookeeper集群 那好,今天就可以搭建solr搜服服务的集群了,这个和redis 集群不同,是需要zk管理的,作为一个代理层 安装四个tomcat,修改其端口号不能冲突.8080~ ...

  9. 同主机下Docker+nginx+tomcat负载均衡集群搭建

    想用Docker模拟一下nginx+tomcat集群部署,今天折腾了一天,遇坑无数,终于在午夜即将到来之际将整个流程走通,借本文希望给同样遇到类似问题的小伙伴们留点线索. 主机环境是CentOS 7, ...

随机推荐

  1. iOS----------componentsJoinedByString 和 componentsSeparatedByString 的方法的区别

    将string字符串转换为array数组 NSArray  *array = [Str componentsSeparatedByString:@","]; ==反向方法 将arr ...

  2. 增加sudo用户访问oracle

    增加zgy用户可以访问数据库[root@DBDATA ~]# useradd zgy--设置密码[root@DBDATA ~]# passwd zgy--设置组[root@DBDATA ~]# use ...

  3. Linux发行版的系统目录名称命名规则以及用途

    linux各种发行版都遵循LSB(Linux Stadards Base)规则,使用一致的相关的基础目录名称,使用根目录系统结构(root filesystem),使用FHS(Files Hierar ...

  4. thinkphp6安装报错,composer install tp6 报错 Parse error: syntax error

    composer install thinkphp6 报错 Parse error: syntax error, unexpected ':', expecting '{' in vendor\top ...

  5. 【转载】解决:'webpack-dev-server' 不是内部或外部命令,也不是可运行的程序 或批处理文件。

    注:网上能搜到的常规解决办法我都试了不好用,这个是最快的解决办法. 以下是转载的解决办法: ****************************************************** ...

  6. 5 其他命令-学习目标以及find命令的基本使用

    .caret, .dropup > .btn > .caret { border-top-color: #000 !important; } .label { border: 1px so ...

  7. leetcode题解:回文数

    判断一个整数是否是回文数.回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数. 示例 1: 输入: 121 输出: true 示例 2: 输入: -121 输出: false 解释: 从左向 ...

  8. [洛谷P1122][题解]最大子树和

    这是一道还算简单的树型dp. 转移方程:f[i]=max(f[j],0) 其中i为任意非叶节点,j为i的一棵子树,而每棵子树都有选或不选两种选择 具体看代码: #include<bits/std ...

  9. Bit Manipulation-leetcode

    Bit Manipulation Find the Difference /* * Given two strings s and t which consist of only lowercase  ...

  10. PHP 将远程文件写入到pdf或者word

    /** * 下载 */public function download($ids = null){ //一些条件参数啥的 $data = []; //获取文件 $res = curl_post(url ...