分两步 第一步是服务内部集成consul,这个相对简单 第二步是ocelot集成consul网关,这个相对麻烦一点
1、内部微服务集成consul集群
需要的配置
public class ConsulConfig
{
public string IP { get; set; } //程序的本机地址 默认是本机的所有地址
public int port { get; set; }//程序的本机端口 注册中心使用
public string consulAddress { get; set; } //consul 地址
public string serviceId { get; set; } //程序的服务id 唯一值
public string serviceName { get; set; } //服务的名称
public string checkUrl { get; set; } //服务的名称
public int checkInterval { get; set; } //服务检查间隔
public string dataCenter { get; set; } //数据中心名称 默认的是dc1
public string enable { get; set; } //是否启用
}
配置:"Consul": {
//单节点
//"Address": "http://XXX:8500",
//"Address": "http://XXX:8500",
"CheckUrl": "/Heath/check",
"CheckInterval": 60, //检查间隔(单位:秒)
"DataCenter": "", //为空则是默认的 dc1
"enable": "1", //是否启用 默认是不启用 1启用 其他不启用
"ignoreNetwork": ".*Sangfor.*,.*Microsoft.*,.*TAP-Windows.*,.*VMware.*,.*VirtualBox.*,.*vEthernet.*,.*Virtual.*,.*Hyper-V.*" //忽略的网卡, //"Address": "http://192.168.1.138:8500",
"enable": "0", //是否启用 默认是不启用 1启用 其他不启用
//集群模式
"Address": "http://XXX:8500,http://1XXX:8500,http://1XXX:8500",
"DataCenter": "XXX"
},
集成方法
////// 添加consul客户端 /// /// ///public static IServiceCollection AddConsulClient(this IServiceCollection services) { ConsulConfig consulConfig = getConfig(services); if (consulConfig.enable != "1") { //因为其他服务注入了 IConsulClient 当不启用consul是会报错 这里注入一个空的consul services.AddConsul(options => { options.Datacenter = consulConfig.dataCenter; options.Address = new Uri("http://localhost:8500"); //options.Token = token1; options.WaitTime = TimeSpan.FromSeconds(consulConfig.checkInterval); }); return services; } foreach (string url in consulConfig.consulAddress.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries)) { services.AddConsul(options => { options.Datacenter = consulConfig.dataCenter; options.Address = new Uri(url); //options.Token = token1; options.WaitTime = TimeSpan.FromSeconds(consulConfig.checkInterval); }); } //覆盖原来的ConsulClientFactory工厂 services.RemoveAll(typeof(IConsulClientFactory)); services.TryAddSingleton (); return services; } /// /// 添加客户端以及注册到注册中心 /// /// ///public static IServiceCollection AddConsulClientAndRegistration(this IServiceCollection services) { ConsulConfig consulConfig = getConfig(services); services.AddConsulClient(); if (consulConfig.enable != "1") { return services; } services.AddConsulServiceRegistration(options => { options.Checks = new[] { new AgentServiceCheck() { DeregisterCriticalServiceAfter = TimeSpan.FromMilliseconds(1), //服务停止后多久注销 Interval = TimeSpan.FromSeconds(10), //服务健康检查间隔 Timeout = TimeSpan.FromSeconds(10), //检查超时的时间 HTTP = consulConfig.checkUrl //检查的地址 } }; options.Address = consulConfig.IP; //本程序的IP地址 options.ID = consulConfig.serviceId; //服务编号,不可重复 options.Name = consulConfig.serviceName; //服务名称 options.Port = consulConfig.port; }); return services; }
替换原来的ConsulClientFactory 默认的ConsulClientFactory不支持配置多个consul客户端public class MyConsulClientFactory : IConsulClientFactory
{
private readonly IOptionsMonitor _optionsMonitor;
public MyConsulClientFactory(IOptionsMonitor optionsMonitor)
{
this._optionsMonitor = optionsMonitor;
}
public IConsulClient CreateClient()
{
return this.CreateClient(RegisterToConsulExtension.currentUseConsulName);
}
public IConsulClient CreateClient(string name)
{
return (IConsulClient)new ConsulClient(this._optionsMonitor.Get(name));
}
}
注意 需要在健康检查中或者定时任务中设置可用的consul客户端 调用如下的方法,如果某个consul客户端挂掉了可以切换到其他的consul服务(需要定义两个变量,用于维护目前使用的是哪个consul客户端)
//保存所有的consul客户端名称
public static List consulNames = new List();
//当前使用的consul客户端名字
public static string currentUseConsulName = "ConsulClient0";
////// 设置可用的consul客户端 /// 检查当前的consul客户端是否可用 不可用时会找一个可用的consul客户端 /// /// public static void SetCurrentConsulClient(IConsulClientFactory consulClientFactory) { IConsulClient consulClient = consulClientFactory.CreateClient(); try { string result = consulClient.Agent.GetNodeName().Result; } catch (Exception e) { ListbadConsulNames = new List () {RegisterToConsulExtension.currentUseConsulName}; Random random = new Random(); while (true) { List okConsulNames = RegisterToConsulExtension.consulNames.FindAll(o => !badConsulNames.Contains(o)); if (okConsulNames.Count == 0) { break; } int next = random.Next(0, okConsulNames.Count); String consulName = okConsulNames[next]; try { consulClient = consulClientFactory.CreateClient(consulName); //如果这里异常这说明这个consul客户端不能用 string result = consulClient.Agent.GetNodeName().Result; RegisterToConsulExtension.currentUseConsulName = consulName; break; } catch (Exception exception) { badConsulNames.Add(consulName); } } } LogUtils.Info($"当前使用的consul:{RegisterToConsulExtension.currentUseConsulName}"); }
//注册到consul
services.AddConsulClientAndRegistration();
2、ocelot 集成consul (ocelot 默认不支持consul集群(也可能是我没找到),需要重写部分方法)
除了上面要调用 services.AddConsulClientAndRegistration(); 外还需要修改ocelot注入
该方法参照 ocelot的 AddConsul 并且需要注入自定义的 MyConsulClientFactory ,重写get方法 覆盖原来的ConsulClientFactory
修改注入的方法
public static IServiceCollection AddOcelotConsul(this IServiceCollection services) {
//添加客户端以及注册到注册中心
services.AddConsulClientAndRegistration();
//注入ocelot需要的类
services.AddSingleton(ConsulProviderFactory.Get);
services.RemoveAll(typeof(Ocelot.Provider.Consul.IConsulClientFactory));
services.AddSingleton();
services.RemoveAll(typeof(IFileConfigurationPollerOptions));
services.AddSingleton();
return services;
}
自定义ConsulClientFactory 该工厂是ocelot里面的工厂不是 consul包里面的工厂public class MyOcelotConsulClientFactory: IConsulClientFactory
{
private Consul.AspNetCore.IConsulClientFactory consulClientFactory;
public MyConsulClientFactory(Consul.AspNetCore.IConsulClientFactory consulClientFactory)
{
this.consulClientFactory = consulClientFactory;
}
public IConsulClient Get(ConsulRegistryConfiguration config)
{
return consulClientFactory.CreateClient();
}
}
如何使用?
直接注入 private Consul.AspNetCore.IConsulClientFactory consulClientFactory;
创建 consul客户端 consulClientFactory.CreateClient();



