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

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: 本文介绍了如何在.NET微服务架构中集成API网关Ocelot和Consul服务发现。首先通过Docker安装并配置Consul,接着在GoodApi项目中实现服务的自动注册与注销,并配置健康检查。然后,通过修改Ocelot的配置文件`ocelot.json`和`Program.cs`,实现基于Consul的服务发现,确保API请求能够正确路由到后端服务。最后,解决了服务解析时可能出现的问题,确保服务的IP地址而非节点名称被正确解析。

前言

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

安装consul

#自定义网络,自定义网络可以指定容器IP,这样服务器重启consul集群也可以正常运行。
docker network create --driver bridge --subnet=172.21.0.0/16 --gateway=172.21.0.16 adnc_consul

docker 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.43
var 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/swashbuckle
builder.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[i].ToString());
        }
    }
    else
    {
        //AddressFamily.InterNetwork = IPv4,
        //AddressFamily.InterNetworkV6= IPv6
        for (int i = 0; i < addresses.Length; i++)
        {
            if (addresses[i].AddressFamily.ToString() == netType)
            {
                IPList.Add(addresses[i].ToString());
            }
        }
    }
    return IPList;
}

加Dockerfile文件

#使用asp.net 6作为基础镜像,起一个别名为base
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
#设置容器的工作目录为/app
WORKDIR /app
#COPY 文件
COPY . /app
ENV ASPNETCORE_ENVIRONMENT Production

#设置时区为东八区
ENV TZ Asia/Shanghai
#启动服务
ENTRYPOINT ["dotnet", "GoodApi.dll"]
# 运行goodapi项目
docker stop goodapi
docker rm -f goodapi
docker 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.43
var 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>(); //这里要注意MyConsulServiceBuilder

var 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[i].ToString());
        }
    }
    else
    {
   
        //AddressFamily.InterNetwork = IPv4,
        //AddressFamily.InterNetworkV6= IPv6
        for (int i = 0; i < addresses.Length; i++)
        {
   
            if (addresses[i].AddressFamily.ToString() == netType)
            {
   
                IPList.Add(addresses[i].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微信同号)

目录
相关文章
SpringCloud+Consul配置Zuul网关服务
SpringCloud+Consul配置Zuul网关服务
224 0
|
3月前
|
负载均衡 监控 API
dotnet微服务之API网关Ocelot
Ocelot 是一个基于 .NET 的 API 网关,适用于微服务架构。本文介绍了如何创建一个 Web API 项目并使用 Ocelot 进行 API 请求路由、负载均衡等。通过配置 `ocelot.json` 和修改 `Program.cs`,实现对 `GoodApi` 和 `OrderApi` 两个项目的路由管理。最终,通过访问 `https://localhost:7122/good/Hello` 和 `https://localhost:7122/order/Hello` 验证配置成功。
59 1
dotnet微服务之API网关Ocelot
|
9月前
|
负载均衡 Java 网络架构
在SpringCloud2023中快速集成SpringCloudGateway网关
本文主要简单介绍SpringCloud2023实战中SpringCoudGateway的搭建。后续的文章将会介绍在微服务中使用熔断Sentinel、鉴权OAuth2、SSO等技术。
189 2
在SpringCloud2023中快速集成SpringCloudGateway网关
EMQ
|
9月前
|
存储 NoSQL API
EMQX Enterprise 5.4 发布:OpenTelemetry 分布式追踪、OCPP 网关、Confluent 集成支持
新版本提供 OpenTelemetry 分布式追踪与日志集成功能,新增了开放充电协议 OCPP 协议接入能力,并为数据集成添加了 Confluent 支持。此外,新版本还进行了多项改进以及 BUG 修复,进一步提升了整体性能和稳定性。
EMQ
1229 14
EMQX Enterprise 5.4 发布:OpenTelemetry 分布式追踪、OCPP 网关、Confluent 集成支持
|
9月前
|
负载均衡 监控 Kubernetes
构建高效微服务架构:API网关与服务发现的融合实践
【5月更文挑战第29天】 在当今的软件开发领域,微服务架构已成为一种流行的设计模式,其通过将应用程序拆分为一系列小型、自治的服务来提供灵活性和可扩展性。然而,随着服务数量的增加,确保通信效率和管理便捷性成为了关键挑战。本文聚焦于如何通过API网关和服务发现机制的有效整合,优化微服务间的交互,提高系统整体性能和可靠性。我们将探讨API网关在请求路由、负载均衡、安全性增强方面的作用,同时分析服务发现对于实现服务间动态通信的重要性,并展示两者如何协同工作以支持复杂的后端系统需求。
|
9月前
|
负载均衡 监控 API
构建高效微服务架构:API网关与服务发现的融合实践
【5月更文挑战第29天】 在微服务架构中,服务的分布式特性要求精确的服务发现机制和灵活的流量控制手段。本文将探讨如何通过合并API网关和服务发现功能来优化后端服务的通信效率,降低延迟,并提升系统的可伸缩性。我们将分析传统模式下两者独立运作的弊端,并提出一种集成方案,该方案不仅能够简化系统架构,还能增强服务的自愈能力。文章还将讨论实施过程中可能遇到的挑战及相应的解决策略。
|
Java API Sentinel
微服务 过滤器 集成Sentinel实现网关限流
微服务 过滤器 集成Sentinel实现网关限流
373 0
|
监控 负载均衡 安全
手把手教你搭建SpringCloud项目(十三 )集成Gateway新一代服务网关
手把手教你搭建SpringCloud项目(十三 )集成Gateway新一代服务网关
339 0
|
8天前
|
API PHP 开发者
速卖通商品详情接口(速卖通API系列)
速卖通(AliExpress)是阿里巴巴旗下的跨境电商平台,提供丰富的商品数据。通过速卖通开放平台(AliExpress Open API),开发者可获取商品详情、订单管理等数据。主要功能包括商品搜索、商品详情、订单管理和数据报告。商品详情接口aliexpress.affiliate.productdetail.get用于获取商品标题、价格、图片等详细信息。开发者需注册账号并创建应用以获取App Key和App Secret,使用PHP等语言调用API。该接口支持多种请求参数和返回字段,方便集成到各类电商应用中。
|
6天前
|
JSON 前端开发 API
以项目登录接口为例-大前端之开发postman请求接口带token的请求测试-前端开发必学之一-如果要学会联调接口而不是纯写静态前端页面-这个是必学-本文以优雅草蜻蜓Q系统API为实践来演示我们如何带token请求接口-优雅草卓伊凡
以项目登录接口为例-大前端之开发postman请求接口带token的请求测试-前端开发必学之一-如果要学会联调接口而不是纯写静态前端页面-这个是必学-本文以优雅草蜻蜓Q系统API为实践来演示我们如何带token请求接口-优雅草卓伊凡
29 5
以项目登录接口为例-大前端之开发postman请求接口带token的请求测试-前端开发必学之一-如果要学会联调接口而不是纯写静态前端页面-这个是必学-本文以优雅草蜻蜓Q系统API为实践来演示我们如何带token请求接口-优雅草卓伊凡

热门文章

最新文章