继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

微服务之:从零搭建ocelot网关和consul集群

湖上湖
关注TA
已关注
手记 276
粉丝 85
获赞 377

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

原文出处:https://www.cnblogs.com/xiaoliangge/p/10221950.html  

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP