.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

posted @ 2020-03-08 14:06  江浙沪柯蓝  阅读(1818)  评论(0编辑  收藏  举报