.NET Core Consul Ocelot Demo
本地环境
Win10
虚拟机 CentOS7
CentOS中提前安装好 docker-compose 和 dotnet 运行环境
WebAPI (.NET 5.0):
NuGet:
Consul (1.6.10.4)
APIGateway(.NET 5.0):
NuGet:
Ocelot (17.0.0)
Ocelot.Provider.Consul (17.0.0)
一、Consul 集群
使用 docker-compose.yaml 快速部署一个 Consul 集群
version: '3'
services:
Consul-1:
image: consul
command: agent -server -client=0.0.0.0 -bootstrap-expect=3 -node=Consul-1 -data-dir=/data
volumes:
- ./Consul-1:/data
Consul-2:
image: consul
command: agent -server -client=0.0.0.0 -retry-join=Consul-1 -node=Consul-2 -data-dir=/data
volumes:
- ./Consul-2:/data
depends_on:
- Consul-1
Consul-3:
image: consul
command: agent -server -client=0.0.0.0 -retry-join=Consul-1 -node=Consul-3 -data-dir=/data
volumes:
- ./Consul-3:/data
depends_on:
- Consul-1
Consul-4:
image: consul
command: agent -client=0.0.0.0 -retry-join=Consul-1 -ui -node=Consul-4 -data-dir=/data
ports:
- 8500:8500
volumes:
- ./Consul-4:/data
depends_on:
- Consul-2
- Consul-3
docker-compose up
启动
win10 中访问 http://CentOSIP:8500/
二、WebAPI
定义两个控制器
using Microsoft.AspNetCore.Mvc; namespace WebAPI.Controllers { [Route("health")] [ApiController] public class healthController : Controller { public IActionResult Get() => Ok("ok"); } } using Microsoft.AspNetCore.Mvc; namespace WebAPI.Controllers { [Route("api/Demo")] [ApiController] public class DemoController : Controller { [HttpGet] public IActionResult Get(string id) { return Json(new { id = id }); } [HttpPost] public IActionResult Post(UserDto userDto) { return Json(new { UserName = userDto.UserName, UserId = userDto.UserId }); } } }
注册 Consul
appsettings.json
{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*", "Consul": { "ServiceId": "11111111111111", // 当前项目的名字,如果部署多个实例,该名字必须一致 "ServiceName": "WebAPI", // 当前项目部署后的IP地址 "ServiceIP": "192.168.214.129", // 当前项目部署后的端口号 "ServicePort": 8001, // 当前项目部署后 Consul 调用该接口判断服务是否健康 "ServiceHealthCheck": "http://192.168.214.129:8001/health", // Consul 的地址 "ConsulAddress": "http://192.168.214.129:8500" } }
安装 appsettings.json 中的 Consul 节点定义一个类型
namespace WebAPI { public class ServiceEntity { public string ServiceId { get; set; } public string ServiceName { get; set; } public string ServiceIP { get; set; } public int ServicePort { get; set; } public string ServiceHealthCheck { get; set; } public string ConsulAddress { get; set; } } }
Startup
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHostApplicationLifetime lifetime) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } ServiceEntity serviceEntity = new ServiceEntity { ServiceId = Configuration["Consul:ServiceId"], ServiceIP = Configuration["Consul:ServiceIP"], ServiceName = Configuration["Consul:ServiceName"], ServicePort = Convert.ToInt32(Configuration["Consul:ServicePort"]), ServiceHealthCheck = Configuration["Consul:ServiceHealthCheck"], ConsulAddress = Configuration["Consul:ConsulAddress"] }; app.UseConsul(lifetime, serviceEntity); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }
ConsulBuilderExtensions.cs
public static class ConsulBuilderExtensions { public static IApplicationBuilder UseConsul(this IApplicationBuilder app, IHostApplicationLifetime lifetime, ServiceEntity serviceEntity) { var consulClient = new ConsulClient(x => { x.Address = new Uri(serviceEntity.ConsulAddress); }); var registration = new AgentServiceRegistration() { ID = Guid.NewGuid().ToString(), Name = serviceEntity.ServiceName,// 服务名 Address = serviceEntity.ServiceIP, // 服务绑定IP Port = serviceEntity.ServicePort, // 服务绑定端口 Check = new AgentServiceCheck() { DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服务启动多久后注册 Interval = TimeSpan.FromSeconds(10),//健康检查时间间隔 HTTP = serviceEntity.ServiceHealthCheck,//健康检查地址 Timeout = TimeSpan.FromSeconds(5) } }; // 服务注册 consulClient.Agent.ServiceRegister(registration).Wait(); // 应用程序终止时,服务取消注册 lifetime.ApplicationStopping.Register(() => { consulClient.Agent.ServiceDeregister(registration.ID).Wait(); }); return app; } }
代码部分就完成了,打包,发布到 CentOS中
WebAPI1 和 WebAPI2 各放一份
其中 WebAPI2 中的 appsettings.json 中的 ServicePort 和 ServiceHealthCheck 中的端口号修改一下,两个实例启动的时候 WebAPI1 会占用
dotnet WebAPI.dll --urls="http://*:8001"
dotnet WebAPI.dll --urls="http://*:8002"
启动两个 WebAPI 实例
启动完成后过稍等片刻
等待的时间通过下面这句代码控制
DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5), //服务启动多久后注册
浏览器中验证一下两个节点是否 OK
三、网关
新建一个 WebAPI项目
添加一个 Ocelot.json 配置文件
{ "Routes": [ { "UpstreamPathTemplate": "/{url}", "UpstreamHttpMethod": [ "Get", "Post", "Put" ], "DownstreamPathTemplate": "/{url}", "DownstreamScheme": "http", "ServiceName": "WebAPI", "LoadBalancerOptions": { "Type": "LeastConnection" } } ], "GlobalConfiguration": { "ServiceDiscoveryProvider": { "Scheme": "http", "Host": "192.168.214.129", "Port": 8500, "Type": "PollConsul", "PollingInterval": 100 } } }
Program.cs
using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; namespace APIGateway { public class Program { public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }) .ConfigureAppConfiguration(configure => { configure.AddJsonFile("Ocelot.json"); }); } }
StartUp.cs
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Ocelot.DependencyInjection; using Ocelot.Middleware; using Ocelot.Provider.Consul; namespace APIGateway { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddOcelot().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(); } } }
只需要这么多就够了,其他的都可以删掉
发布后部署到CentOS中
dotnet APIGateway.dll --urls="http://*:9001"
启动网关
浏览器通过网关访问 某个 WebAPI 的实例
Demo中通过 Consul 实现网关与 WebAPI实例 之间的解耦
网关不停的轮询从 Consul 中获取 WebAPI可用的实例
只要 Consul 中还有一个 WebAPI的实力,整个服务都是OK的