consul在.netcore简单应用

consul

            • 用consul来做什么
            • 安装consul
            • 运行consul
            • 服务注册
            • 服务发现

用consul来做什么

consul是什么我没有发言权,网上有很多的理解和介绍的文章,如果英文好可以去consul官网看下。这里只介绍下打算用consul来做什么。
场景:假设我们有很多api服务,为了保证服务的可靠性或者分担服务压力每个服务部署了多份(集群),这样我们就会有大量的api服务。而这些服务并不是一直不变的,因为每个服务都有可能宕机,我们也会根据需要调整集群里服务的数量。
这种场景下我们怎么管理这一大堆的服务,并保证对外提供的服务都是能用的呢?用consul来管理!
大致流程是这样的:
1:启动consul;
2:每个服务部署启动后,向consul注册(告诉consul有这个服务),并提供健康检查(consul用来测试这服务是否可用);
3:服务正常关闭后,向consul注销(告诉consul这服务不干了);
4:consul服务记下所有注册了的服务,并定期检查服务是否还健在(健康检查),如果不在了就把这服务标记为异常状态不对外提供,下次检查如果发现这服务又复活了,就把这服务标记成健康状态并恢复对外提供;
5:外部需要服务统一找consul要,consul把健康提供所有健康的服务给外部自行选择。

安装consul

【操作视频:https://www.bilibili.com/video/av82190189/ 】

到consul官网的下载页面找到对应系统的安装包下载。
我这是centos7的系统;
安装包下载到目录:/usr/download;
下载地址是:https://releases.hashicorp.com/consul/1.6.2/consul_1.6.2_linux_amd64.zip(注意:不同时间consul版本不一样,下载地址也会不一样,要去上面的网页找当前的地址)
解压(安装)到目录:/usr/consul

cd /usr/download
wget https://releases.hashicorp.com/consul/1.16.0/consul_1.16.0_linux_amd64.zip
unzip consul_1.16.0_linux_amd64.zip -d /usr/consul

将命令写入环境变量:

ln -sv /usr/consul/consul /usr/bin/

查看consul版本,确认是否已安装成功。(如果能看见版本号就说明成功了)

consul -v
运行consul

【操作视频(视频有点老旧,文章后来有改动):https://www.bilibili.com/video/av82190379/ 】

  • 命令行参数
    运行consul的时候有一些必要的参数需要设定,所以要先对consul的配置参数有个大致的了解。
    官网有详细的配置说明文档:https://www.consul.io/docs/agent/options.html。英文的,我也看不大懂。
    下面是一些基本用法可能用到的参数中文说明(英语不好自己琢磨的可能不太对)
参数名 说明
-advertise 如:-advertise=10.1.22.33。此参数绑定集群内部通讯用的本地外网地址。如果consul都部署在同一个局域网内,这个参数就不需要了。
-bootstrap 如:-bootstrap。此标识会使服务推荐自己成为leader。一个数据中心不能有多台服务用这个标识,否则可能会出现多个leader。集群搭建起来后不推荐使用这个标识。此参数必须与 -server 一起使用。(说白了就是这个标识太自我,会让标识了的服务争着做领导!为了避免冲突,如非必要尽量不要用!)
-bootstrap-expect 如:-bootstrap-expect=3。此参数设置数据中心预期的服务数量。如果设置了这个参数,consul会等到指定服务全部加入后才开始启动集群工作。它会自动推荐出一个leader。 此参数不能喝-bootstrap一起使用,且必须与 -server 一起使用。
-bind 如:-bind=192.168.1.100。此参数绑定集群内部通讯用的本地内网地址。默认值是0.0.0.0,如果电脑有多个内网IP需指定一个。
-client 如:-client=0.0.0.0。此参数绑定客户端地址,。默认值是127.0.0.1,只允许本地访问。
-config-dir 如:-config-dir=/usr/consul/consul.json。此参数设置配置文件路径。consul会按字母的顺序加载后缀为“ .json”或“ .hcl”的所有文件。
-data-dir 如:-data-dir=/usr/consul/data。agent持久化数据的目录。
-datacenter 如:-datacenter=dc-mylife。数据中心名。
-dev 如:-dev。此标识启用开发模式。快速启动consul,但不做持久化。
-encrypt 如:-encrypt=zinrVj3m2yrkQ0wB+WW0uljNQvgzs5aCktBiueiMxB8=。此参数指定用于加密Consul网络流量的密钥,该密钥必须是经过Base64编码的32字节。可以用命令[consul keygen]生成。
-log-file 如:-log-file=/usr/consul/log/。此参数设置日志文件名或目录,如果是目录,则文件名默认为consul-{timestamp}.log。目录需要先创建好。
-join 如:-join=192.168.1.20。此参数指定当前服务启动时要加入的另一个代理服务地址。如果加入失败当前服务会启动失败。
-retry-join 如:-retry-join=192.168.1.20。此参数和-join类似,但是如果加入失败就重试。
-log-level 如:-log-level=warn。此参数设置日志级别。可选的级别有:“trace”,“debug”,“info”,“warn”,“err”。默认值为"info"。
-node 如:-node=node-mylife。此参数指定本服务在集群中的节点名,需是唯一的。
-server 如:-server。此标识指定本agent是处于服务器模式还是客户端模式。每个Consul群集至少要有一台服务器。
-ui 如:-ui。此标识设置是否启用web管理页面。
我这只有一台服务器,运行命令行:
consul agent -server -bootstrap-expect=1 -client=0.0.0.0 -ui -data-dir=/usr/consul/data -datacenter=dc-mylife -node=node-mylife -log-file=/usr/consul/log/

(注:日志文件存放的路径要自己手动创建。)

  • 配置文件
    如果嫌命令太长,还可以把一些的参数设置到配置文件里。设置到配置文件的时候一个参数的参数名会有所变动。。。
    具体的还是去看官方文档吧:https://www.consul.io/docs/agent/options.html#configuration-files。
    下面是部分命令行参数和配置文件参数的映射关系:
命令行参数 配置文件参数名
-advertise advertise_addr
-bootstrap bootstrap
-bootstrap-expect bootstrap_expect
-bind bind_addr
-client client_addr
-data-dir data_dir
-datacenter datacenter
-encrypt encrypt
-log-file log_file
-retry-join retry_join
-log-level log_level
-node node_name
-server server
-ui ui
命令行(假设把配置文件放在目录:/usr/consul/consul.json):
consul agent -config-file=/usr/consul/consul.json

配置文件:

{
  "server": true,
  "bootstrap_expect": 1,
  "client_addr": "0.0.0.0",
  "ui": true,
  "data_dir": "/usr/consul/data",
  "datacenter": "dc-mylife",
  "node_name": "node-mylife",
  "log_file": "/usr/consul/log/"
}

Consul运行启动后,可以查看其web管理页面:http://172.81.235.6:8500/ui。(这里的IP是我的服务器IP)

服务注册

【操作视频:https://www.bilibili.com/video/av82190648/ 】

创建业务服务并注册到consul。

  1. 用vs创建core框架的webapi工程ConsulServiceRegister。
  2. 用Nuget安装Consul。
  3. 实现健康检查控制器。
[Route("api/[controller]")]
[ApiController]
public class HealthController : ControllerBase
{
    /// 
    /// 健康检测
    /// 
    /// 
    [HttpGet]
    [Route("Check")]
    public IActionResult Check()
    {
        return Ok();
    }
}
  1. 在Startup类里添加方法注册到Consul方法
    方法:把本服务注册到Consul
        /// 
        /// 把本服务注册到Consul
        /// 
        /// 参数配置
        /// 程序生命周期
        private void RegisterToConsul(IConfiguration config, IHostApplicationLifetime appLifetime)
        {
            //Consul地址
            var consulClient = new ConsulClient(p => { p.Address = new Uri($"http://127.0.0.1:8500"); });

            //本地IP
            var localIP = this.GetLocalIP();
            //本地服务端口
            var localPort = Convert.ToInt32(config["port"]); //端口号从命令行参数获取(注:目前没找到直接获取本服务监听的端口的方法)

            //心跳检测设置
            var httpCheck = new AgentServiceCheck()
            {
                DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(15), //心跳检测失败多久后注销
                Interval = TimeSpan.FromSeconds(10), //间隔多久心跳检测一次
                HTTP = $"http://{localIP}:{localPort}/api/Health/Check", //心跳检查地址,本服务提供的地址
                Timeout = TimeSpan.FromSeconds(5)  //心跳检测超时时间
            };

            //服务名(这里通过命令行参数传入不同的服务名,模拟我们有不同的服务[其实只是同一个接口项目的不同运行实例])
            var serviceName = config["service"];

            //注册信息
            var registration = new AgentServiceRegistration()
            {
                ID = $"{localIP}:{localPort}", //服务ID,唯一
                Name = serviceName, //服务名(如果服务搭集群,它们的服务名应该是一样的,但是ID不一样)
                Address = $"{localIP}", //服务地址
                Port = localPort, //服务端口
                Tags = new string[] { }, //服务标签,一般可以用来设置权重等本地服务特有信息
                Checks = new[] { httpCheck }, //心跳检测设置
            };

            //向Consul注册服务
            consulClient.Agent.ServiceRegister(registration).Wait();

            //关闭程序后注销到Consul
            appLifetime.ApplicationStopped.Register(() =>
            {
                consulClient.Agent.ServiceDeregister(registration.ID).Wait();
            });
        }

方法:获取本地IP

/// 
/// 获取本地IP
/// 
/// 
private string GetLocalIP()
{
    var ip = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces()
            .Select(p => p.GetIPProperties())
            .SelectMany(p => p.UnicastAddresses)
            .Where(p => p.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork && !System.Net.IPAddress.IsLoopback(p.Address))
            .FirstOrDefault()?.Address.ToString();
    return ip;
}
  1. 在Configure方法中注入IConfiguration和IHostApplicationLifetime,并调用上面写的方法RegisterToConsul。
  2. 分别用以下2个命令运行服务
dotnet ConsulServiceRegister.dll --urls="http://0.0.0.0:20011" --port=20011 --service="service1"
dotnet ConsulServiceRegister.dll --urls="http://0.0.0.0:20012" --port=20012 --service="service1"
dotnet ConsulServiceRegister.dll --urls="http://0.0.0.0:20021" --port=20021 --service="service2"
  1. 在Consul的ui管理界面可以看到服务已经被注册到Consul了。
    consul在.netcore简单应用_第1张图片
    consul在.netcore简单应用_第2张图片
服务发现

【操作视频:https://www.bilibili.com/video/av82190906/ 】

从Consul找到已注册到上面的服务。
(注:这里Consul只是做了服务注册和发现,并没有做请求路由和分发!)

  1. 用vs创建core框架的webapi工程ConsulTest。
  2. 用Nuget安装Consul。
  3. 实现查找服务的控制器:
 [Route("api/[controller]")]
    [ApiController]
    public class ServicesController : ControllerBase
    {
        /// 
        /// 获取服务
        /// 
        /// 
        /// 
        [HttpGet]
        [Route("FindService")]
        public List<string> FindService(string name)
        {
            using (var consul = new ConsulClient(c =>
            {
                c.Address = new Uri("http://172.81.235.6:8500/"); //Consul地址
            }))
            {
                //获取服务
                var services = consul.Catalog.Service(name).Result.Response;
                var list = services.Select(m => $"{m.Address}:{m.ServicePort}").ToList();

                return list;
            }
        }
    }
  1. 运行起来后就可以根据服务名字查找服务地址了:
    consul在.netcore简单应用_第3张图片
    consul在.netcore简单应用_第4张图片

(以上2步的代码已放到github上:https://github.com/dabintang/SomeExperiments/tree/master/consul)

你可能感兴趣的:(学习,consul,.net)