34345 发表于 2025-2-7 02:51:50

Ocelot集成Consul实现api网关与服务发现

前言

没看dotnet微服务之API网关Ocelot的请先看,这篇文章接上面文章
安装consul

#自定义网络,自定义网络可以指定容器IP,这样服务器重启consul集群也可以正常运行。docker network create --driver bridge --subnet=172.21.0.0/16 --gateway=172.21.0.16 adnc_consuldocker run -d -p 8500:8500 -p 8600:8600 -p 8301:8301 --restart=always --network=adnc_consul --ip 172.21.0.1 --privileged=true --name=consul_server_1--name consul consul:1.15.4 agent -server -bootstrap -ui -node=consul_server_1 -client='0.0.0.0'在GoodApi项目中修改Program.cs

先要添加Consul包
再添加Consul注册于注销等相关代码
using Consul;using System.Linq;using System.Net;using System.Net.Sockets;// 创建Consul客户端var consulAddress = "http://10.75.174.43:8500";// Environment.GetEnvironmentVariable("CONSUL_ADDRESS"); //10.75.174.43var consulUri = new Uri(consulAddress);var client = new ConsulClient(config =>{    config.Address = consulUri;});// 配置服务的健康检查var check = new AgentServiceCheck(){    HTTP = $"http://{GetLocalIpAddress("InterNetwork").FirstOrDefault()}:8080/health", // 健康检查地址    Interval = TimeSpan.FromSeconds(10) // 检查间隔};var serviceId = "goodapi-1"; // 要注销的服务的ID// 注册一个服务var registration = new AgentServiceRegistration(){    ID = serviceId,    Name = "goodapi",    Address = GetLocalIpAddress("InterNetwork").FirstOrDefault(),    Port = 8080,    Check = check};await client.Agent.ServiceDeregister(serviceId);client.Agent.ServiceRegister(registration);var builder = WebApplication.CreateBuilder(args);// Add services to the container.builder.Services.AddControllers();// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbucklebuilder.Services.AddEndpointsApiExplorer();builder.Services.AddSwaggerGen();var app = builder.Build();// Configure the HTTP request pipeline.//if (app.Environment.IsDevelopment()){    app.UseSwagger();    app.UseSwaggerUI();}app.MapControllers();app.MapGet("/health", async context =>{    context.Response.StatusCode = 200;    await context.Response.WriteAsync("health");});app.Run();// 注销服务await client.Agent.ServiceDeregister(serviceId);List<string> GetLocalIpAddress(string netType){    string hostName = Dns.GetHostName();    IPAddress[] addresses = Dns.GetHostAddresses(hostName);    var IPList = new List<string>();    if (netType == string.Empty)    {      for (int i = 0; i < addresses.Length; i++)      {            IPList.Add(addresses.ToString());      }    }    else    {      //AddressFamily.InterNetwork = IPv4,      //AddressFamily.InterNetworkV6= IPv6      for (int i = 0; i < addresses.Length; i++)      {            if (addresses.AddressFamily.ToString() == netType)            {                IPList.Add(addresses.ToString());            }      }    }    return IPList;}加Dockerfile文件

#使用asp.net 6作为基础镜像,起一个别名为baseFROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base#设置容器的工作目录为/appWORKDIR /app#COPY 文件COPY . /appENV ASPNETCORE_ENVIRONMENT Production#设置时区为东八区ENV TZ Asia/Shanghai#启动服务ENTRYPOINT ["dotnet", "GoodApi.dll"]# 运行goodapi项目docker stop goodapidocker rm -f goodapidocker build -t goodapi .docker run --name=goodapi -d -p 8080:8080 --network=adnc_consul goodapi在OcelotGA中加consul配置与代码

加包Consul,Ocelot.Provider.Consul
改ocelot.json配置

{"Routes": [    {      "UseServiceDiscovery": true,      "UpstreamPathTemplate": "/good/{everything}",      "UpstreamHttpMethod": [ "Get" ],      "DownstreamPathTemplate": "/{everything}",      "DownstreamScheme": "http",      "ServiceName": "goodapi",      "LoadBalancerOptions": {      "Type": "LeastConnection"      }    },    {      "UseServiceDiscovery": true,      "UpstreamPathTemplate": "/order/{everything}",      "UpstreamHttpMethod": [ "Get" ],      "DownstreamPathTemplate": "/{everything}",      "DownstreamScheme": "http",      "ServiceName": "orderapi",      "LoadBalancerOptions": {      "Type": "LeastConnection"      }    }],"GlobalConfiguration": {    "BaseUrl": "http://gw.wxy.ink",    "ServiceDiscoveryProvider": {      "Scheme": "http",      "Host": "10.75.174.43", // 这里是您Consul的地址      "Port": 8500, // Consul的端口      "Type": "Consul"    }}}修改Program.cs

using Microsoft.AspNetCore.Builder;using Microsoft.Extensions.DependencyInjection;using Ocelot.DependencyInjection;using Ocelot.Middleware;using Ocelot.Provider.Consul;using System;using System.Collections.Generic;using System.Net;using Consul;using OcelotGA;// 创建Consul客户端var consulAddress = "http://10.75.174.43:8500";// Environment.GetEnvironmentVariable("CONSUL_ADDRESS"); //10.75.174.43var consulUri = new Uri(consulAddress);var client = new ConsulClient(config =>{    config.Address = consulUri;});// 配置服务的健康检查var check = new AgentServiceCheck(){    HTTP = $"http://{GetLocalIpAddress("InterNetwork").FirstOrDefault()}:8080/health", // 健康检查地址    Interval = TimeSpan.FromSeconds(10) // 检查间隔};var serviceId = "gw-1"; // 要注销的服务的ID// 注册一个服务var registration = new AgentServiceRegistration(){    ID = serviceId,    Name = "gw",    Address = GetLocalIpAddress("InterNetwork").FirstOrDefault(),    Port = 8080,    //Check = check};await client.Agent.ServiceDeregister(serviceId);client.Agent.ServiceRegister(registration);var builder = WebApplication.CreateBuilder(args);builder.Configuration.AddJsonFile("ocelot.json", optional: false, reloadOnChange: true);builder.Services.AddOcelot().AddConsul<MyConsulServiceBuilder>(); //这里要注意MyConsulServiceBuildervar app = builder.Build();app.UseOcelot().Wait();app.UseRouting();app.MapGet("/Health", async context =>{    context.Response.StatusCode = 200;    await context.Response.WriteAsync("Health");});app.Run();// 注销服务await client.Agent.ServiceDeregister(serviceId);List<string> GetLocalIpAddress(string netType){    string hostName = Dns.GetHostName();    IPAddress[] addresses = Dns.GetHostAddresses(hostName);    var IPList = new List<string>();    if (netType == string.Empty)    {      for (int i = 0; i < addresses.Length; i++)      {            IPList.Add(addresses.ToString());      }    }    else    {      //AddressFamily.InterNetwork = IPv4,      //AddressFamily.InterNetworkV6= IPv6      for (int i = 0; i < addresses.Length; i++)      {            if (addresses.AddressFamily.ToString() == netType)            {                IPList.Add(addresses.ToString());            }      }    }    return IPList;}添加MyConsulServiceBuilder.cs
using Consul;using Ocelot.Logging;using Ocelot.Provider.Consul;using Ocelot.Provider.Consul.Interfaces;namespace OcelotGA{    public class MyConsulServiceBuilder : DefaultConsulServiceBuilder    {      public MyConsulServiceBuilder(IHttpContextAccessor contextAccessor, IConsulClientFactory clientFactory, IOcelotLoggerFactory loggerFactory)            : base(contextAccessor, clientFactory, loggerFactory) { }      // I want to use the agent service IP address as the downstream hostname      protected override string GetDownstreamHost(ServiceEntry entry, Node node)            => entry.Service.Address;    }}运行网关项目

我们访问gw.wxy.ink/good/health

爬坑记录

Program.cs中的
builder.Services.AddOcelot().AddConsul<MyConsulServiceBuilder>(); //这里要注意MyConsulServiceBuilder若为builder.Services.AddOcelot().AddConsul();则会出现下面问题

服务解析出来是node的名称,而非服务的IP
解决方法:Service Discovery — Ocelot Gateway 23.4 documentation


就是说默认的DefaultConsulServiceBuilder会这样处理
protected virtual string GetDownstreamHost(ServiceEntry entry, Node node)    => node != null ? node.Name : entry.Service.Address;而我们需要的是
protected override string GetDownstreamHost(ServiceEntry entry, Node node)      => entry.Service.Address;作者

吴晓阳(手机:13736969112微信同号)
页: [1]
查看完整版本: Ocelot集成Consul实现api网关与服务发现