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

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

介绍

微服务中有关键的几项技术,其中网关和服务服务发现,服务注册相辅相成。

首先解释几个本次教程中需要的术语

网关 Gateway(API GW / API 网关),顾名思义,是企业 IT 在系统边界上提供给外部访问内部接口服务的统一入口,简化了外部由于多服务协同完成任务时的繁琐配置。网关组件有Kong,ocelot,

服务发现:通过网关访问内部各个微服务,网关要找到所需服务的过程称为服务发现

服务注册:既然有服务发现,前提是要把所需服务提前“录入”,这个录入的过程称为服务注册。服务注册可配置文件(人肉方式不推荐),也可用服务注册组件如Consul或者Eureka等等(推荐)

搭建Consul集群(Windows)

官网下载Consul程序,https://www.consul.io/downloads.html

下载下来就是一个可执行文件Consul.exe

Consul有两种代理模式,一种server,一种client,官方建议Server端达到3台以上才可高可用,但不要太多,太多会给集群间数据同步造成压力,client数量不限。

多个server端之间会选择出一个leader,当一个server的leader宕机则会从其他server端”投票“选择新的leader

实践

这里server我们用2台实验

192.168.74.55

192.168.74.54

1台Client

192.168.74.161

consul启动有两种方式一种是命令行,一种是配置文件的方式。

命令行方式启动一个consul的server端

consul agent -server -ui -bootstrap-expect 2 -data-dir opt/consul/data -node ServerMaster -bind 192.168.74.55 -client 192.168.74.55

关键参数说明

-server:server模式启动

-ui :开启ui界面(consul.exe内部带了GUI图形界面操作)

-bootstrap-expect 2:server端到2个时集群生效

-data-dir:consul产生的文件路径(consul自己会产生一下数据存储的位置)

-node:此节点名称

-bind:集群内部通信地址,默认0.0.0.0

-client:此节点绑定的通讯地址

以上只是关键参数,以下是完整参数说明:

但是命令启动很繁琐,所以推荐下面的配置文件的方式启动

在consul同文件夹下建立一个server.json的配置文件

{
  "datacenter": "dc1",
  "data_dir": "opt/consul/data",
  "node_name": "consul-server01",
  "server": true,
  "bootstrap_expect": 2,
  "bind_addr": "192.168.74.55",
  "client_addr": "192.168.74.55",
  "ui":true
}

为了快速启动,再建立一个bat批处理文件runconsul.bat

consul agent -config-dir server.json
pause

双击runconsul.bat启动consul

在192.168.74.54服务器开启一个server端继续以上操作。

命令方式启动

consul agent -server -ui -data-dir opt/consul/data -node Server01 -bind 192.168.74.54 -client 192.168.74.54 -join=192.168.74.55

-join将192.168.74.54加入到192.168.74.55服务器

配置文件方式:

{
  "datacenter": "dc1",
  "data_dir": "opt/consul/data",
  "node_name": "consul-server2",
  "server": true,
  "bind_addr": "192.168.74.54",
  "client_addr": "192.168.74.54",
  "ui":true,
  "retry_join": ["192.168.74.55"],
  "retry_interval": "30s",
  "rejoin_after_leave": true,
  "start_join":["192.168.74.55"]
  }

在192.168.74.161服务器开启一个consul的client端

命令方式:

consul agent -ui -data-dir opt/consul/data -node ServerSlave  -bind 192.168.74.161 -client 192.168.74.161 -join 192.168.74.55

配置文件方式:

{
  "datacenter": "dc1",
  "data_dir": "opt/consul/data",
  "node_name": "consul-client01",
  "server": false,
  "bind_addr": "192.168.74.161",
  "client_addr": "192.168.74.161",
  "ui":true,
  "retry_join": ["192.168.74.55"],
  "retry_interval": "30s",
  "rejoin_after_leave": true,
  "start_join":["192.168.74.55"]
}

效果

简单Consul集群到这里就搭建成功,只要访问三台服务器任意一个都可数据同步,演示:

netcore集成Consul服务注册

服务注册关键代码

首先新建一个ConsulClient的类库

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.cs

using 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.cs

using 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/lonelyxmas/p/10223140.html

时间: 2024-11-29 11:27:38

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

8分钟学会Consul集群搭建及微服务概念

原文:8分钟学会Consul集群搭建及微服务概念 Consul介绍: Consul 是由 HashiCorp 公司推出的开源软件,用于实现分布式系统的服务发现与配置.与其他分布式服务注册与发现的方案,Consul 的方案更“一站式”,内置了服务注册与发现框 架.分布一致性协议实现.健康检查.Key/Value 存储.多数据中心方案,不再需要依赖其他工具(比如 ZooKeeper 等),使用起来也较为简单. Consul的如何实现的? Consul 用 Golang 实现,因此具有天然可移植性(支

服务发现之美:Consul集群搭建

近几年随着Docker容器技术.微服务等架构的兴起,人们开始意识到服务发现的必要性.微服务架构简单来说,是一种以一些微服务来替代开发单个大而全应用的方法, 每一个小服务运行在自己的进程里,并以轻量级的机制来通信, 通常是 HTTP RESTful API.微服务强调小快灵, 任何一个相对独立的功能服务不再是一个模块, 而是一个独立的服务.那么,当我们需要访问这个服务时,如何确定它的地址呢?这时就需要服务发现了. Consul 是 HashiCorp 公司推出的开源工具,用于实现分布式系统的服务发

使用keepalived搭建高可用的LVS-DR集群

使用keepalived搭建高可用的LVS-DR集群   一:Keepalived服务概述 keepalived 是一个类似于 layer3, 4 & 5 交换机制的软件,也就是我们平时说的第 3 层.第 4 层和第 5层交换. Keepalived 的作用是检测 web 服务器的状态,如果有一台 web 服务器死机,戒工作出现故障,Keepalived 将检测到,并将有故障的 web 服务器从系统中剔除,当 web 服务器工作正常后 Keepalived 自劢将web 服务器加入到服务器群中,

实战中的asp.net core结合Consul集群&amp;Docker实现服务治理

0.目录 整体架构目录:ASP.NET Core分布式项目实战-目录 一.前言 在写这篇文章之前,我看了很多关于consul的服务治理,但发现基本上都是直接在powershell或者以命令工具的方式在服务器上面直接输入consul agent .... 来搭建启动consul集群,一旦把命令工具关掉,则consul无法再后台启动,尤其是在linux系统中. 如果在window系统中,采用bat文件到时可以做成开机自启,或者在linux中把命令做成一个service 服务文件来启动就可以实现后台运

部署AlwaysOn第一步:搭建Windows服务器故障转移集群

在Windows Server 2012 R2 DataCenter 环境中搭建集群之前,首先要对Windows服务器故障转移集群(Windows Server Failover Cluster,简称WSFC)有基本的了解.WSFC必须部署在域管理环境中,由多台服务器组成,每台服务器称作一个"结点"(Node),每个结点上都运行了Windows服务器故障转移集群服务,整个集群系统允许部分结点掉线.故障或损坏而不影响整个系统的正常运作.集群自动检测结点的健康状态,一旦活跃结点发生异常,变

基于keepalived搭建MySQL的高可用集群

http://www.cnblogs.com/ivictor/p/5522383.html 基于keepalived搭建MySQL的高可用集群 MySQL的高可用方案一般有如下几种: keepalived+双主,MHA,MMM,Heartbeat+DRBD,PXC,Galera Cluster 比较常用的是keepalived+双主,MHA和PXC. 对于小公司,一般推荐使用keepalived+双主,简单. 下面来部署一下 配置环境: 角色                          

Nginx+Keepalived搭建高可用负载均衡集群

Nginx+Keepalived搭建高可用负载均衡集群   一. 环境说明 前端双Nginx+keepalived,nginx反向代理到后端的tomcat集群实现负载均衡,Keepalived实现集群高可用. 操作系统: Centos 6.6_X64 Nginx版本: nginx-1.9.5 Keepalived版本:keepalived-1.2.13 结构: Keepalived+nginx-MASTER:10.6.1.210         Keepalived+nginx-BACKUP:

使用Nginx1.9.9+Keepalived1.2.x搭建高可用负载均衡集群

一 简介以及原理介绍 (1)Nginx概念介绍: Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like 协议下发行.由俄罗斯的程序设计师Igor Sysoev所开发.其特点是占有内存少,并发能力强,事实上nginx的并发能力确实在同类型的网页服务器中表现较好,中国大陆使用nginx网站用户有:百度.京东.新浪.网易.腾讯.淘宝等 (2)Keepalived概念介绍: Keepalived的作用是检测服务器的状态,如果有一台we

搭建高性能Jboss负载均衡集群

负载均衡集群是由两台或者两台以上的服务器组成.分为前端负载调度和后端服务两个部分.负载调度部分负载把客户端的请求按照不同的策略分配给后端服务节点,而后端节点是真正提供营养程序服务的部分.与双机热备不同的是,负载均衡集群中,所有的后端节点都处于活动动态,它们都对外提供服务,分摊系统的工作负载. 负载均衡集群可以把一个高负荷的应用分散到多个节点共同完成,适用于业务繁忙.大负荷访问的应用系统.负载均衡集群的一大优点除了将大负荷进行分摊解决性能问题之外,他还有极强的出错互补机制,每一个提供服务的节点在出