35

.NET微服务从0到1:服务注册与发现(Consul)

 4 years ago
source link: http://www.cnblogs.com/zhaobingwang/p/12442398.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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端口,你可以看到如下界面

NrAFBff.png!web

基于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

    byuemaA.png!web

    可以看到健康检查已通过,并且服务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();
}

启动各个服务,查看结果

nU7FnuA.png!web

可以看到已成功执行

更多参考


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK