您的位置:首页 > 运维架构 > Docker

Ocelot + Consul + Registrator 基于Docker 实现服务发现、服务自动注册

2018-07-25 23:47 1016 查看

目录

  • 2. Registrator服务注册工具
  • 3. clientservice服务Demo
  • 4. Ocelot网关Demo
  • 5 总结
  • 关于这个工具的介绍这里就不多说了,网上、官网都很详细,这里直接记录一下搭建过程。另外最后有几个疑惑还未解决,希望各位前辈答疑解惑。

    1. Consul集群搭建

    我们基于Docker搭建三个Server和两个Client的DC。

    • server1
    docker run -d --name server1 consul agent -server -node=server1 -bootstrap-expect=3
    # 获取server1IP地址,方便后续节点接入集群
    JOIN_IP="$(sudo docker inspect -f '{{.NetworkSettings.IPAddress}}' server1)"
    • server2
    docker run -d --name server2 consul agent -server -node=server2 -join $JOIN_IP
    • server3
    docker run -d --name server3 consul agent -server -node=server3 -join $JOIN_IP
    • client1
    docker run -d --name client1 consul agent -node=client1 -join $JOIN_IP
    • client2
    docker run -d --name client2 -p 8400:8400 -p 8500:8500 -p 8600:53/udp  consul agent -ui -node=client2 -client=0.0.0.0 -join $JOIN_IP

    运行效果:

    1.1 F&Q

    Consul官方推荐的host网络模式运行

    查看Consul官方文档,官方推荐Consul以Docker的host网络模式运行。但是这样的话,一个Docker寄宿主机只运行一个consul agent?生产中的Docker集群是如何搭建的?

    2. Registrator服务注册工具

    启动Registrator工具容器,Registrator使用主机网络模式,使用

    -internal
    选项,注册基于expose端口的服务。

    docker run -d --name registrator --net host --volume=/var/run/docker.sock:/tmp/docker.sock gliderlabs/registrator -internal consul://172.17.0.6:8500

    Consul管理UI服务截图,Registrator会把Consul也作为服务注册到Consul。这也是可以理解的,因为Registrator的观点是任何监听在端口的程序都是服务。

    2.1 F&Q

    Registrator悬挂服务

    正常情况下,这里应该是没有clientservice的,但是由于我之前测试没有正常按顺序启停容器,形成了悬挂服务,一直没有清除。我看Registrator文档中有

    -cleanup
    选项可以清理悬挂服务,后续尝试一下。

    Registrator的
    -internal
    选项

    不指定这个选项时,Registrator使用容器的发布端口(映射到寄宿主机的端口)自动注册服务,这时候一般要用

    -ip
    选项指定主机的IP地址,因为Registrator一般很难推断出主机的IP地址。当使用
    -internal
    选项时,Registrator使用服务所在容器分配的内部地址自动注册服务。

    3. clientservice服务Demo

    clientservice是一个web api项目,由于是自动服务发现和注册,因此clientservice跟无需做特别的配置。
    我仅仅指定服务的端口为5000,修改了ValueController,返回服务调用情况。

    3.1 Program.cs

    public class Program
    {
    public static void Main(string[] args)
    {
    CreateWebHostBuilder(args).Build().Run();
    }
    
    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
    .UseUrls("http://*:5000")
    .UseStartup<Startup>();
    }

    3.2 ValuesController.cs

    ...
    [HttpGet]
    public ActionResult<RequestInfo> Get()
    {
    var clientHost = HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString();
    var serverHost = HttpContext.Connection.LocalIpAddress.MapToIPv4().ToString();
    var path = HttpContext.Request.Path;
    return new RequestInfo{
    RemoteIp = clientHost,
    RemotePort = HttpContext.Connection.RemotePort,
    LocalIp = serverHost,
    LocalPort = HttpContext.Connection.LocalPort,
    Path = path,
    Host = HttpContext.Request.Host.ToUriComponent()
    };
    }
    ...

    3.3 Dockerfile

    #基于microsoft/dotnet:latest构建Docker image
    FROM microsoft/dotnet:latest
    
    #进入docker中的/usr/local/src目录,创建DockerWebAPI目录
    RUN cd /usr/local/src&&mkdir DockerWebAPI
    
    #设置工作路径
    WORKDIR /usr/local/src/DockerWebAPI
    
    #将当前文件夹下的所有文件全部复制到工作目录
    COPY ./ ./
    
    #向外界暴露5000端口
    EXPOSE 5000
    
    #执行dotnet *.dll命令
    CMD ["dotnet","clientservice.dll"]

    3.4 制作镜像并启动容器

    • 制作镜像
    docker build -t zhangdk/clientservice .
    • 启动容器
    docker run -d zhangdk/clientservice

    Consul管理UI截图,如果你是第一次搭建集群并启动Clientservice的话,后面应该有小标1。我这里由于悬挂服务的问题,有启动前的1现在变成了2。

    clientservice注册信息(多余的是悬挂服务的注册信息),要注意查看ServiceAddress和ServicePort是否正确:

    4. Ocelot网关Demo

    VS Code创建空web项目

    dotnet new web
    ,安装ocelot库
    dot add package ocelot
    ,主要修改三个文件:

    4.1 Program.cs:

    public class Program
    {
    public static void Main(string[] args)
    {
    CreateWebHostBuilder(args).Build().Run();
    }
    
    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
    .UseStartup<Startup>()
    .UseUrls("http://*:5010")  //服务监听在5010端口,后期可以调整为从外部读取,方便配置
    .ConfigureAppConfiguration((context,builder)=>{
    builder.AddJsonFile("configuration.json",false,true); //读取Ocelot配置文件
    });
    }

    4.2 Startup.cs:

    public class Startup
    {
    public Startup(IConfiguration configuration){
    Configuration = configuration;
    }
    
    public IConfiguration Configuration{get;set;}
    
    public void ConfigureServices(IServiceCollection services) => services.AddOcelot(Configuration); //注册Ocelot服务
    
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
    if (env.IsDevelopment())
    {
    app.UseDeveloperExceptionPage();
    }
    
    app.UseOcelot().Wait();   //启用Ocelot中间件
    }
    }

    4.3 添加配置文件configuration.json:

    {
    "ReRoutes": [
    {
    "UseServiceDiscovery": true,  //启用服务发现
    "DownstreamPathTemplate": "/api/{url}",
    "DownstreamScheme": "http",
    "ServiceName": "clientservice",
    "LoadBalancerOptions": {
    "Type": "RoundRobin"
    },
    "UpstreamPathTemplate": "/api/clientservice/{url}",
    "UpstreamHttpMethod": [ "Get", "Post" ],
    "ReRoutesCaseSensitive": false
    }
    ],
    "GlobalConfiguration": {
    "ServiceDiscoveryProvider": {
    "Host": "172.17.0.6",  //Consul client IP
    "Port": 8500  //Consul HTTP API端口
    }
    }
    }

    4.4 Dockerfile文件编写

    #基于microsoft/dotnet:latest构建Docker image
    FROM microsoft/dotnet:latest
    
    #进入docker中的/usr/local/src目录,创建DockerWebAPI目录
    RUN cd /usr/local/src&&mkdir DockerWebAPI
    
    #设置工作路径
    WORKDIR /usr/local/src/DockerWebAPI
    
    #将当前文件夹下的所有文件全部复制到工作目录
    COPY ./ ./
    
    #向外界暴露5010端口
    EXPOSE 5010
    
    #执行dotnet *.dll命令
    CMD ["dotnet","oceletgateway.dll"]

    4.5 发布项目,制作镜像,并启动容器

    • 发布项目
    dotnet publish
    • 拷贝Dockfile到Demo的publish文件夹,打开终端
    docker build -t zhangdk/ocelotgateway .
    • 运行OcelotGateway服务容器
    docker run -d --name=ocelotgateway zhangdk/ocelotgateway

    通过Ocelot网关服务访问clientservice

    直接访问clientservice

    4.6 F&Q

    Ocelot服务发现地址怎么配置

    刚开始的我以为应该配置Leader server的地址,但是由于leader server的端口并没有暴露,因此容器间无法访问。尝试使用client的地址,发现也是可以成功的。

    Ocelot的服务发现地址配置

    Consul在集群模式运行时,单个server或者client agent节点挂掉后仍然可以通过投票等协议正常运行。但是,Ocelot网关服务中配置了唯一的一个agent地址,那岂不是意味着这个节点挂掉后,Ocelot网关服务就和Consul集群的服务发现就失去了联系,那这里的Consul集群有什么意义?

    5 总结

    初步按照自己的思路搭建起来的服务发现,自动注册的架构,后续会继续完善权限验证、负载均衡等网关的其他功能。搭建的过程中也有许多困惑还没有想明白,后续边想边做。微服务这一块也是刚刚接触,有什么问题或错误,还希望各位前辈指正。

    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: