为了让网关更好地了解内部服务的情况,我们需要服务发现组件,如:Consul。
Consul 的安装与运行
选择下载后,解压,确定里面的 exe 文件名为 consul.exe
如果不是,请修改成 consul.exe。
然后将 consul.exe 剪切到 D:cmd 中,至于为什么请,请看
打开 cmd 输入命令 consul version,显示版本号,则说明安装成功~1
2> consul version
Consul v1.4.2
然后继续输入以下命令启动 Consul,这里不解释命令各个参数的意义,
把注意力集中用于理解 Consul 和 Ocelot 是怎么配合运作的。1> consul agent -server -bootstrap-expect=1 -data-dir=/tmp/consul -node=s1 -bind=127.0.0.1 -ui
在浏览器中输入:http://127.0.0.1:8500
如果能成功浏览则说明成功启动 consul,
内容大约如下:
| Service | Health Checks | Tag |
| ——- | ————- | — |
| consul | √ 1 | |
如果不能访问,那么很大可能是 8500 端口被其中程序占用了。
可以使用 netstat -ano 命令查看哪个程序占用了 8500 ,将程序关闭之。
服务注册
使用 NuGet 给 Catalog 项目,添加 Consul。
然后将 Catalog 项目的 Startup.cs 修改成内容如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Consul;
namespace
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
// Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env
, IApplicationLifetime lifetime)
{
RegisterService(lifetime);
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc();
}
private void SetRuntimeIpAndPort(ref string ip, ref int port)
{
var server_urls = Configuration["server.urls"]
.Replace("http://", string.Empty)
.Split(":");
ip = server_urls[0];
port = int.Parse(server_urls[1]);
}
private void RegisterService(IApplicationLifetime appLifetime)
{
string serviceIp = string.Empty;
int servicePort = 80;
// 从命令行中获取程序运行时的地址与端口
// 这里只是为了演示方便,实际写到配置文件或环境变量中会比较好
SetRuntimeIpAndPort(ref serviceIp, ref servicePort);
string serviceId = "CatalogApi_" + Guid.NewGuid();//服务编号保证不重复
string serviceName = "CatalogService";
var client = new ConsulClient(ConfigurationOverview); //回调获取
var result = client.Agent.ServiceRegister(new AgentServiceRegistration()
{
ID = serviceId,
Name = serviceName,
Address = serviceIp,
Port = servicePort,
Check = new AgentServiceCheck //健康检查
{
DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服务启动多久后反注册
Interval = TimeSpan.FromSeconds(10),//健康检查时间间隔
HTTP = $"http://{serviceIp}:{servicePort}/api/Health",//健康检查地址
Timeout = TimeSpan.FromSeconds(5)
}
});
appLifetime.ApplicationStopping.Register(() =>
{
Console.WriteLine("注销方法");
client.Agent.ServiceDeregister(serviceId).Wait();//服务停止时取消注册
});
}
private static void ConfigurationOverview(ConsulClientConfiguration obj)
{
//consul的地址
obj.Address = new Uri("http://127.0.0.1:8500");
//数据中心命名
obj.Datacenter = "dc1";
}
}
}
在 Catalog 项目下的 Controllers 下创建 HealthController.cs,
然后将其内容修改成如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
namespace Catalog.Controllers
{
// 用于被 Consul 的检查服务是否健康
[]
[Route("api/Health")]
public class HealthController : Controller
{
[HttpGet]
public IActionResult Get()=> Ok("ok");
}
}
编译 Catalog 项目,
打开一个新的 cmd ,cd 到 Catalog.ddl 所在的目录路径。
路径大约:xxxeShopCatalogbinDebugnetcoreapp2.11
2
3
4
5> dotnet catalog.dll --server.urls "http://127.0.0.1:8001"
...
Now listening on: http://127.0.0.1:8001
Application started. Press Ctrl+C to shut down.
1["value from Catalog","http://127.0.0.1:8001/api/values"]
说明我们的服务已经正常运行了~
在浏览器中输入:http://127.0.0.1:8500
可以看到服务已经注册到 consul 中了ServiceHealth ChecksTagCatalogService√ 2
consul√ 1
Ocelot 与 Consul
使用 NuGet 给 OcelotGateWay 项目,添加 Ocelot.Provider.Consul。
修改 OcelotGateWay 项目的 ocelot.json,内容如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28{
"ReRoutes": [
{
"DownstreamPathTemplate": "/api/{everything}",
"DownstreamScheme": "http",
"UpstreamPathTemplate": "/catalog/{everything}",
"UpstreamHttpMethod": [ "Get", "Post" ],
"UseServiceDiscovery": true,
"ServiceName": "CatalogService",
"LoadBalancerOptions": {
"Type": "RoundRobin"
}
},
{
"DownstreamPathTemplate": "/api/{everything}",
"DownstreamScheme": "http",
"UpstreamPathTemplate": "/order/{everything}",
"UpstreamHttpMethod": [ "Get", "Post" ],
"UseServiceDiscovery": true,
"ServiceName": "OrderingApiServer",
"LoadBalancerOptions": {
"Type": "RoundRobin"
}
}
],
"GlobalConfiguration": {
}
}
特别说明:
"UseServiceDiscovery": true, : 使用服务发现。
"ServiceName": "CatalogService", : 服务的名称一定要对应上。
GlobalConfiguration 中什么都没有配置,是因为 Ocelot 默认使用 Consul。
修改 OcelotGateWay 项目的 Program.cs,内容如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection;
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
using Ocelot.Provider.Consul; // 新增
namespace OcelotGateWay
{
public class Program
{
public static void Main(string[] args)
{
new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureAppConfiguration((hostingContext, config) =>
{
config
.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath)
.AddJsonFile("appsettings.json", true, true)
.AddJsonFile("ocelot.json") // 加载 Ocelot 配置
.AddEnvironmentVariables();
})
.ConfigureServices(s => {
s.AddOcelot()
.AddConsul(); // 新增
})
.ConfigureLogging((hostingContext, logging) =>
{
//add your logging
})
.Configure(app =>
{
app.UseOcelot().Wait();
})
.Build()
.Run();
}
//public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
// WebHost.CreateDefaultBuilder(args)
// .UseStartup();
}
}
将 OcelotGateWay 设为启动项目,按 F5 运行我们的网关~
在浏览器中输入:http://localhost:7000/catalog/values
可以看到:1["value from Catalog","http://127.0.0.1:8001/api/values"]
打开一个新的 cmd ,cd 到 Catalog.ddl 所在的目录路径。
路径大约:xxxeShopCatalogbinDebugnetcoreapp2.11> dotnet catalog.dll --server.urls "http://127.0.0.1:8002"
打开一个新的 cmd ,cd 到 Catalog.ddl 所在的目录路径。
路径大约:xxxeShopCatalogbinDebugnetcoreapp2.11> dotnet catalog.dll --server.urls "http://127.0.0.1:8003"
在浏览器中输入:http://127.0.0.1:8500
可以新启动的服务都已经注册到 consul 中了
| Service | Health Checks | Tag |
| ————– | ————- | — |
| CatalogService | √ 6 | |
| consul | √ 1 | |
点击 CatalogService 看看~1["value from Catalog","http://127.0.0.1:8001/api/values"]1["value from Catalog","http://127.0.0.1:8002/api/values"]1["value from Catalog","http://127.0.0.1:8003/api/values"]
结束语
可以看出用 Consul 来搭建网关很简单方便,
然而使用起来简单方便不是我们选择的标准,
网关作为流量汇总的入口,它除了能正常运转外,还必须快!快!!快!!!,
所以,我会将更多的时间投入到: Kong 和 traefik
小流量项目使用 Consul,
大流量项目则必须用牛刀了。