Linux环境(Centos7)下基于docker+consul框架发布.netcore微服务应用的部署(二)
一、consul容器的部署,部分转自https://www.cnblogs.com/bossma/p/9756809.html
用consul做服务注册与发现的实现至少需要部署3个server和1个client,3个server是为了有效的选举出1个leader,而client用于服务注册时的绑定,即服务对应的consul的IP及端口绑定在client上,这样当某个server挂掉时,新选举出来的server一样能返回服务的真正的接口地址和端口,也可以绑定在server上,但是如果这个server挂掉了,服务就没法访问了
发布consul的server容器并运行
#启动第1个Client节点,做为leader,配置webui界面访问 docker run -d --name=consul1 -p 8900:8500 -e CONSUL_BIND_INTERFACE=eth0 consul agent --server=true --bootstrap-expect=3 --client=0.0.0.0 -ui #启动第2个Client节点,并加入集群 docker run -d --name=consul2 -e CONSUL_BIND_INTERFACE=eth0 consul agent --server=true --client=0.0.0.0 --join 172.17.0.2 #启动第3个Client节点,并加入集群 docker run -d --name=consul3 -e CONSUL_BIND_INTERFACE=eth0 consul agent --server=true --client=0.0.0.0 --join 172.17.0.2 #启动第4个Client节点,做为client # docker run -d --name=consul4 -e CONSUL_BIND_INTERFACE=eth0 consul agent --server=false --client=0.0.0.0 --join 172.17.0.2
8500是consul服务的默认访问端口,这里映射到8900,这样在webui中使用8900就可以访问consul集群了,consul集群部署完了后通过一些docker命令查看集群的信息
docker中进行consul部署容器的IP地址默认从172.17.0.2开始,依次类推,查看各容器的IP情况如下
如下可以查看当前的leader是哪个,因为我之前停止了consul1,所以这里的leader已经选举产生成了consul2
webui界面访问地址http://114.115.200.152:8900/ui/dc1/services
二、服务的发布与注册,实现consul的服务发现,从而通过访问consul服务器中的注册服务名称,得到真正的应用服务的接口地址,以.netcore2.0为例
我是在win10环境下做的asp.netcore webapi开发,新建webapi项目,安装consul依赖,编写服务注册类
using Consul; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using System; namespace Manulife.DNC.MSAD.Common { public static class AppBuilderExtensions { public static IApplicationBuilder RegisterConsul(this IApplicationBuilder app, IApplicationLifetime lifetime, ServiceEntity serviceEntity) { var consulClient = new ConsulClient(x => x.Address = new Uri($"http://{serviceEntity.ConsulIP}:{serviceEntity.ConsulPort}"));//请求注册的 Consul 地址 var httpCheck = new AgentServiceCheck() { DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服务启动多久后注册 Interval = TimeSpan.FromSeconds(10),//健康检查时间间隔,或者称为心跳间隔 HTTP = $"http://{serviceEntity.IP}:{serviceEntity.Port}/api/health",//健康检查地址 Timeout = TimeSpan.FromSeconds(5) }; // Register service with consul var registration = new AgentServiceRegistration() { Checks = new[] { httpCheck }, ID = Guid.NewGuid().ToString(), Name = serviceEntity.ServiceName, Address = serviceEntity.IP, Port = serviceEntity.Port, Tags = new[] { $"urlprefix-/{serviceEntity.ServiceName}" }//添加 urlprefix-/servicename 格式的 tag 标签,以便 Fabio 识别 }; consulClient.Agent.ServiceRegister(registration).Wait();//服务启动时注册,内部实现其实就是使用 Consul API 进行注册(HttpClient发起) /* lifetime.ApplicationStopping.Register(() => { consulClient.Agent.ServiceDeregister(registration.ID).Wait();//服务停止时取消注册 }); */ return app; } } }
新建一个控制器,实现一个简单的接口
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; namespace WebApplication2.Controllers { [Produces("application/json")] [Route("api/Health")] public class HealthController : Controller { [HttpGet] public IActionResult Get() => Ok("ok"); } }
在startup.cs中实现服务注册的接口业务
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime lifetime) { if (env.IsDevelopment()) { app.UseBrowserLink(); app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Error"); } app.UseStaticFiles(); app.UseMvc(); ServiceEntity serviceEntity = new ServiceEntity { IP = Configuration["Service:IP"],//NetworkHelper.LocalIPAddress, Port = Convert.ToInt32(Configuration["Service:Port"]), ServiceName = Configuration["Service:Name"], ConsulIP = Configuration["Consul:IP"], ConsulPort = Convert.ToInt32(Configuration["Consul:Port"]) }; Console.WriteLine($"服务器IP:{serviceEntity.IP},ConsulIP:{serviceEntity.ConsulIP}"); app.RegisterConsul(lifetime, serviceEntity); }
在appsetting中实现consul服务器的参数配置,这里接口注册的consul对应的是client
{ "Service": { "Name": "ProductService", "IP": "114.115.200.152", "Port": "8088" }, "Consul": { "IP": "172.17.0.5", "Port": "8500" }, "Logging": { "IncludeScopes": false, "Debug": { "LogLevel": { "Default": "Warning" } }, "Console": { "LogLevel": { "Default": "Warning" } } } }
Service配置中的Name是Consul中注册的服务名,IP为访问服务时真实的服务地址,这个地址需要请求注册的consul服务进行返回,发布webapi,用winscp将webapi发布生成的publish上传到consul服务器,运行dotnet WebApplication2.dll(这里以自己的实现项目为准,运行dotnet需要先在Linux主机中进行安装netcore sdk,可以参与https://jingyan.baidu.com/article/bea41d43d1ab1bb4c51be6ac.html)
访问http://114.115.200.152:8900/v1/catalog/service/ProductService可以看到返回了接口Health的服务地址与端口
上述返回信息中ServiceAddress/ServicePort即为接口服务的发布地址及端口,知道这些信息后,访问接口时就可以以通常的方式进行了
这种服务的注册、发现及访问,流程会让人觉得有些麻烦,但是后台这样实现访问客户端与后台服务接口的分离,后台接口配置的变动,不会引起客户端配置的变更,同时,后台服务以注册/发现的形式发布,后台服务项目可以按业务功能进行适当的拆分,以各子项单独注册的方式进行,各个子项目的变更上线,不会对其它子项目产生影响