一、ConSul和Ocelot
Consul:是一個服務網格解決方案,提供了一個功能齊全的控制平面,具有服務發現、配置和分段功能。這些功能中的每一項都可以根據需要單獨使用,也可以一起使用來構建一個完整的服務網格。Consul需要一個數據平面,並支持代理和原生集成模型。Consul提供了一個簡單的內置代理,因此一切都可以開箱即用,具有註冊中心、配置中心、健康檢查等很好用的功能。
Ocelot:Ocelot首先通過配置將HttpRequest對象保存到一個指定的狀態直到它到達用來創建HttpRequestMessage對象並將創建的HttpRequestMessage對象發送到下游服務中的請求構造中間件。通過中間件來發出請求是Ocelot管道中做的最後一件事。它不會再調用下一個中間件。下游服務的響應會存儲在每個請求 scoped repository中,並作爲一個請求返回到Ocelot管道中。有一箇中間件將HttpResponseMessage映射到HttpResponse對象並返回給客戶端。
接下來是你使用Ocelot是可能會使用的配置。
二、環境和版本
Demo框架:.Net6
Docker:20.10.18
Consul:1.6.10.8
Ocelot:18.0.0
三、Docker裏面安裝Consul
Docker安裝可參考:https://www.cnblogs.com/chj929555796/p/16779240.html
執行拉取鏡像命令:
docker pull consul
創建Consul容器:
docker run -d --name consul -p 8500:8500 consul:latest
四、Demo事例
一、Demo結構說明
Client-WebService:網關項目端口5001
Order-OrderApi:訂單服務,端口5002、5004、5006
Product-ProductApi:產品服務,端口5003、5005
二、Consul擴展類
ConsulRegisterOptions:Consul註冊服務節點類
namespace OrderApi.ConsulExtends { public class ConsulRegisterOptions { public string ConsulAddress { get; set; } public string Healthcheck { get; set; } public string ServiceName { get; set; } public string Ip { get; set; } public int Port { get; set; } } }
ConsulExend:Consul注入服務延伸類
namespace OrderApi.ConsulExtends { public static class ConsulExend { public static void AddConsulRegister(this IServiceCollection services) { services.AddTransient<IConsulRegister, ConsulRegister>(); } } }
IConsulRegister:註冊服務接口類
namespace OrderApi.ConsulExtends { public interface IConsulRegister { Task ConsulRegisterAsync(); } }
ConsulRegister:註冊服務實現類
using Consul; using Microsoft.Extensions.Options; namespace OrderApi.ConsulExtends { public class ConsulRegister : IConsulRegister { private readonly ConsulRegisterOptions _consulRegisterOptions; public ConsulRegister(IOptionsMonitor<ConsulRegisterOptions> consulRegisterOptions) { _consulRegisterOptions = consulRegisterOptions.CurrentValue; } public async Task ConsulRegisterAsync() { var client = new ConsulClient(options => { options.Address = new Uri(_consulRegisterOptions.ConsulAddress);// Consul客戶端地址 }); var registration = new AgentServiceRegistration { ID = Guid.NewGuid().ToString(),//唯一ID Name = _consulRegisterOptions.ServiceName,//服務名 Address = _consulRegisterOptions.Ip,//服務綁定IP Port = _consulRegisterOptions.Port,//服務綁定端口 Check = new AgentServiceCheck { DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(1),//服務啓動後多久註冊 Interval = TimeSpan.FromSeconds(5),//健康檢查時間 HTTP = $"http://{_consulRegisterOptions.Ip}:{_consulRegisterOptions.Port}{_consulRegisterOptions.Healthcheck}",//檢查地址 Timeout = TimeSpan.FromSeconds(10),//超時時間 } }; await client.Agent.ServiceRegister(registration); } } }
HealthCheckMiddleware:Consul檢測服務中間件類
using System.Net; namespace OrderApi.ConsulExtends { public static class HealthCheckMiddleware { public static void UseHealthCheckMiddleware(this IApplicationBuilder app, string checkPath = "/healthcheck") { int code = 0; app.Map(checkPath, applicationBuilder => applicationBuilder.Run(async context => { Console.WriteLine("this is health check"); code = context.Response.StatusCode; context.Response.StatusCode = (int)HttpStatusCode.OK; await context.Response.WriteAsync("OK"); })); } } }
以上幾個類OrderApi和ProductApi都一樣,用於在服務啓動時註冊服務到Consul中。
三、appsettings.json和Program.cs配置
1、OrderApi服務
"ConsulRegister": { "ConsulAddress": "http://consul-IP:8500", //consul客戶端地址 "Healthcheck": "/healthcheck", //consul健康檢查地址 "ServiceName": "OrderService",//服務名稱,服務啓動時會註冊到Consul中的Service "Ip": "consul-IP", "Port": "服務端口號"//定義一個就行,後期容器啓動時可以通過命令映射更改 },
using OrderApi.ConsulExtends; var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); //註冊consul服務 builder.Services.Configure<ConsulRegisterOptions>(builder.Configuration.GetSection("ConsulRegister")); builder.Services.AddConsulRegister(); builder.WebHost.UseUrls("http://*:5002"); var app = builder.Build(); //註冊consul服務 app.Services.GetService<IConsulRegister>()!.ConsulRegisterAsync(); // Configure the HTTP request pipeline. //if (app.Environment.IsDevelopment()) //{ //app.UseExceptionHandler("/Home/Error"); app.UseSwagger(); app.UseSwaggerUI(); //} app.UseAuthorization(); app.MapControllers(); //註冊consul健康檢查中間件 app.UseHealthCheckMiddleware(); app.Run();
2、ProductApi服務
"ConsulRegister": { "ConsulAddress": "http://consul-IP:8500", //consul客戶端地址 "Healthcheck": "/healthcheck", //consul健康檢查地址 "ServiceName": "ProductService",//服務名稱,服務啓動時會註冊到consul中的Service "Ip": "consul-IP", "Port": "服務端口號"//定義一個就行,後期容器啓動時可以通過命令映射更改 },
using ProductApi.ConsulExtends; var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); //註冊consul服務 builder.Services.Configure<ConsulRegisterOptions>(builder.Configuration.GetSection("ConsulRegister")); builder.Services.AddConsulRegister(); builder.WebHost.UseUrls("http://*:5003"); var app = builder.Build(); //註冊consul服務 app.Services.GetService<IConsulRegister>()!.ConsulRegisterAsync(); // Configure the HTTP request pipeline. //if (app.Environment.IsDevelopment()) //{ app.UseSwagger(); app.UseSwaggerUI(); //} app.UseAuthorization(); app.MapControllers(); app.UseHealthCheckMiddleware(); app.Run();
截止爲止,兩個服務註冊Consul相關已完成,啓動服務時會自動把服務註冊到Consul
查看詳細服務
3、WebService網關項目
需要安裝Nuget包:Consul、Ocelot、Ocelot.Provider.Consul
新增文件:ocelot.json
{ "Routes": [ { "UseServiceDiscovery": true, // 使用服務發現 "DownstreamPathTemplate": "/orderapi/{url}", //下游的路由模板,即真實處理請求的路徑模板 "UpstreamPathTemplate": "/orderapi/{url}", //上游請求的模板,即用戶真實請求的鏈接 "DownstreamScheme": "http", //"DownstreamHostAndPorts": [ // { // "Host": "consul-ip", // "Port": 5002 // }, // { // "Host": "consul-ip", // "Port": 5004 // }, // { // "Host": "consul-ip", // "Port": 5006 // } //], "ServiceName": "OrderService", // 服務名稱-這個要跟應用註冊時寫的名字一致,否則無效 //配置負載均衡 "LoadBalancerOptions": { "Type": "RoundRobin" //負載均衡 RoundRobin(輪詢)/LeastConnection(最少連接數) }, "UpstreamHttpMethod": [ "Options", "Get", "Post", "Put", "Delete" ], "ReRoutesCaseSensitive": false, // 路由大小寫敏感設置 "key": "orderapi" }, { "UseServiceDiscovery": true, // 使用服務發現 "DownstreamPathTemplate": "/productapi/{url}", //下游的路由模板,即真實處理請求的路徑模板 "UpstreamPathTemplate": "/productapi/{url}", //上游請求的模板,即用戶真實請求的鏈接 "DownstreamScheme": "http", //"DownstreamHostAndPorts": [ // { // "Host": "consul-ip", // "Port": 5003 // }, // { // "Host": "consul-ip", // "Port": 5005 // } //], "ServiceName": "ProductService", // 服務名稱-這個要跟應用註冊時寫的名字一致,否則無效 //配置負載均衡 "LoadBalancerOptions": { "Type": "RoundRobin" //負載均衡方式 }, "UpstreamHttpMethod": [ "Options", "Get", "Post", "Put", "Delete" ], "ReRoutesCaseSensitive": false, // 路由大小寫敏感設置 "key": "productapi" } ], "GlobalConfiguration": { // 網關全局配置 "BaseUrl": "http://consul-ip:5001", //當前網關項目的地址 "ServiceDiscoveryProvider": { // 服務發現的配置 "Scheme": "http", "Host": "consul-ip", //Consul 服務的訪問ip "Port": 8500, //Consul 服務的訪問端口 "Type": "Consul" } } }
WebService-Program.cs
using Ocelot.DependencyInjection; using Ocelot.Middleware; using Ocelot.Provider.Consul; var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddRazorPages(); builder.Configuration.AddJsonFile("appsettings.json", true, true); //支持在更改時重新加載 json 配置文件 builder.Configuration.AddJsonFile("ocelot.json",false,true).AddEnvironmentVariables(); builder.Services.AddOcelot().AddConsul(); builder.WebHost.UseUrls("http://*:5001"); var app = builder.Build(); // Configure the HTTP request pipeline. //if (!app.Environment.IsDevelopment()) //{ // app.UseExceptionHandler("/Error"); //} app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); app.MapRazorPages(); app.UseOcelot().Wait(); app.Run();
五、Docker構建
一、上傳項目文件夾到雲服務器
二、切換到每個目錄下依次執行構建鏡像及創建容器
1、OrderApi
切換目錄:cd /Order 構建鏡像:sudo docker build -t microservicesorder . 創建容器: docker run -d -p 5002:5002 --name orderapitest microservicesorder --ConsulRegister:Port="5002" docker run -d -p 5004:5002 --name orderapitest1 microservicesorder --ConsulRegister:Port="5004" docker run -d -p 5006:5002 --name orderapitest2 microservicesorder --ConsulRegister:Port="5006" 這裏需要注意ConsulRegister:Port的地方,以往我們構建容器方式是 docker run --name orderapitest -p 5002:5002 microservicesorder 但是此處多了--ConsulRegister:Port="5006",此段代碼就是在訪問時去替換當前服務appsettings.json文件ConsulRegister節點的Port
2、ProductApi
切換目錄:cd /Product 構建鏡像:sudo docker build -t microservicesproduct . 創建容器: docker run -d -p 5003:5003 --name productapitest microservicesproduct --ConsulRegister:Port="5003" docker run -d -p 5005:5003 --name productapitest1 microservicesproduct --ConsulRegister:Port="5005"
3、Client網關
切換目錄:cd /Client 構建鏡像:sudo docker build -t microservicesclient . 創建容器:docker run --name clienttest -p 5001:5001 microservicesclient
服務健康監測運行情況
訪問Order服務
訪問Product服務
參考文獻:https://blog.xiaobaicai.fun/share/7386.html