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即为接口服务的发布地址及端口,知道这些信息后,访问接口时就可以以通常的方式进行了

这种服务的注册、发现及访问,流程会让人觉得有些麻烦,但是后台这样实现访问客户端与后台服务接口的分离,后台接口配置的变动,不会引起客户端配置的变更,同时,后台服务以注册/发现的形式发布,后台服务项目可以按业务功能进行适当的拆分,以各子项单独注册的方式进行,各个子项目的变更上线,不会对其它子项目产生影响

 

posted @ 2019-06-12 17:00  心燃  阅读(543)  评论(0编辑  收藏  举报