1 环境准备
vm下准备3台windows虚拟机 192.168.8.220 , 192.168.8.221 , 192.168.8.222
2 consul集群(2个server+1个client)
IP220电脑 consul agent -server -ui -bootstrap-expect 2 -data-dir data -node Server01 -bind 192.168.8.220 -client 0.0.0.0 &
IP221电脑 consul agent -server -ui -bootstrap-expect 2 -data-dir data -node Server01 -bind 192.168.8.221 -client 0.0.0.0 & 然后执行 consul join 192.168.8.220
IP222电脑 consul agent -ui -data-dir data -node Server03 -bind 192.168.8.222 -client 0.0.0.0 & 然后执行 consul join 192.168.8.220
这样集群就算完成了 具体consul的详细配置请自行查阅文档
3 编码阶段
3.1 ocelot网关,新建一个API的网关项目,结构如下
startup.cs 文件
public void ConfigureServices(IServiceCollection services)
{
services.AddOcelot(Configuration).AddConsul();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseOcelot().Wait();
}
program.cs 文件
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args).ConfigureAppConfiguration((host, config) =>
{
config.AddJsonFile("ocelot.json");
}).ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
3.2 新建api服务,结构如下
startup.cs 文件
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
//注入consul
Configuration.ConsulRegister();
}
appsettings.json 文件
"Consul": {
"Address": "http://127.0.0.1:8500",
"DataCenter": "dc1",
"ServiceName": "Api01"
}
ConsulConfigurationEx.cs 文件
public static void ConsulRegister(this IConfiguration configuration, IApplicationLifetime lifetime)
{
ConsulClient client = new ConsulClient(
(ConsulClientConfiguration c) =>
{
c.Address = new Uri(configuration["Consul:Address"]); //Consul服务中心地址
c.Datacenter = configuration["Consul:DataCenter"]; //指定数据中心,如果未提供,则默认为代理的数据中心。
}
);
Console.WriteLine("IP:" + configuration["ip"].ToString());
String ip = configuration["ip"];//部署到不同服务器的时候不能写成127.0.0.1或者0.0.0.0,因为这是让服务消费者调用的地址
Console.WriteLine("port:" + configuration["port"].ToString());
Int32 port = Int32.Parse(configuration["port"]);
var registration = new AgentServiceRegistration()
{
ID = Guid.NewGuid().ToString(), //服务编号,不可重复
Name = configuration["Consul:ServiceName"], //服务名称
Port = port, //本程序的端口号
Address = ip, //本程序的IP地址
Check = new AgentServiceCheck()
{
DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(10), //服务停止后多久注销
Interval = TimeSpan.FromSeconds(5), //服务健康检查间隔
Timeout = TimeSpan.FromSeconds(5), //检查超时的时间
HTTP = $"http://{ip}:{port}/ConsulHealth/Get",//健康检查地址, //检查的地址
}
};
//注册
client.Agent.ServiceRegister(registration).ConfigureAwait(true);
//应用程序关闭时候
lifetime.ApplicationStopping.Register(() =>
{
//正在注销
client.Agent.ServiceDeregister(registration.ID).ConfigureAwait(true);
});
}
ConsulHealthController.cs 文件
[ApiController]
[Route("[controller]/[action]")]
public class ConsulHealthController : ControllerBase
{
[HttpGet]
public IActionResult Get()
{
return Ok("ok");
}
}
4 部署阶段
220电脑 启动服务 dotnet Service1.dll --urls="http://*:6001" --ip="192.168.8.220" --port=6001
221电脑 启动服务 dotnet Service2.dll --urls="http://*:6001" --ip="192.168.8.221" --port=6002
222电脑 启动网关 dotnet OcelotGateWay.dll --urls="http://*:3388" --ip="192.168.8.222" --port=3388
请求
http://192.168.8.222:3388/ConsulHealth/Get
这样我们就算是成功了
遇到几个难点,在部署consul集群时,如果指定了node节点名字,需要在系统hosts文件把对应的 ip和节点写上
如 192.168.8.220 Server01,如果没有指定节点,ocelot会使用电脑名字解析,原因就是ocelot源码处理了,
对应文件为 Ocelot-develop\src\Ocelot.Provider.Consul\Consul.cs
public
async Task<List<Service>> Get()
{
var
queryResult = await _consul.Health.Service(_config.KeyOfServiceInConsul,
string
.Empty,
true
);
var
services =
new
List<Service>();
foreach
(
var
serviceEntry
in
queryResult.Response)
{
if
(IsValid(serviceEntry))
{
var
nodes = await _consul.Catalog.Nodes();
if
(nodes.Response ==
null
)
{
services.Add(BuildService(serviceEntry,
null
));
}
else
{
var
serviceNode = nodes.Response.FirstOrDefault(n => n.Address == serviceEntry.Service.Address);
services.Add(BuildService(serviceEntry, serviceNode));
}
}
else
{
_logger.LogWarning($
"Unable to use service Address: {serviceEntry.Service.Address} and Port: {serviceEntry.Service.Port} as it is invalid. Address must contain host only e.g. localhost and port must be greater than 0"
);
}
}
return
services.ToList();
}
private
Service BuildService(ServiceEntry serviceEntry, Node serviceNode)
{
return
new
Service(
serviceEntry.Service.Service,
new
ServiceHostAndPort(serviceNode ==
null
? serviceEntry.Service.Address : serviceNode.Name, serviceEntry.Service.Port),
serviceEntry.Service.ID,
GetVersionFromStrings(serviceEntry.Service.Tags),
serviceEntry.Service.Tags ?? Enumerable.Empty<
string
>());
}
20210526 ocelot + consul 集群 调用服务无法访问下游填坑
原文:https://www.cnblogs.com/tmacsjp/p/14814654.html