.NET微服务从0到1:服务注册与发现(Consul)
Consul搭建
基于Docker搭建Consul
以下为单机环境构建脚本,用于本机测试,生产环境中应当进行集群搭建
version: '3'
services:
consul:
image: consul:1.7.1
container_name: consul
volumes:
- /c/docker/consul/data:/consul/data
- /c/docker/consul:/consul/config
ports:
- 8300:8300
- 8301:8301
- 8301:8301/udp
- 8302:8302
- 8302:8302/udp
- 8400:8400
- 8500:8500
- 53:53/udp
command: agent -server -bind=0.0.0.0 -client=0.0.0.0 -node=consul_Server1 -bootstrap-expect=1 -ui
成功搭建后,访问8500端口,你可以看到如下界面
基于Windows搭建Consul
点击下载Consul
执行以下命令运行consul
consul agent -dev
ServiceA集成Consul做服务注册
配置前一篇文章中的ServiceA
Install-Package Consul -Version 0.7.2.6
- Consul配置模型
public class ServiceDisvoveryOptions
{
public string ServiceName { get; set; }
public ConsulOptions Consul { get; set; }
}
public class ConsulOptions
{
public string HttpEndpoint { get; set; }
public DnsEndpoint DnsEndpoint { get; set; }
}
public class DnsEndpoint
{
public string Address { get; set; }
public int Port { get; set; }
public IPEndPoint ToIPEndPoint()
{
return new IPEndPoint(IPAddress.Parse(Address), Port);
}
}
- 添加appsetting.json
"ServiceDiscovery": {
"ServiceName": "ServiceA",
"Consul": {
"HttpEndpoint": "http://127.0.0.1:8500",
"DnsEndpoint": {
"Address": "127.0.0.1",
"Port": 8600
}
}
}
- Consul服务注册实现
private void ConfigureConsul(IApplicationBuilder app, IOptions<ServiceDisvoveryOptions> serviceOptions, IConsulClient consul, IHostApplicationLifetime lifetime)
{
var features = app.Properties["server.Features"] as FeatureCollection;
var addresses = features.Get<IServerAddressesFeature>()
.Addresses
.Select(p => new Uri(p));
foreach (var address in addresses)
{
var serviceId = $"{serviceOptions.Value.ServiceName}_{address.Host}:{address.Port}";
var httpCheck = new AgentServiceCheck()
{
DeregisterCriticalServiceAfter = TimeSpan.FromMinutes(1),
Interval = TimeSpan.FromSeconds(30),
HTTP = new Uri(address, "health").OriginalString
};
var registration = new AgentServiceRegistration()
{
Checks = new[] { httpCheck },
Address = address.Host,
ID = serviceId,
Name = serviceOptions.Value.ServiceName,
Port = address.Port
};
consul.Agent.ServiceRegister(registration).GetAwaiter().GetResult();
lifetime.ApplicationStopping.Register(() =>
{
consul.Agent.ServiceDeregister(serviceId).GetAwaiter().GetResult();
});
}
}
- 配置服务到DI容器
public void ConfigureServices(IServiceCollection services)
{
services.AddOptions();
services.Configure<ServiceDisvoveryOptions>(Configuration.GetSection("ServiceDiscovery"));
services.AddSingleton<IConsulClient>(p => new ConsulClient(cfg =>
{
var serviceConfiguration = p.GetRequiredService<IOptions<ServiceDisvoveryOptions>>().Value;
if (!string.IsNullOrEmpty(serviceConfiguration.Consul.HttpEndpoint))
{
// if not configured, the client will use the default value "127.0.0.1:8500"
cfg.Address = new Uri(serviceConfiguration.Consul.HttpEndpoint);
}
}));
services.AddHealthChecks();
services.AddControllers();
}
- 将Consul相关配置添加到管道
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IOptions<ServiceDisvoveryOptions> serviceDisvoveryOptions, IConsulClient consul, IHostApplicationLifetime lifetime)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseAuthorization();
ConfigureConsul(app, serviceDisvoveryOptions, consul, lifetime);
app.UseHealthChecks("/health");
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
- 运行ServiceA
可以看到健康检查已通过,并且服务ServiceA已成功注册到Consul
Ocelot集成Consul做服务发现
安装nuget包依赖
Install-Package Ocelot.Provider.Consul -Version 14.0.11
在上一篇文章的基础上,我们先修改ocelot.json
删除了ServiceA路由中的DownstreamHostAndPorts写死的地址和端口,改为使用Consul服务发现
{
"ReRoutes": [
{
"DownstreamPathTemplate": "/{url}",
"DownstreamScheme": "http",
"UpstreamPathTemplate": "/service-a/{url}",
"UpstreamHttpMethod": [ "Get", "Post" ],
"AuthenticationOptions": {
"AuthenticationProviderKey": "SampleKey",
"AllowedScopes": [ "gateway_api" ]
},
"ServiceName": "ServiceA",
"LoadBalancerOptions": {
"Type": "LeastConnection"
}
}
],
"GlobalConfiguration": {
"BaseUrl": "http://localhost",
"ServiceDiscoveryProvider": {
"Host": "localhost",
"Port": 8500,
"Type": "Consul"
}
}
}
向容器中添加Consul服务
public void ConfigureServices(IServiceCollection services)
{
services.AddOcelot()
.AddConsul();
}
启动各个服务,查看结果
可以看到已成功执行
更多参考
Consul
Service Discovery And Health Checks In ASP.NET Core With Consul