ConsulRegister.csproj所需组件如下:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netstandard2.0</TargetFramework> </PropertyGroup> <ItemGroup> <PackageReference Include="Consul" Version="0.7.2.6" /> <PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="2.1.0" /> <PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.1.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="2.1.0" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="2.1.0" /> <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.1.0" /> </ItemGroup></Project>
ServiceDiscoveryOptions.csusing System;using System.Collections.Generic;using System.Text;namespace ConsulRegister
{ /// <summary>
/// 服务治理第三方组件Consul相关配置参数 /// </summary>
public class ServiceDiscoveryOptions
{ public string ServiceName { get; set; } public ConsulOptions Consul { get; set; }
} public class ConsulOptions
{ public string HttpEndPoint { get; set; }
}
}RegisterToConsulExtension.csusing Consul;using Microsoft.AspNetCore.Builder;using Microsoft.AspNetCore.Hosting;using Microsoft.AspNetCore.Hosting.Server.Features;using Microsoft.AspNetCore.Http;using Microsoft.AspNetCore.Http.Features;using Microsoft.Extensions.Configuration;using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Options;using System;using System.Linq;using System.Net;using System.Net.NetworkInformation;using System.Net.Sockets;namespace ConsulRegister
{ public static class RegisterToConsulExtension
{ /// <summary>
/// Add Consul /// 添加consul /// </summary>
/// <param name="services"></param>
/// <param name="configuration"></param>
/// <returns></returns>
public static IServiceCollection AddConsul(this IServiceCollection services, IConfiguration configuration)
{ // configuration Consul register address //配置consul注册地址
services.Configure<ServiceDiscoveryOptions>(configuration.GetSection("ServiceDiscovery"));
//configuration Consul client //配置consul客户端
services.AddSingleton<IConsulClient>(sp => new Consul.ConsulClient(config =>
{ var consulOptions = sp.GetRequiredService<IOptions<ServiceDiscoveryOptions>>().Value; if (!string.IsNullOrWhiteSpace(consulOptions.Consul.HttpEndPoint))
{
config.Address = new Uri(consulOptions.Consul.HttpEndPoint);
}
})); return services;
} /// <summary>
/// use Consul /// 使用consul /// The default health check interface format is http://host:port/HealthCheck /// 默认的健康检查接口格式是 http://host:port/HealthCheck /// </summary>
/// <param name="app"></param>
/// <returns></returns>
public static IApplicationBuilder UseConsul(this IApplicationBuilder app)
{
IConsulClient consul = app.ApplicationServices.GetRequiredService<IConsulClient>();
IApplicationLifetime appLife = app.ApplicationServices.GetRequiredService<IApplicationLifetime>();
IOptions<ServiceDiscoveryOptions> serviceOptions = app.ApplicationServices.GetRequiredService<IOptions<ServiceDiscoveryOptions>>(); var features = app.Properties["server.Features"] as FeatureCollection; var port = new Uri(features.Get<IServerAddressesFeature>()
.Addresses
.FirstOrDefault()).Port;
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine($"application port is :{port}"); var addressIpv4Hosts = NetworkInterface.GetAllNetworkInterfaces()
.OrderByDescending(c => c.Speed)
.Where(c => c.NetworkInterfaceType != NetworkInterfaceType.Loopback && c.OperationalStatus == OperationalStatus.Up); foreach (var item in addressIpv4Hosts)
{ var props = item.GetIPProperties(); //this is ip for ipv4 //这是ipv4的ip地址
var firstIpV4Address = props.UnicastAddresses
.Where(c => c.Address.AddressFamily == AddressFamily.InterNetwork)
.Select(c => c.Address)
.FirstOrDefault().ToString(); var serviceId = $"{serviceOptions.Value.ServiceName}_{firstIpV4Address}:{port}"; var httpCheck = new AgentServiceCheck()
{
DeregisterCriticalServiceAfter = TimeSpan.FromMinutes(1),
Interval = TimeSpan.FromSeconds(30), //this is default health check interface //这个是默认健康检查接口
HTTP = $"{Uri.UriSchemeHttp}://{firstIpV4Address}:{port}/HealthCheck",
}; var registration = new AgentServiceRegistration()
{
Checks = new[] { httpCheck },
Address = firstIpV4Address.ToString(),
ID = serviceId,
Name = serviceOptions.Value.ServiceName,
Port = port
};
consul.Agent.ServiceRegister(registration).GetAwaiter().GetResult();
//send consul request after service stop //当服务停止后想consul发送的请求
appLife.ApplicationStopping.Register(() =>
{
consul.Agent.ServiceDeregister(serviceId).GetAwaiter().GetResult();
});
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine($"health check service:{httpCheck.HTTP}");
} //register localhost address //注册本地地址
var localhostregistration = new AgentServiceRegistration()
{
Checks = new[] { new AgentServiceCheck()
{
DeregisterCriticalServiceAfter = TimeSpan.FromMinutes(1),
Interval = TimeSpan.FromSeconds(30),
HTTP = $"{Uri.UriSchemeHttp}://localhost:{port}/HealthCheck",
} },
Address = "localhost",
ID = $"{serviceOptions.Value.ServiceName}_localhost:{port}",
Name = serviceOptions.Value.ServiceName,
Port = port
};
consul.Agent.ServiceRegister(localhostregistration).GetAwaiter().GetResult(); //send consul request after service stop //当服务停止后想consul发送的请求
appLife.ApplicationStopping.Register(() =>
{
consul.Agent.ServiceDeregister(localhostregistration.ID).GetAwaiter().GetResult();
});
app.Map("/HealthCheck", s =>
{
s.Run(async context =>
{ await context.Response.WriteAsync("ok");
});
}); return app;
}
}
}再新建一个.netcore的webapi项目WebA,并且引用ConsulRegister项目
在WebA项目中的Startup.cs文件中加入Consul服务
public void ConfigureServices(IServiceCollection services)
{ services.AddConsul(Configuration);
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
} // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{ if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
} app.UseConsul();
app.UseMvc();
}在WebA项目的appsettings.json配置文件中加入以下Consul服务端配置
{ "Logging": { "LogLevel": { "Default": "Warning"
}
}, "AllowedHosts": "*",
"ServiceDiscovery": { "ServiceName": "A", "Consul": { "HttpEndpoint": "http://192.168.74.161:8500"
}
}
}这里服务注册就算完成
Ocelot网关搭建
接下来继续Ocelot借助于Consul实现服务发现
新建项目Ocelot.Gateway

将以下依赖加入Ocelot.Gateway.csproj中:
<Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFramework>netcoreapp2.1</TargetFramework> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.AspNetCore.App" /> <PackageReference Include="Ocelot" Version="12.0.1" /> <PackageReference Include="Ocelot.Provider.Consul" Version="0.1.2" /> </ItemGroup> <ItemGroup> <Content Update="ocelot.json"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> </ItemGroup></Project>
新建ocelot.json文件
{ "ReRoutes": [
{ "UseServiceDiscovery": true,
"DownstreamPathTemplate": "/{url}", "DownstreamScheme": "http", "ServiceName": "A", "LoadBalancerOptions": { "Type": "RoundRobin"
}, "UpstreamPathTemplate": "/a/{url}", "UpstreamHttpMethod": [ "Get", "Post" ], "ReRoutesCaseSensitive": false
}
], "GlobalConfiguration": { // 使用Consul服务治理
"ServiceDiscoveryProvider": { "Host": "192.168.74.161", "Port": 8500, "ConfigurationKey": "Oceolot_A" //存储在Consul上的Key }
}
}修改Startup.cs文件如下:
public class Startup
{ public Startup(IConfiguration configuration)
{
Configuration = configuration;
} public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddOcelot( new ConfigurationBuilder()
.AddJsonFile("ocelot.json", optional: false, reloadOnChange: true).Build())
.AddConsul()
.AddConfigStoredInConsul();
} // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{ if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
} else
{
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseOcelot().Wait();
}
}发布WebA后复制两份分别启动
dotnet WebA.dll --urls="http://0.0.0.0:2001"
dotnet WebA.dll --urls="http://0.0.0.0:2002"
到这里相当于2001和2002程序简单集群了一下
可以发现日志中有 http://192.168.74.161:2002/HealthCheck调用信息:

这其实是consul进行健康检查进行的调用。
启动多个程序后,打开浏览器打开Consuld界面会发现注册了两个服务



这里ocelot网关和consul的服务注册和发现就算初步集成。
如果生成环境是windows的情况,将consul做成windwos服务即可
sc create "ConsulServer" binPath="F:\XXX\consul.exe agent -config-dir XXX.json"
生产环境是linux则借助systemd做成守护进程即可
目前集群搭建成功,但是连接的话如果指定某个端点的ip进行连接,端点宕机,就会导致网关一样无法连接consul进行服务发现。所以还需进行配置暴露一个端点让客户端连接,配置详情:https://www.consul.io/docs/connect/configuration.html
不过也可以做成虚拟ip进行多台consul的负载。客户端连接虚拟ip即可
项目地址:
https://github.com/liuyl1992/Ocelot.GatewayToConsul

随时随地看视频