zoukankan      html  css  js  c++  java
  • 实战中的asp.net core结合Consul集群&Docker实现服务治理

    0、目录


    整体架构目录:ASP.NET Core分布式项目实战-目录

    一、前言


    在写这篇文章之前,我看了很多关于consul的服务治理,但发现基本上都是直接在powershell或者以命令工具的方式在服务器上面直接输入consul agent .... 来搭建启动consul集群,一旦把命令工具关掉,则consul无法再后台启动,尤其是在linux系统中。

    如果在window系统中,采用bat文件到时可以做成开机自启,或者在linux中把命令做成一个service 服务文件来启动就可以实现后台运行。

    因此为了社区能更好的发展技术,且能把consul应用在生产环境中,我认真回顾了在公司项目中的应用,特此把我开发及总结的分享给大家,此篇文章采用docker引擎,并且只涉及到consul集群部署以及结合asp.net core微服务注册。

    当然如果内容有涉及安全隐患的,大家可以积极留言,共同进步。

     注:以下所涉及到部署过程全部经过楼主我反复的验证,总结得来。大家在应用的过程中如果出现问题,可以留言咨询。

    二、部署consul集群


    1、介绍一下Consul

    consul 关键特性
      服务发现:支持服务发现。你可以通过 DNS 或 HTTP 的方式获取服务信息。
      健康检查:支持健康检查。可以提供与给定服务相关联的任何数量的健康检查(如 web 状态码或 cpu 使用率)。
      K/V 存储:键/值对存储。你可用通过 consul 存储如动态配置之类的相关信息。
      多数据中心:支持多数据中心,开箱即用。
      WEB UI:支持 WEB UI。点点点,你就能够了解你的服务现在的运行情况,一目了然,对开发运维是非常友好的。

    说明:

    在Consul方案中,每个提供服务的节点上都要部署和运行Consul的Client Agent,所有运行Consul Agent节点的集合构成Consul Cluster。
    Consul Agent有两种运行模式:Server和Client。这里的Server和Client只是Consul集群层面的区分,与搭建在Cluster之上的应用服务无关。以Server模式运行的Consul Agent节点用于维护Consul集群的状态,官方建议每个Consul Cluster至少有3个或以上的运行在Server Mode的Agent,Client节点不限。

    Consul支持多数据中心,每个数据中心的Consul Cluster都会在运行于Server模式下的Agent节点中选出一个Leader节点,这个选举过程通过Consul实现的raft协议保证,多个 Server节点上的Consul数据信息是强一致的。处于Client Mode的Consul Agent节点比较简单,无状态,仅仅负责将请求转发给Server Agent节点。

    Consul与其他工具的比较

    consul的端口解释

    好了,该介绍的已经介绍了,接下来就是正式部署吧

    2、Docker上运行Consul

    第一步:安全配置,适用授权和数据加密传输(生产环境是必须的)

    为了consul的安全,需要进行gossip加密以及RPC加密结合TLS。
    Gossip加密:主要用于节点间的接收发送集群信息安全。
    RPC加密:主要用于Agent之间调用RPC授权的安全性。

    此处大家可以参考官网或者一下资料:

    https://www.jianshu.com/p/3d074ed76a68
    https://www.consul.io/docs/agent/encryption.html

    第二步:consul集群部署

    准备服务器(可以采用虚拟机部署)

      名称 IP
    CentOS7-1 server1 192.168.216.160
    CentOS7-2 server2 192.168.216.161
    CentOS7-3 server3 192.168.216.162
    CentOS7-4 client1 192.168.216.163
    vs 2017 project部署在docker上 192.168.216.163

    部署server1

    docker run -d --net=host -v $PWD/data:/consul/data -v $PWD/config:/consul/config --restart always --name consulServer1 consul agent -server -bind=192.168.216.160 -node=server1 -bootstrap-expect 3 -data-dir=/consul/data -config-file=/consul/config -client 0.0.0.0 -ui

     

    部署server2
    docker run -d --net=host -v $PWD/data:/consul/data -v $PWD/config:/consul/config --restart always --name cs2 consul agent -server -bind=192.168.216.161 -node=server2 -bootstrap-expect 3 -data-dir=/consul/data -config-file=/consul/config -client 0.0.0.0 -ui -retry-join=192.168.216.160

     

    部署server3
    docker run -d --net=host -v $PWD/data:/consul/data -v $PWD/config:/consul/config --restart always --name cs3 consul agent -server -bind=192.168.216.162 -node=server3 -bootstrap-expect 3 -data-dir=/consul/data -config-file=/consul/config -client 0.0.0.0 -ui -retry-join=192.168.216.160


    部署client-连接server
    docker run -d --net=host -v $PWD/data:/consul/data -v $PWD/config:/consul/config --restart always --name cc1 consul agent -bind=192.168.216.163 -node=client1 -data-dir=/consul/data -config-file=/consul/config -client 0.0.0.0 -retry-join=192.168.216.160

     

    注:(针对以上的参数以及配置解释)
    1、此处的数据挂载就是把容器内的data以及配置挂载到外部地址,$PWD代表当前目录即你运行docker命令时的目录,当然$PWD可以替换为具体的路径
    2、-data-dir=/consul/consul -config-file=/consul/config :这两个地方代表在consul启动后会把数据以及配置文件放到指定的目录下,这个对于在服务器模式下运行的代理尤其重要,因为它们必须能够保持群集状态。
    3、总结,以上两点结合就是说明 consul产生的数据然后挂载在外部地址进行持久化存储。
    4、server端 的-client 参数可以不用,官方推荐是 服务注册到client端,由client端再把数据统一提交到server端。

    参数说明

    -client : 0.0.0.0 代表绑定到所有接口的选项,如果没有此选项,则asp.net core无法进行服务注册使用

    -bind :该地址用来在集群内部的通讯,集群内的所有节点到地址都必须是可达的

    --net=host 使得docker容器越过了net namespace的隔离,免去手动指定端口映射的步骤

    -retry-join 允许你在第一次失败后进行尝试,加入一个已经启动的agent的ip地址

    -bootstrap-expect 提供的server节点数目

    -ui 启动自有主机的界面

    -data-dir :提供一个目录用来存放agent的状态,所有的agent允许都需要该目录,该目录必须是稳定的,系统重启后都继续存在

    CONSUL_LOCAL_CONFIG={"skip_leave_on_interrupt": true}:在0.7版本之后默认是true,因此不是必须的。

    CONSUL_LOCAL_CONFIG={"leave_on_terminate": true}:在0.7版本之后默认是true,因此不是必须的。如果启用,当代理收到TERM信号时,它将向Leave群集的其余部分发送消息并正常离开

    打开浏览器器查看 consul :

    看所有consul节点情况
    docker exec -t cs1 consul members

    查看server的状态,以及哪一个节点是leader

    docker exec -t cs1 consul operator raft list-peers

    注:

    如果其中一台或者多台server端挂掉,则Consul集群就会重新选举新的Leader,
    但是一旦挂掉阿的节点数量超过一半,则Consul集群就无法工作了。

    三、asp.net core微服务进行服务注册


    1、新建一个项目asp.net core webapi项目

    引入 consul ,nuget包

    2、在控制器中新建一个控制器Health,代表健康检查

    [Produces("application/json")]
        [Route("api/Health")]
        public class HealthController : Controller
        {
            [HttpGet]
            public IActionResult Get() => Ok("ok");
        }

    3、然后在appsetting.json中添加配置文件

    需要手动配置一下地址和端口号。

    {
      "Logging": {
        "IncludeScopes": false,
        "Debug": {
          "LogLevel": {
            "Default": "Warning"
          }
        },
        "Console": {
          "LogLevel": {
            "Default": "Warning"
          }
        }
      },
      "ServiceRegister": { //服务注册
        "IsActive": true,
        "ServiceName": "testconsul6",
        "ServiceHost": "192.168.216.163",
        "ServicePort": 5006,
        "Register": {
          "HttpEndpoint": "http://192.168.216.163:8500"
        }
      }
    }

    4、这一步是服务注册的类

    ServiceRegisterOptions.cs

    public class ServiceRegisterOptions
        {
            /// <summary>
            /// 是否启用
            /// </summary>
            public bool IsActive { get; set; }
            /// <summary>
            /// 服务名称
            /// </summary>
            public string ServiceName { get; set; }
            /// <summary>
            /// 服务IP或者域名
            /// </summary>
            public string ServiceHost { get; set; }
            /// <summary>
            /// 服务端口号
            /// </summary>
            public int ServicePort { get; set; }
            /// <summary>
            /// consul注册地址
            /// </summary>
            public RegisterOptions Register { get; set; }
        }

     RegisterOptions.cs

    public class RegisterOptions
        {
            public string HttpEndpoint { get; set; }
        }

     5、在startup.cs 中的服务注册

    public void ConfigureServices(IServiceCollection services)
            {
                #region 服务注册基础信息配置
                services.Configure<ServiceRegisterOptions>(Configuration.GetSection("ServiceRegister"));
                services.AddSingleton<IConsulClient>(p => new ConsulClient(cfg =>
                {
                    var serviceConfiguration = p.GetRequiredService<IOptions<ServiceRegisterOptions>>().Value;
                    if (!string.IsNullOrEmpty(serviceConfiguration.Register.HttpEndpoint))
                    {
                        cfg.Address = new Uri(serviceConfiguration.Register.HttpEndpoint);
                    }
                }));
                #endregion
    
                services.AddMvc();
            }

    在Configure 方法中配置代码

    private static void RegisterService(IApplicationBuilder app,
                IOptions<ServiceRegisterOptions> serviceRegisterOptions,
                IConsulClient consul,
                IApplicationLifetime appLife)
            {
                var serviceId = $"{serviceRegisterOptions.Value.ServiceName}_{serviceRegisterOptions.Value.ServiceHost}:{serviceRegisterOptions.Value.ServicePort}";
    
                var httpCheck = new AgentServiceCheck()
                {
                    DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服务启动多久后注册
                    Interval = TimeSpan.FromSeconds(30),//健康检查时间间隔,或者称为心跳间隔
                    HTTP = $"http://{serviceRegisterOptions.Value.ServiceHost}:{serviceRegisterOptions.Value.ServicePort}/api/health",//健康检查地址
                };
    
                var registration = new AgentServiceRegistration()
                {
                    Checks = new[] { httpCheck },
                    Address = serviceRegisterOptions.Value.ServiceHost,
                    ID = serviceId,
                    Name = serviceRegisterOptions.Value.ServiceName,
                    Port = serviceRegisterOptions.Value.ServicePort
                    //Tags = new[] { $"urlprefix-/{serviceRegisterOptions.Value.ServiceName}" }//添加 urlprefix-/servicename 格式的 tag 标签,以便 Fabio 识别
                };
                //.GetAwaiter().GetResult()
                consul.Agent.ServiceRegister(registration).GetAwaiter().GetResult();
    
                appLife.ApplicationStopping.Register(() =>
                {
                    consul.Agent.ServiceDeregister(serviceId).GetAwaiter().GetResult();//服务停止时取消注册
                });
            }
            #endregion

    自此,可以把我们的项目部署到163服务器上面的docker上啦。

    我们看一下效果,成功注册到了

    参考资料:

    Conusl TLS配置:

    https://www.jianshu.com/p/3d074ed76a68
    https://www.consul.io/docs/agent/encryption.html

    consul 参数配置: 

    https://blog.csdn.net/zl1zl2zl3/article/details/79622476

    consul服务治理:

    http://michaco.net/blog/ServiceDiscoveryAndHealthChecksInAspNetCoreWithConsul
    https://www.cnblogs.com/myzony/p/9168851.html
    https://www.cnblogs.com/edisonchou/p/9124985.html


    asp.net Core 交流群:787464275 欢迎加群交流
    如果您认为这篇文章还不错或者有所收获,您可以点击右下角的【推荐】按钮精神支持,因为这种支持是我继续写作,分享的最大动力!

    作者:LouieGuo
    声明:原创博客请在转载时保留原文链接或者在文章开头加上本人博客地址,如发现错误,欢迎批评指正。凡是转载于本人的文章,不能设置打赏功能,如有特殊需求请与本人联系!

    微信公众号:欢迎关注                                                 QQ技术交流群: 欢迎加群

                    

  • 相关阅读:
    Python 中的 __str__ 与 __repr__ 到底有什么差别
    02 LeetCode---链表相加
    01 LeetCode---两数之和
    python 数据结构一 之 线性表
    来自C++的"Const式"傲娇
    string 与 char 字符串区别-1
    超级有爱的并查集入门
    多项式求解
    竞码编程-蓝桥杯模拟赛4-D题
    树的直径-蓝桥杯大臣的旅费
  • 原文地址:https://www.cnblogs.com/guolianyu/p/9614050.html
Copyright © 2011-2022 走看看