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]