.NET+Consul+Ocelot實現微服務分佈式部署

一、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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章