zoukankan      html  css  js  c++  java
  • 庐山真面目之十二微服务架构基于Docker搭建Consul集群、Ocelot网关集群和IdentityServer版本实现

    庐山真面目之十二微服务架构基于Docker搭建Consul集群、Ocelot网关集群和IdentityServer版本实现

    一、简介
           在第七篇文章《庐山真面目之七微服务架构Consul集群、Ocelot网关集群和IdentityServer4版本实现》中,我们已经探讨了如何搭建基于Windows 环境的Consul服务集群、Ocelot网关集群和认证的微服务架构。我们是不是这样就算是完成了微服务架构的搭建了吗?当然没有了,生产环境中肯定不会在Windows系统下搭建这些,以前只不过是测试的环境。从今天开始我们将要微服务架构搬到Linux环境中去,并且是基于Docker来搭建的?今天这篇文章会很长,大家要有耐性。

        1、说明
               在看这篇文章之前,大家还是要有些准备的。比如:会操作Linux系统,会使用Docker,基本操作要会,对Net5.0也要所有了解,也就是对跨平台开发有所了解,还要有一些镜像文件,比如:nginx,consul等等,还有其他的一些基础,大家都要熟悉,这些东西没有办法写在这里了。在此特别声明:如果是高手的话,这些东西相对于您来说,肯定是微不足道,请您口下留德,再者说,这些文章是为零基础的人写的,不要抬杠了,如果有高见,也希望不灵赐教。特别说明,这里的所有代码都经过测试,所以大家可以放心使用。

        2、开发环境
              
    以下就是开发环境,不用多说,都很简单,一看就知道。
             (1)、开发工具:Visual Studio 2019
             (2)、开发语言:C#
             (3)、开发平台:Net 5.0和Net Core 3.1,跨平台。
             (4)、服务注册:Consul集群,服务注册、发现中心
             (5)、服务治理:Ocelot集群,负载均衡、服务治理
             (6)、网关服务:Nginx 服务组件,一个负载Consul服务,一个负载Ocelot网关。
             (7)、操作系统:Linux(CentOS7)。
             (8)、鉴权授权:IdentityServer4

        3、我们的目标
              今天我们的目标是,在Linux系统上搭建基于Docker来实现Consul集群、Ocelot集群和IdentityServer4鉴权、授权的微服务架构。这个任务比较艰巨,篇幅一定很长,因为包含的内容有点多。当然这个肯定不是最终版本,我们还会继续演化下去。
               目标框架如图:
                

    二、搭建Consul服务的集群。
       

               

            Consul 用 Golang 实现,因此具有天然可移植性(支持 Linux、windows 和 Mac OS X ),它的安装包仅包含一个可执行文件,方便部署,与 Docker 等轻量级容器可无缝配合。
            在这里我们仅仅对Consul集群做简单的介绍,具体的详情可以自己去网上学习。Consul服务在Cluster集群上的每一个节点都运行一个Agent代理,这个Agent代理可以使用Server服务器或者Client客户端模式。Client客户端负责到Server服务器端的高效通信,相对为无状态的。 Server服务器端负责:包括选举领导节点,维护Cluster集群的状态,对所有的查询做出响应,跨数据中心的通信等等。
            Agent代理可以运行在Server服务器模式或者Client客户模式,每个数据中心至少有一个Agent代理运行在server服务器模式,一般建议是3或者5个Server。部署单个Server是非常不好的,因为在失败场景中出现数据丢失是不可避免的。我们今天要3个服务器端和1个客户端来完成我们今天的架构任务。

            名词解释:
            A、Client Consul 的 Client模式,就是客户端模式。是 Consul 节点的一种模式,这种模式下,所有注册到当前节点的服务会被转发到 Server,本身不具有持久化数据的功能。
            B、Server :Consul 的 Server 模式,表明这个 Consul 是个 Server ,这种模式下,功能和 Client 都一样,唯一不同的是,它会把所有的数据持久化的本地,这样遇到故障,信息是可以被保留的。
            C、Server-Leader:是所有服务器们的老大,它和其它 Server 不一样的一点是,它需要负责同步注册的信息给其它的 Server ,同时也要负责各个节点的健康监测。
            D、Raft:Server 节点之间的数据一致性保证协议使用的是 raft,而 Zookeeper 用的 PAXOS,ETCD采用的也是Raft服务发现协议,Consul 采用 http 和 DNS 协议,ETCD 只支持 http 。
            E、服务注册:Consul 支持两种方式实现服务注册,一种是通过 Consul 的服务注册API(Http协议),由服务自己调用 API 实现注册;另一种方式是通过 JSON 格式的配置文件实现注册,将需要注册的服务以 JSON 格式的配置文件给出。Consul 官方建议使用第二种方式。

        Consul文档:https://www.consul.io/docs
        Consul官网:https://www.consul.io

           我们开始在Linux环境中基于Docker来搭建我们的Consul服务集群。

           1、在Linux系统中,先查看我们是否有Consul的镜像,如果没有就赶紧拉去吧。

                   命令:#docker images,我这里没有,我把环境清空了,所以我要重新拉取。
                    

                   命令:#docker pull consul
                    

           2、开始启动服务实例,3个服务器端实例,一个客户端实例。
                  
    Client 客户端,不会存储数据。Server服务器端可以固化数据,3个服务器端,实现 Raft算法,选举出一个Leader。初始化需要3个Server服务器节点,选出Leader 服务器节点负责数据同步。如果只有一个Server 节点,集群会失败。
           
                  参数解释:
                       consul agent:命令头,必须要有。
                       -server表示要启动服务器代理(agent)模式。Consul Agent节点的运行模式有两种,Server模式和Client模式。其区别就是Server模式数据可以持久化到本地,而Client模式不可以。
                       -uiconsul运行后,会提供一个http://127.0.0.1:8500/ui/的网站,里面存储了Consul Agent各个节点以及注册的服务等相关信息,即数据中心的网页形式体现。这个参数代表是否创建这个网站,这个参数与这个数据中心网站有关。
                       -bind本机的IP地址,集群内其他代理服务器可以通过这个IP来访问这台电脑的consul代理服务器。
                       -bootstrap-expect:是集群启动条件,指当服务器端模式(Server模式)的代理达到这个数目后,才开始运行。
                       -data-dir是存放数据中心数据的目录,该目录必须是稳定的,系统重启后也继续存在的。
                       -config-dir:是存放数据中心日志的目录,该目录必须是稳定的,系统重启后也继续存在的。
                       -datacenter:当前Consul的中心数据的名称,默认是dc1。
                       -node节点在集群中的名称,在一个集群中必须是唯一的,默认是该节点的主机名(代表一个机器)。
                       -client本地IP地址,这里使用 0.0.0.0 ,就表示这个服务器所有IP都可以,即当这台电脑有俩IP,192.168.1.100和192.168.1.111,那么通过这俩IP都可以访问到这台机器的consul代理服务器。
                       -join表示当前的服务器节点或者是客户端节点要加入集群的服务器,后面跟要加入的服务器的具体IP地址。

                  安装完成后,Agent就可以启动了,我们开始搭建我们Consul集群了。

                    (1)、启动 Consul-Server-Leader 主节点。
                             命令:# docker run -d --name=masternode --restart=always -e 'CONSUL_LOCAL_CONFIG={"skip_leave_on_interrupt":true}' -p 8300:8300 -p 8301:8301 -p 8301:8301/udp -p 8302:8302/udp -p 8302:8302 -p 8400:8400 -p 8500:8500 -p 8600:8600 -h masternode consul agent -server -bind=0.0.0.0 -bootstrap-expect=3 -node=masternode -data-dir=/tmp/data-dir -client 0.0.0.0 -ui

     1     docker run -d --name=masternode --restart=always 
     2     -e 'CONSUL_LOCAL_CONFIG={"skip_leave_on_interrupt":true}'
     3     -p 8300:8300
     4     -p 8301:8301
     5     -p 8301:8301/udp
     6     -p 8302:8302/udp
     7     -p 8302:8302
     8     -p 8400:8400
     9     -p 8500:8500
    10     -p 8600:8600
    11     -h masternode
    12     consul agent -server -bind=0.0.0.0 -bootstrap-expect=3 -node=masternode
    13     -data-dir=/tmp/data-dir -client 0.0.0.0 -ui
    14 
    15     Consul的地址:http://192.168.127.141:8500/    


                             启动:
                                    
                             效果:
                                     

                   (2)、创建Server- Follower,Consul集群中的第一个追随者
                             命令:# docker run -d --name=followernode --restart=always -e 'CONSUL_LOCAL_CONFIG={"skip_leave_on_interrupt":true}' -p 9300:8300 -p 9301:8301 -p 9301:8301/udp -p 9302:8302/udp -p 9302:8302 -p 9400:8400 -p 9500:8500 -p 9600:8600 -h followernode consul agent -server -bind=0.0.0.0 -join=192.168.127.141 -node-id=$(uuidgen | awk '{print tolower($0)}') -node=followernode -data-dir=/tmp/data-dir -client 0.0.0.0 -ui

     1     docker run -d --name=followernode --restart=always
     2     -e 'CONSUL_LOCAL_CONFIG={"skip_leave_on_interrupt":true}'
     3     -p 9300:8300
     4     -p 9301:8301
     5     -p 9301:8301/udp
     6     -p 9302:8302/udp
     7     -p 9302:8302
     8     -p 9400:8400
     9     -p 9500:8500
    10     -p 9600:8600
    11     -h followernode
    12     consul agent -server -bind=0.0.0.0 -join=192.168.127.141
    13         -node-id=$(uuidgen | awk '{print tolower($0)}') -node=followernode
    14     -data-dir=/tmp/data-dir -client 0.0.0.0 -ui
    15 
    16 
    17     Consul的地址:http://192.168.127.141:9500/


                             启动:
                                     
                             效果:
                                     
                        
                   (3)、创建Server- Follower,Consul集群中的第二个追随者
                             命令:#docker run -d --name=followernode2 --restart=always -e 'CONSUL_LOCAL_CONFIG={"skip_leave_on_interrupt":true}' -p 10300:8300 -p 10301:8301 -p 10301:8301/udp -p 10302:8302/udp -p 10302:8302 -p 10400:8400 -p 10500:8500 -p 10600:8600 -h followernode2 consul agent -server -bind=0.0.0.0 -join=192.168.127.141 -node-id=$(uuidgen | awk '{print tolower($0)}') -node=followernode2 -data-dir=/tmp/data-dir -client 0.0.0.0 -ui

     1     docker run -d --name=followernode2 --restart=always
     2     -e 'CONSUL_LOCAL_CONFIG={"skip_leave_on_interrupt":true}'
     3     -p 10300:8300
     4     -p 10301:8301
     5     -p 10301:8301/udp
     6     -p 10302:8302/udp
     7     -p 10302:8302
     8     -p 10400:8400
     9     -p 10500:8500
    10     -p 10600:8600
    11     -h followernode2
    12     consul agent -server -bind=0.0.0.0
    13     -join=192.168.127.141 -node-id=$(uuidgen | awk '{print tolower($0)}') -node=followernode2
    14     -data-dir=/tmp/data-dir -client 0.0.0.0 -ui
    15 
    16     Consul的地址:http://192.168.127.141:10500/


                             启动:
                                     
                             效果:
                                     

                   (4)、创建Consul-Client ,Consul集群中的客户端。
                             命令:#docker run -d --name=clientNode --restart=always -e 'CONSUL_LOCAL_CONFIG={"leave_on_terminate":true}' -p 11300:8300 -p 11301:8301 -p 11301:8301/udp -p 11302:8302/udp -p 11302:8302 -p 11400:8400 -p 11500:8500 -p 11600:8600 -h clientNode consul agent -bind=0.0.0.0 -retry-join=192.168.127.141 -node-id=$(uuidgen | awk '{print tolower($0)}') -node=clientNode -data-dir=/tmp/data-dir -client 0.0.0.0 -ui

     1     docker run -d --name=clientnode --restart=always
     2     -e 'CONSUL_LOCAL_CONFIG={"leave_on_terminate":true}'
     3     -p 11300:8300
     4     -p 11301:8301
     5     -p 11301:8301/udp
     6     -p 11302:8302/udp
     7     -p 11302:8302
     8     -p 11400:8400
     9     -p 11500:8500
    10     -p 11600:8600
    11     -h clientnode
    12     consul agent -bind=0.0.0.0 -retry-join=192.168.127.141
    13     -node-id=$(uuidgen | awk '{print tolower($0)}') -node=clientnode
    14     -data-dir=/tmp/data-dir -client 0.0.0.0 -ui
    15 
    16     Consul的网站:http://192.168.127.141:11500/


                             启动:
                                    
                             效果:
                                                   

           3、验证3个服务器端和一个客户端是否安装成功。

                   执行这些命令,都要切换到Consul所在的目录。切记。
                   (1)、执行命令查看容器实例
                               命令:#docker ps –a
                                   

                   (2)、查看Consul成员列表,三个服务器端实例,一个客户端实例。
                  
    命令:#docker exec -t clientnode consul members
                      

                   3
    个server,1个client,状态是:alive,说明集群创建成功。

             
    (3)、我们在看看服务器角色的分配是否合适?一主二从,则表示运行成功。
                   
    命令:#docker exec -t masternode consul operator raft list-peers

                                    

                    (4)、我们也可以通过浏览器访问以下地址,验证Consul服务是否安装成功。
                               第一主服务器: http://192.168.127.141:8500
                               第二从服务器: http://192.168.127.141:9500
                               第三从服务器: http://192.168.127.141:10500
                               Consul客户端: http://192.168.127.141:11500
                               能看到如下截图,也可以说明成功。我只截一个图了,其他都类似。

                                

    三、搭建微服务测试项目。

              我们要想搭建微服务架构,第一步,我们当然要搭建我们自己的测试项目了,代码都很简单,主要是为了突出各个开源技术点。这是基础中的基础,没有这一步,其他的都是空中楼阁,没有说服力了。废话少说,我们开始吧。
        
            1、建立测试项目,并编写各个项目的所需代码。

                    (1)、PatrickLiu.MicroService.Client(ASP.NET CORE MVC),客户端项目。
                              该项目模仿客户端程序,当然可以是你愿意的任何客户端程序,别抬杠,我这里只是一个简单的MVC项目,通过地址访问微服务。

                    

                               样例代码:
                    

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Net.Http;
     4 using Microsoft.AspNetCore.Mvc;
     5 using Microsoft.Extensions.Logging;
     6 using PatrickLiu.MicroService.Interfaces;
     7 using PatrickLiu.MicroService.Models;
     8 
     9 namespace PatrickLiu.MicroService.Client.Controllers
    10 {
    11     public class HomeController : Controller
    12     {
    13         private readonly ILogger<HomeController> _logger;
    14         private readonly IUserService _userService;        
    15 
    16         /// <summary>
    17         /// 初始化该类型的新实例。
    18         /// </summary>
    19         /// <param name="logger">注入日志对象。</param>
    20         /// <param name="userService">注入用户服务对象。</param>
    21         public HomeController(ILogger<HomeController> logger, IUserService userService)
    22         {
    23             _logger = logger;
    24             _userService = userService;
    25         }
    26 
    27         /// <summary>
    28         /// 首页。
    29         /// </summary>
    30         /// <returns></returns>
    31         public IActionResult Index()
    32         {
    33           
    34             #region 通过 Ocelot 集群网关访问服务实例,追加访问 Token,切记,我这里没写。
    35 
    36             string url = "http://192.168.127.141:8083/gate/users/all";
    37 
    38             #endregion
    39 
    40             string content = InvokeAPI(url);
    41             this.ViewBag.Users = Newtonsoft.Json.JsonConvert.DeserializeObject<IEnumerable<User>>(content);
    42             Console.WriteLine($"This is {url} Invoke.");
    43             
    44             #endregion
    45 
    46             return View();
    47         }
    48 
    49 
    50         /// <summary>
    51         /// 
    52         /// </summary>
    53         /// <param name="url"></param>
    54         /// <returns></returns>
    55         public static string InvokeAPI(string url)
    56         {
    57             using (HttpClient client = new HttpClient())
    58             {
    59                 HttpRequestMessage message = new HttpRequestMessage();
    60                 message.Method = HttpMethod.Get;
    61                 message.RequestUri = new Uri(url);
    62                 var result = client.SendAsync(message).Result;
    63                 string conent = result.Content.ReadAsStringAsync().Result;
    64                 return conent;
    65             }
    66         }
    67     }
    68 }


                    (2)、PatrickLiu.MicroService.Interfaces(NET CORE 类库),定义服务接口,面向接口编程嘛,代码很简单,因为重点不是它。

                            

                               样例代码:                           

     1 using PatrickLiu.MicroService.Models;
     2 using System.Collections.Generic;
     3 
     4 namespace PatrickLiu.MicroService.Interfaces
     5 {
     6     /// <summary>
     7     /// 用户服务的接口定义。
     8     /// </summary>
     9     public interface IUserService
    10     {
    11         /// <summary>
    12         /// 查找指定主键的用户实例对象。
    13         /// </summary>
    14         /// <param name="id">用户的主键。</param>
    15         /// <returns>返回查找到的用户实例对象。</returns>
    16         User FindUser(int id);
    17 
    18         /// <summary>
    19         /// 获取所有用户的实例集合。
    20         /// </summary>
    21         /// <returns>返回所有的用户实例。</returns>
    22         IEnumerable<User> UserAll();
    23     }
    24 }


                    (3)、PatrickLiu.MicroService.Models(NET CORE 类库),定义实例类型,主要用于数据传递,代码很简单,因为重点不是它。

                                 
             
                               样例代码:

     1 using System;
     2 
     3 namespace PatrickLiu.MicroService.Models
     4 {
     5     /// <summary>
     6     /// 用户模型。
     7     /// </summary>
     8     public class User
     9     {
    10         /// <summary>
    11         /// 获取或者设置用户主键。
    12         /// </summary>
    13         public int ID { get; set; }
    14 
    15         /// <summary>
    16         /// 获取或者设置用户姓名。
    17         /// </summary>
    18         public string Name { get; set; }
    19 
    20         /// <summary>
    21         /// 获取或者设置用户账号名称。
    22         /// </summary>
    23         public string Account { get; set; }
    24 
    25         /// <summary>
    26         /// 获取或者设置用户密码。
    27         /// </summary>
    28         public string Password { get; set; }
    29 
    30         /// <summary>
    31         /// 获取或者设置用户的电子邮箱地址。
    32         /// </summary>
    33         public string Email { get; set; }
    34 
    35         /// <summary>
    36         /// 获取或者设置用户角色。
    37         /// </summary>
    38         public string Role { get; set; }
    39 
    40         /// <summary>
    41         /// 获取或者设置用户的登录时间。
    42         /// </summary>
    43         public DateTime LoginTime { get; set; }
    44     }
    45 }


                    (4)、PatrickLiu.MicroService.Services(NET CORE 类库),定义服务实现,我们有了接口,然后基于接口实现具体的服务,代码很简单,因为重点不是它。

                                 

                   样例代码:
                                

     1 using PatrickLiu.MicroService.Interfaces;
     2 using PatrickLiu.MicroService.Models;
     3 using System;
     4 using System.Collections.Generic;
     5 using System.Linq;
     6 
     7 namespace PatrickLiu.MicroService.Services
     8 {
     9     /// <summary>
    10     /// 实现用户服务接口的实现类型。
    11     /// </summary>
    12     public class UserService : IUserService
    13     {
    14         private IList<User> dataList;
    15 
    16         /// <summary>
    17         /// 初始化类型的实例
    18         /// </summary>
    19         public UserService()
    20         {
    21             dataList = new List<User>()
    22             { new User {ID=1,Name="黄飞鸿",Account="HuangFeiHong",Password="HuangFeiHong123456",Email="huangFeiHong@sina.com", Role="Admin", LoginTime=DateTime.Now },
    23             new User {ID=2,Name="洪熙官",Account="HongXiGuan",Password="HongXiGuan54667",Email="HongXiGuan@sina.com", Role="Admin", LoginTime=DateTime.Now.AddDays(-5) },
    24             new User {ID=3,Name="方世玉",Account="FangShiYu",Password="FangShiYu112233",Email="fangShiYu@163.com", Role="Admin", LoginTime=DateTime.Now.AddDays(-30) },
    25             new User {ID=4,Name="苗翠花",Account="MiaoCuiHua",Password="MiaoCuiHua887766",Email="miaoCuiHua@sohu.com", Role="Admin", LoginTime=DateTime.Now.AddDays(-90) },
    26             new User {ID=5,Name="严咏春",Account="YanYongChun",Password="YanYongChun09392",Email="yanYongChun@263.com", Role="Admin", LoginTime=DateTime.Now.AddMinutes(-50) }};
    27         }
    28 
    29         /// <summary>
    30         /// 查找指定主键的用户实例对象。
    31         /// </summary>
    32         /// <param name="id">用户的主键。</param>
    33         /// <returns>返回查找到的用户实例对象。</returns>
    34         public User FindUser(int id)
    35         {
    36             return dataList.FirstOrDefault(user => user.ID == id);
    37         }
    38 
    39         /// <summary>
    40         /// 获取所有用户的实例集合。
    41         /// </summary>
    42         /// <returns>返回所有的用户实例。</returns>
    43         public IEnumerable<User> UserAll()
    44         {
    45             return dataList;
    46         }
    47     }
    48 }


                    (5)、PatrickLiu.MicroService.ServiceInstance(ASP.NET CORE WEBAPI),这个就是我们的服务,通过启动多个实例,实现集群,代码很简单,因为重点不是它。
                              这个项目必须引入其他三个项目:
                               PatrickLiu.MicroService.Interfaces
                               PatrickLiu.MicroService.Models
                               PatrickLiu.MicroService.Services

                               

                             【1】、安装Consul服务组件,以支持注册到Consul服务中心。
                        命令:Install-Package Consul
                                       
                          可以在项目菜单【依赖项】菜单上点击右键,选择【管理 NuGet 程序包】来安装Consul服务。

                               【2】、HealthController.cs,主要用于Consul服务的健康检查。                      
                        
                                     
    样例代码:

     1 using System;
     2 using Microsoft.AspNetCore.Mvc;
     3 using Microsoft.Extensions.Configuration;
     4 
     5 namespace PatrickLiu.MicroService.ServiceInstance.Controllers
     6 {
     7     /// <summary>
     8     /// 健康检查的控制器。
     9     /// </summary>
    10     [ApiController]
    11     [Route("api/[controller]")]
    12     public class HealthController : ControllerBase
    13     {
    14         private IConfiguration _configuration;
    15 
    16         /// <summary>
    17         /// 初始化该类型的新实例。
    18         /// </summary>
    19         /// <param name="configuration">配置接口。</param>
    20         public HealthController(IConfiguration configuration)
    21         {
    22             _configuration = configuration;
    23         }
    24 
    25         /// <summary>
    26         /// 要调用的接口。
    27         /// </summary>
    28         [HttpGet]
    29         [Route("Index")]
    30         public IActionResult Index()
    31         {
    32             Console.WriteLine($"This is HealhController {_configuration["port"]} Invoke");
    33             return Ok();
    34         }
    35     }
    36 }

                        
                             
    3】、UsersController.cs,主要是业务类型,内容很简单。                     
                        
                                     
    样例代码:

      1 using System;
      2 using System.Collections.Generic;
      3 using System.Linq;
      4 using System.Threading;
      5 using Microsoft.AspNetCore.Mvc;
      6 using Microsoft.Extensions.Configuration;
      7 using Microsoft.Extensions.Logging;
      8 using PatrickLiu.MicroService.Interfaces;
      9 using PatrickLiu.MicroService.Models;
     10 
     11 namespace PatrickLiu.MicroService.ServiceInstance.Controllers
     12 {
     13     /// <summary>
     14     /// 用户的 API 类型。
     15     /// </summary>
     16     [Route("api/[controller]")]
     17     [ApiController]    
     18     public class UsersController : ControllerBase
     19     {
     20         #region 私有字段
     21 
     22         private readonly ILogger<UsersController> _logger;
     23         private readonly IUserService _userService;
     24         private IConfiguration _configuration;
     25 
     26         #endregion
     27 
     28         #region 构造函数
     29 
     30         /// <summary>
     31         /// 初始化该类型的新实例。
     32         /// </summary>
     33         /// <param name="logger">日志记录器。</param>
     34         /// <param name="userService">用户服务接口。</param>
     35         /// <param name="configuration">配置服务。</param>
     36         public UsersController(ILogger<UsersController> logger, IUserService userService, IConfiguration configuration)
     37         {
     38             _logger = logger;
     39             _userService = userService;
     40             _configuration = configuration;
     41         }
     42 
     43         #endregion
     44 
     45         #region 实例方法
     46 
     47         /// <summary>
     48         /// 获取一条记录。
     49         /// </summary>
     50         /// <param name="id"></param>
     51         /// <returns></returns>
     52         [HttpGet]
     53         [Route("Get")]
     54         public User Get(int id)
     55         {
     56             return _userService.FindUser(id);
     57         }
     58 
     59         /// <summary>
     60         /// 获取所有记录。
     61         /// </summary>
     62         /// <returns></returns>
     63         [HttpGet]
     64         [Route("All")]        
     65         public IEnumerable<User> Get()
     66         {
     67             Console.WriteLine($"This is UsersController {this._configuration["port"]} Invoke");
     68 
     69             return this._userService.UserAll().Select((user => new User
     70             {
     71                 ID = user.ID,
     72                 Name = user.Name,
     73                 Account = user.Account,
     74                 Password = user.Password,
     75                 Email = user.Email,
     76                 Role = $"{this._configuration["ip"]}:{this._configuration["port"]}",
     77                 LoginTime = user.LoginTime
     78             })); ;
     79         }
     80 
     81         /// <summary>
     82         /// 超时处理,用于测试服务治理的超时管理。
     83         /// </summary>
     84         /// <returns></returns>
     85         [HttpGet]
     86         [Route("Timeout")]
     87         public IEnumerable<User> Timeout()
     88         {
     89             Console.WriteLine($"This is Timeout Start");
     90             //超时设置。
     91             Thread.Sleep(3000);
     92 
     93             Console.WriteLine($"This is Timeout End");
     94 
     95             return this._userService.UserAll().Select((user => new User
     96             {
     97                 ID = user.ID,
     98                 Name = user.Name,
     99                 Account = user.Account,
    100                 Password = user.Password,
    101                 Email = user.Email,
    102                 Role = $"{this._configuration["ip"]}:{this._configuration["port"]}",
    103                 LoginTime = user.LoginTime
    104             })); ;
    105         }
    106 
    107         #endregion
    108     }
    109 }

                          
                             
    4】、增加扩展类型:ConsulExtension.cs
                          
                
                        源码如下:

      1 using Consul;
      2 using Microsoft.Extensions.Configuration;
      3 using Microsoft.Extensions.Hosting;
      4 using System;
      5 
      6 namespace PatrickLiu.MicroService.ServiceInstance.Extensions
      7 {
      8     /// <summary>
      9     /// Consul 静态扩展类。
     10     /// </summary>
     11     public static class ConsulExtension
     12     {
     13         /// <summary>
     14         ///类型初始化器,初始化 Consul 网址和数据中心。
     15         /// </summary>
     16         static ConsulExtension()
     17         {
     18             Uri = new Uri("http://localhost:8500");
     19             DataCenter = "dc1";
     20         }
     21 
     22         /// <summary>
     23         /// 获取或者设置 Consul 的网址。
     24         /// </summary>
     25         public static Uri Uri { get; set; }
     26 
     27         /// <summary>
     28         /// 获取或者设置数据中心。
     29         /// </summary>
     30         public static string DataCenter { get; set; }
     31 
     32         /// <summary>
     33         /// 向 Consul 服务中心注册服务实例。
     34         /// </summary>
     35         /// <param name="configuration">配置对象。</param>
     36         /// <param name="consulServiceName">在 Consul 服务中心注册的服务类别名称,多个实例的 ID 可以属于一个服务类别名称。</param>
     37         /// <param name="serviceID">服务实例的主键值,必须唯一。</param>
     38         public static void ConsulRegist(this IConfiguration configuration, string consulServiceName, string serviceID)
     39         {
     40             if (string.IsNullOrEmpty(consulServiceName) || string.IsNullOrWhiteSpace(consulServiceName))
     41             {
     42                 throw new ArgumentNullException("consulServiceName is null");
     43             }
     44             if (string.IsNullOrEmpty(serviceID) || string.IsNullOrWhiteSpace(serviceID))
     45             {
     46                 throw new ArgumentNullException("serviceID is null.");
     47             }
     48 
     49             string consulAddress = configuration["ConsulAddress"];
     50             string consulCenter = configuration["ConsulCenter"];
     51             if (!string.IsNullOrEmpty(consulAddress) && !string.IsNullOrWhiteSpace(consulAddress))
     52             {
     53                 Uri = new Uri(consulAddress);
     54             }
     55 
     56             if (!string.IsNullOrEmpty(consulCenter) && !string.IsNullOrWhiteSpace(consulCenter))
     57             {
     58                 DataCenter = consulCenter;
     59             }
     60 
     61             using (ConsulClient client = new ConsulClient(config =>
     62             {
     63                 config.Address = Uri;
     64                 config.Datacenter = DataCenter;
     65             }))
     66             {
     67                 string ip = configuration["ip"];
     68                 int port = int.Parse(configuration["port"]);                
     69                 int weight = string.IsNullOrWhiteSpace(configuration["weight"]) ? 1 : int.Parse(configuration["weight"]);
     70 
     71 
     72                 client.Agent.ServiceRegister(new AgentServiceRegistration()
     73                 {
     74                     ID = serviceID,
     75                     Name = consulServiceName,
     76                     Address = ip,
     77                     Port = port,
     78                     Tags = new string[] { weight.ToString() },
     79                     Check = new AgentServiceCheck()
     80                     {
     81                         Interval = TimeSpan.FromSeconds(12),
     82                         HTTP = $"http://{ip}:{port}/API/Health/Index",
     83                         Timeout = TimeSpan.FromSeconds(5),
     84                         DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(20)
     85                     }
     86                 }).Wait();
     87                 Console.WriteLine($"注册服务:{ip}:{port}--Weight:{weight}");
     88             };
     89         }
     90 
     91         /// <summary>
     92         /// 向 Consul 服务中心注销服务实例。
     93         /// </summary>
     94         /// <param name="applicationLifetime">配置对象。</param>
     95         /// <param name="serviceID">服务实例的主键值,必须唯一。</param>
     96         public static void ConsulDown(this IHostApplicationLifetime applicationLifetime, string serviceID)
     97         {
     98             if (string.IsNullOrEmpty(serviceID) || string.IsNullOrWhiteSpace(serviceID))
     99             {
    100                 throw new ArgumentNullException("serviceID is null");
    101             }
    102             applicationLifetime.ApplicationStopped.Register(() =>
    103             {
    104                 using (var consulClient = new ConsulClient(config => { config.Address = Uri; config.Datacenter = DataCenter; }))
    105                 {
    106                     Console.WriteLine("服务已经退出");
    107                     consulClient.Agent.ServiceDeregister(serviceID);
    108                 }
    109             });
    110         }
    111     }
    112 }


                            
    5】、修改 Startup.cs 类的 Configure 方法的代码。
                          
                
                       源码如下:

     1 using Microsoft.AspNetCore.Builder;
     2 using Microsoft.AspNetCore.Hosting;
     3 using Microsoft.Extensions.Configuration;
     4 using Microsoft.Extensions.DependencyInjection;
     5 using Microsoft.Extensions.Hosting;
     6 using PatrickLiu.MicroService.Interfaces;
     7 using PatrickLiu.MicroService.ServiceInstance.Extensions;
     8 using PatrickLiu.MicroService.Services;
     9 using System;
    10 
    11 namespace PatrickLiu.MicroService.ServiceInstance
    12 {
    13     /// <summary>
    14     /// 应用程序启动配置。
    15     /// </summary>
    16     public class Startup
    17     {
    18         /// <summary>
    19         /// 构造函数注入配置对象。
    20         /// </summary>
    21         /// <param name="configuration">配置对象</param>
    22         public Startup(IConfiguration configuration)
    23         {
    24             Configuration = configuration;
    25         }
    26 
    27         /// <summary>
    28         ///获取配置对象实例。
    29         /// </summary>
    30         public IConfiguration Configuration { get; }
    31 
    32         /// <summary>
    33         /// 配置注入容器的实例。
    34         /// </summary>
    35         /// <param name="services"></param>
    36         public void ConfigureServices(IServiceCollection services)
    37         {
    38             services.AddControllers();
    39             services.AddSingleton<IUserService, UserService>();
    40         }
    41 
    42         /// <summary>
    43         /// 配置 Http处理的管道。
    44         /// </summary>
    45         /// <param name="app">应用程序生成器。</param>
    46         /// <param name="env">Web宿主环境。</param>
    47         /// <param name="applicationLifetime">宿主应用程序的生命周期。</param>
    48         public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHostApplicationLifetime applicationLifetime)
    49         {
    50             #region 中间件配置
    51 
    52             if (env.IsDevelopment())
    53             {
    54                 app.UseDeveloperExceptionPage();
    55             }
    56 
    57             //app.UseHttpsRedirection();
    58 
    59             app.UseRouting();
    60 
    61             //增加认证环节
    62             app.UseAuthentication();//认证===============================
    63 
    64             app.UseAuthorization();//授权
    65 
    66             app.UseEndpoints(endpoints =>
    67             {
    68                 endpoints.MapControllers();
    69             });
    70 
    71             #endregion
    72 
    73             #region Consul 注册
    74 
    75             string serviceID = $"Service:{Configuration["ip"]}:{Configuration["port"]}---{Guid.NewGuid()}";
    76             string consuleServiceName = "PatrickLiuService";            
    77 
    78             //注册服务。
    79             Configuration.ConsulRegist(consuleServiceName, serviceID);
    80 
    81             //注销服务
    82             applicationLifetime.ConsulDown(serviceID);
    83 
    84             #endregion
    85         }
    86     }
    87 }


                            
    6】、增加4个配置JSON文件。
                         
                 appsettings5726.json
                                          

                                       appsettings5727.json
                                          
                                       appsettings5728.json
                                           
                                       appsettings5729.json
                                          

                             7】、增加docker-compose.yml批处理了文件。
                         
                                        代码如下:
                        

     1 version: '3.3'
     2 services:
     3     service1:
     4         container_name: serviceInstance_5726
     5         environment: 
     6             - ASPNETCORE_ENVIRONMENT=Production
     7         build: 
     8             context: /root/microService/sourceCode/project/PatrickLiu.MicroService.Docker
     9         image: compose-net5.0v1.202125
    10         ports: 
    11             - 5726:80/tcp
    12         volumes: 
    13             - /root/microService/config/appsettings/appsettings5726.json:/app/appsettings.json
    14   
    15     service2:  
    16         container_name: serviceInstance_5727
    17         environment: 
    18             - ASPNETCORE_ENVIRONMENT=Production
    19         image: compose-net5.0v1.202125
    20         ports: 
    21             - 5727:80/tcp
    22         command: ["dotnet","/app/publish/PatrickLiu.MicroService.ServiceInstance.dll"]
    23         volumes:
    24             - /root/microService/config/appsettings/appsettings5727.json:/app/appsettings.json
    25 
    26     service3:
    27         container_name: serviceInstance_5728
    28         environment: 
    29             - ASPNETCORE_ENVIRONMENT=Production
    30         image: compose-net5.0v1.202125
    31         ports:
    32             - 5728:80/tcp
    33         command: ["dotnet","/app/publish/PatrickLiu.MicroService.ServiceInstance.dll"]
    34         volumes:
    35             - /root/microService/config/appsettings/appsettings5728.json:/app/appsettings.json
    36 
    37     service4:   
    38         container_name: serviceInstance_5729
    39         environment: 
    40             - ASPNETCORE_ENVIRONMENT=Production
    41         image: compose-net5.0v1.202125
    42         ports:
    43             - 5729:80/tcp
    44         command: ["dotnet","/app/publish/PatrickLiu.MicroService.ServiceInstance.dll"]
    45         volumes:
    46             - /root/microService/config/appsettings/appsettings5729.json:/app/appsettings.json


                    (6)、PatrickLiu.MicroService.Gateway(ASP.NET CORE WEBAPI),网关服务。
                               

                              【1】、安装Ocelot组件,可以实现针对服务管理工作,如:缓存等。
                                        在【程序包管理器控制台】执行命令
                                        命令:Install-Package Ocelot
                                        
                                        当然也可以在项目下的【依赖项】上点右键,点击【管理NuGet程序包】菜单,在【浏览】项先安装,输入Ocelot,在右侧安装则可以。

                              【2】、安装Ocelot.Provider.Consul组件,以实现Ocelot和Consul的组合。
                                         在【程序包管理器控制台】执行命令。
                                         命令:Install-Package Ocelot.Provider.Consul
                                         
                                         当然也可以在项目下的【依赖项】上点右键,点击【管理NuGet程序包】菜单,在【浏览】项先安装,输入Ocelot.Provider.Consul,在右侧安装则可以。

                              【3】、配置Startup.cs文件。
                                         
                        源码如下:

     1 using IdentityServer4.AccessTokenValidation;
     2 using Microsoft.AspNetCore.Builder;
     3 using Microsoft.AspNetCore.Hosting;
     4 using Microsoft.Extensions.Configuration;
     5 using Microsoft.Extensions.DependencyInjection;
     6 using Ocelot.Cache.CacheManager;
     7 using Ocelot.DependencyInjection;
     8 using Ocelot.Middleware;
     9 using Ocelot.Provider.Consul;
    10 using Ocelot.Provider.Polly;
    11 
    12 namespace PatrickLiu.MicroService.Gateway
    13 {
    14     /// <summary>
    15     /// 1、Ocelot 提供网关功能
    16     /// 2、Ocelot.Provider.Polly 提供服务治理
    17     /// 3、Ocelot.Provider.Consul 提供服务发现
    18     /// 4、Ocelot.Cache.CacheManager 提供缓存功能。
    19     /// </summary>
    20     public class Startup
    21     {
    22         /// <summary>
    23         /// 通过构造函数初始化配置对象。
    24         /// </summary>
    25         /// <param name="configuration">配置对象。</param>
    26         public Startup(IConfiguration configuration)
    27         {
    28             Configuration = configuration;
    29         }
    30 
    31         /// <summary>
    32         /// 获取配置对象。
    33         /// </summary>
    34         public IConfiguration Configuration { get; }
    35 
    36         /// <summary>
    37         /// 配置服务。
    38         /// </summary>
    39         /// <param name="services">服务容器。</param>
    40         public void ConfigureServices(IServiceCollection services)
    41         {
    42             #region 1、在网关中增加鉴权模块
    43 
    44             var authenticationProviderKey = "UserGatewayKey";
    45             services.AddAuthentication("Bearer")
    46                 .AddIdentityServerAuthentication(authenticationProviderKey, options =>
    47                 {
    48                     options.Authority = "http://192.168.127.141:7200";
    49                     options.ApiName = "UserApi";
    50                     options.RequireHttpsMetadata = false;
    51                     options.SupportedTokens = SupportedTokens.Both;
    52                 });
    53 
    54             #endregion
    55 
    56             #region 2、配置网关、网关缓存和服务治理
    57 
    58             services.AddOcelot()//使用 Ocelot 网关服务。
    59                 .AddConsul()//使用Consul 服务发现控制器。
    60                 .AddCacheManager(builer => builer.WithDictionaryHandle()) //使用 Ocelot 缓存服务
    61                 .AddPolly();//支持瞬态故障库----超时、熔断、限流、降级、雪崩效应等都可以做
    62 
    63             #endregion
    64         }
    65 
    66         /// <summary>
    67         /// 配置中间件。
    68         /// </summary>
    69         /// <param name="app">应用程序生成器。</param>
    70         /// <param name="env">Web宿主环境。</param>
    71         public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    72         {
    73             app.UseOcelot();//配置使用 Ocelot 网关中间件。
    74         }
    75     }
    76 }


                              【4】、增加JSON配置文件,文件名:configuration.json。
                                         
                        源码如下:
                        

     1 //4、************************************* Ocelot 网关 + Consul 服务发现 *************************************
     2   "Routes": [
     3     {
     4       "DownstreamPathTemplate": "/api/{url}",
     5       "DownstreamScheme": "http",
     6       "UpstreamPathTemplate": "/gate/{url}",
     7       "UpstreamHttpMethod": [ "Get", "Post" ],
     8       "UseServiceDiscovery": true,
     9       "ServiceName": "PatrickLiuService",
    10       "LoadBalancerOptions": { "Type": "RoundRobin" }
    11     }
    12   ],
    13   "GlobalConfiguration": {
    14     "BaseUrl": "http://192.168.127.141:6299",
    15     "ServiceDiscoveryProvider": {
    16       "Host": "192.168.127.141",
    17       "Port": 8089,
    18       "Type": "Consul",
    19       "PollingInterval": 1000,//轮训 Consul,频率毫秒
    20       "Token": "footoken"//需要ACL的话
    21     }
    22   }


                              【5】、修改 Program.cs 文件,使用上面增加的JSON配置文件。
                                       

                    (7)、PatrickLiu.MicroService.AuthenticationCenter(ASP.NET CORE WEBAPI),鉴权、授权中心,也可以称“认证服务器”。
                                 

                               【1】、要想认证,必须安装IdentityServer4。
                                          命令:Install-Package IdentityServer4
                                          
                                          当然也可以在项目下的【依赖项】上点右键,点击【管理NuGet程序包】菜单,在【浏览】项先安装,输入IdentityServer4,在右侧安装则可以。

                               【2】、修改 Startup.cs文件。
                                          

                               【3】、增加一个类型 ClientInitConfig.cs文件。
                                         
                                         代码样例:
                                          

     1 using IdentityServer4.Models;
     2 using System.Collections.Generic;
     3 
     4 namespace PatrickLiu.MicroService.AuthenticationCenter
     5 {
     6     /// <summary>
     7     /// 
     8     /// </summary>
     9     public class ClientInitConfig
    10     {
    11         /// <summary>
    12         /// 
    13         /// </summary>
    14         /// <returns></returns>
    15         public static IEnumerable<ApiScope> GetApiScopes()
    16         {
    17             return new List<ApiScope>
    18             {
    19                 //User API 
    20                 new ApiScope(name: "User.Get",   displayName: "获取用户数据"),                
    21 
    22                 // Health API
    23                 new ApiScope(name: "Health.Check",    displayName: "健康检查."),                
    24             };
    25         }
    26 
    27         /// <summary>
    28         /// 能访问的资源权限。
    29         /// </summary>
    30         /// <returns></returns>
    31         public static IEnumerable<ApiResource> GetApiResources()
    32         {
    33             return new List<ApiResource>
    34             {
    35                 new ApiResource("UserApi","Invoice API")
    36                 {
    37                     Scopes={ "User.Get", "Health.Check" }
    38                 }
    39             };
    40         }
    41 
    42 
    43         /// <summary>
    44         /// 客户端的认证条件。
    45         /// </summary>
    46         /// <returns></returns>
    47         public static IEnumerable<Client> GetClients()
    48         {
    49             return new List<Client> {
    50                 new Client{
    51                  ClientId="PatrickLiu.MicroService.AuthenticationDemo",
    52                  ClientSecrets={new Secret("PatrickLiu123456".Sha256()) },
    53                  AllowedGrantTypes=GrantTypes.ClientCredentials,
    54                  AllowedScopes=new[]{ "User.Get", "Health.Check" },
    55                  Claims=new List<ClientClaim>(){
    56                  new ClientClaim(IdentityModel.JwtClaimTypes.Role,"Admin"),
    57                  new ClientClaim(IdentityModel.JwtClaimTypes.NickName,"PatrickLiu"),
    58                  new ClientClaim("eMail","PatrickLiu@sina.com")
    59                  }
    60                 }
    61             };
    62         }
    63     }
    64 }


            2、编译【PatrickLiu.MicroService.ServiceInstance】项目,发布4个服务实例,独立进程承载,形成服务集群。

                     
    再次提醒大家,在开始启动这4个服务实例之前,必须启动Consul服务中心。
                    (1)、将【PatrickLiu.MicroService.ServiceInstance】项目编译无误后,然后将项目源码上传至Linux服务器。                  
                               服务器路径为:/root/microService/sourceCode/project
                               

                    (2)、为【PatrickLiu.MicroService.ServiceInstance】项目增加4个appsettings.json配置文件,并将配置文件上传至Linux服务器。
                               服务器路径为:/root/microService/config/appsettings
                                

                    (3)、为【PatrickLiu.MicroService.ServiceInstance】项目增加Nginx配置文件,并上传至Linux服务器。
                               服务器路径为:/root/microService/config/nginx
                                 
                  
                          
                    (4)、为【PatrickLiu.MicroService.ServiceInstance】项目增加docker-compose.yml配置文件,并上传至Linux服务器。该文件一般建议存放在项目的根目录,如果存在解决方案,则存放在解决方案的根目录。
                                 服务器路径为:/root/microService/sourceCode/project/PatrickLiu.MicroService.Docker
                                  
                  Docker-Compose.yml文件的内容:

     1 version: '3.3'
     2 services:
     3     service1:
     4         container_name: serviceInstance_5726
     5         environment: 
     6             - ASPNETCORE_ENVIRONMENT=Production
     7         build: 
     8             context: /root/microService/sourceCode/project/PatrickLiu.MicroService.Docker
     9         image: compose-net5.0v1.202125
    10         ports: 
    11             - 5726:80/tcp
    12         volumes: 
    13             - /root/microService/config/appsettings/appsettings5726.json:/app/appsettings.json
    14   
    15     service2:  
    16         container_name: serviceInstance_5727
    17         environment: 
    18             - ASPNETCORE_ENVIRONMENT=Production
    19         image: compose-net5.0v1.202125
    20         ports: 
    21             - 5727:80/tcp
    22         command: ["dotnet","/app/publish/PatrickLiu.MicroService.ServiceInstance.dll"]
    23         volumes:
    24             - /root/microService/config/appsettings/appsettings5727.json:/app/appsettings.json
    25 
    26     service3:
    27         container_name: serviceInstance_5728
    28         environment: 
    29             - ASPNETCORE_ENVIRONMENT=Production
    30         image: compose-net5.0v1.202125
    31         ports:
    32             - 5728:80/tcp
    33         command: ["dotnet","/app/publish/PatrickLiu.MicroService.ServiceInstance.dll"]
    34         volumes:
    35             - /root/microService/config/appsettings/appsettings5728.json:/app/appsettings.json
    36 
    37     service4:   
    38         container_name: serviceInstance_5729
    39         environment: 
    40             - ASPNETCORE_ENVIRONMENT=Production
    41         image: compose-net5.0v1.202125
    42         ports:
    43             - 5729:80/tcp
    44         command: ["dotnet","/app/publish/PatrickLiu.MicroService.ServiceInstance.dll"]
    45         volumes:
    46             - /root/microService/config/appsettings/appsettings5729.json:/app/appsettings.json


                    (5)、为【PatrickLiu.MicroService.ServiceInstance】项目增加Dockerfile配置文件,并将该配置文件上传至服务器,建议该文件存放在项目根目录,如果是解决方案,那就存放在解决方案的根目录。
                                服务器路径为:/root/microService/sourceCode/project/PatrickLiu.MicroService.Docker
                                 
                  Dockerfile文件的内容:              

     1 #See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
     2 
     3 FROM mcr.microsoft.com/dotnet/aspnet:5.0-buster-slim AS base
     4 WORKDIR /app
     5 EXPOSE 80
     6 EXPOSE 443
     7 
     8 FROM mcr.microsoft.com/dotnet/sdk:5.0-buster-slim AS build
     9 WORKDIR /src
    10 COPY ["PatrickLiu.MicroService.ServiceInstance/PatrickLiu.MicroService.ServiceInstance.csproj", "PatrickLiu.MicroService.ServiceInstance/"]
    11 COPY ["PatrickLiu.MicroService.Interfaces/PatrickLiu.MicroService.Interfaces.csproj", "PatrickLiu.MicroService.Interfaces/"]
    12 COPY ["PatrickLiu.MicroService.Models/PatrickLiu.MicroService.Models.csproj", "PatrickLiu.MicroService.Models/"]
    13 COPY ["PatrickLiu.MicroService.Services/PatrickLiu.MicroService.Services.csproj", "PatrickLiu.MicroService.Services/"]
    14 RUN dotnet restore "PatrickLiu.MicroService.ServiceInstance/PatrickLiu.MicroService.ServiceInstance.csproj"
    15 COPY . .
    16 WORKDIR "/src/PatrickLiu.MicroService.ServiceInstance"
    17 RUN dotnet build "PatrickLiu.MicroService.ServiceInstance.csproj" -c Release -o /app/build
    18 
    19 FROM build AS publish
    20 RUN dotnet publish "PatrickLiu.MicroService.ServiceInstance.csproj" -c Release -o /app/publish
    21 
    22 FROM base AS final
    23 WORKDIR /app
    24 COPY --from=publish /app/publish .
    25 ENTRYPOINT ["dotnet", "PatrickLiu.MicroService.ServiceInstance.dll"]


                    (6)、通过docker-compose up 命令,启动4个服务实例和一个NGINX服务。执行 docker-compose up 命令,必须在docker-compose.yml文件所在的目录,docker-compose.yml和dockerfile两个文件最好都放在一个目录里,建议都存放在项目或者解决方案的根目录里。
                                 
                                命令:# docker-compose up –d,执行命令,后台运行,必须确保本地有Net5.0镜像,Net5.0的官方镜像拉取太慢,如果想提升镜像拉取速度,请查看我的文章《我教你如何解决 Docker 下载 mcr.microsoft.com 镜像慢的办法》。
                                                    
                  
                  

                    (7)、检查服务是否启动成功,是否正确注册Consul服务。
                               访问地址:http://192.168.127.141:8500
                                           http://192.168.127.141:9500
                                           http://192.168.127.141:10500
                                           http://192.168.127.141:11500
                                 任何一个地址都可以访问。
                                  

                    
                    (8)、所有服务都启动成功,包括Consul集群和4个服务实例一个Nginx服务。
                                  

                    (9)、配置Consul集群的Nginx代理服务,修改Nginx.conf配置文件。
                                服务器路径:/root/microService/config/consulNginx
                                 
                                修改配置文件:nginx.conf,进入当前目录,执行命令:vim nginx.conf
                                 

                    (10)、启动Consul集群的代理服务Nginx服务。
                                命令:#docker run -d -p 8089:80 -v /root/microService/config/consulNginxLog/:/var/log/nginx/ -v /root/microService/config/consulNginx/nginx.conf:/etc/nginx/nginx.conf --name consulnginx nginx
                                参数1:/root/microService/config/consulNginxLog/:/var/log/nginx/ 通过挂载将容器里面路径:/var/log/nginx/的nginx日志映射到容器外的这个目录:/root/microService/config/consulNginxLog/ 。
                                参数2:/root/microService/config/consulNginx/nginx.conf:/etc/nginx/nginx.conf 通过挂载文件用/root/microService/config/consulNginx/nginx.conf配置文件来替换/etc/nginx/nginx.conf配置文件。
                                

                    (11)、验证Consul集群的 Nginx 地址是否有效。
                               访问地址:http://192.168.127.141:8089/
                                

            3、编译【PatrickLiu.MicroService.Gateway】项目,发布3个网关服务实例,独立进程承载,形成服务集群。
             
                    (1)、为【PatrickLiu.MicroService.Gateway】项目增加Dockerfile文件,该文件上传到Linux服务器。该文件可以放到项目根目录,如果有解决方案就放在解决方案的根目录。
                             服务器路径:/root/microService/sourceCode/gateway
                             
                             Dockerfile文件的内容:
                             
                              如果使用官方的镜像,会报一下错误,内容很多,只是部分截图:
                              
                             Dockerfile文件增加的内容,二者选其一:
                              FROM mcr.microsoft.com/dotnet/sdk:5.0-alpine(慢点)
                                FROM mcr.microsoft.com/dotnet/sdk:5.0-focal

                    (2)、为【PatrickLiu.MicroService.Gateway】项目增加docker-compose.yml文件,该文件上传到Linux服务器。该文件可以放到项目根目录,如果有解决方案就放在解决方案的根目录。
                             服务器路径:/root/microService/sourceCode/gateway
                              
                               Docker-Compose.yml文件内容:
                              
                  源码如下:

     1 version: '3.3'
     2 services:
     3     service1:
     4         container_name: serviceOcelot_6297_GateWay
     5         environment: 
     6             - ASPNETCORE_ENVIRONMENT=Production
     7         build: 
     8             context: /root/microService/sourceCode/gateway
     9             dockerfile: PatrickLiu.MicroService.Gateway/Dockerfile
    10         image: compose-net5.0v1.202125-gateway
    11         ports: 
    12             - 6297:80/tcp
    13   
    14     service2:  
    15         container_name: serviceOcelot_6298_GateWay
    16         environment: 
    17             - ASPNETCORE_ENVIRONMENT=Production
    18         image: compose-net5.0v1.202125-gateway
    19         ports: 
    20             - 6298:80/tcp
    21         command: ["dotnet","/app/publish/PatrickLiu.MicroService.Gateway.dll"]
    22 
    23     service3:
    24         container_name: serviceOcelot_6299_GateWay
    25         environment: 
    26             - ASPNETCORE_ENVIRONMENT=Production
    27         image: compose-net5.0v1.202125-gateway
    28         ports:
    29             - 6299:80/tcp
    30         command: ["dotnet","/app/publish/PatrickLiu.MicroService.Gateway.dll"]     
    31 
    32     nginx:
    33         container_name: serviceOcelotNginx_8083_GateWay
    34         image: nginx:latest
    35         ports:
    36             - 8083:80/tcp
    37         restart: always
    38         volumes:
    39             - /root/microService/config/gatewayNginx/nginx.conf:/etc/nginx/nginx.conf


                    (3)、为【PatrickLiu.MicroService.Gateway】项目增加configuration.json配置文件,该文件上传到Linux服务器。
                               

                    (4)、使用docker-compose up -d 命令进行批处理,启动3个网关实例和一个NGINX服务。在执行该命令之前,必须切换到docker-compose.yml文件所在的目录,并且dockerfile文件也要在当前目录下。
                                 

                                 命令:#docker-compose up –d
                                 
                                 中间还有很多内容,省略了。。。
                                 
                      
                    (5)、我们网关启动完成后,可以通过docker-compose ps命令查看服务是否启动正常,执行该命令必须在docker-compose.yml文件所在的目录,切记。
                                 命令:#docker-compose ps
                                  

                    (6)、开始验证,在客户端访问我们的客户端是否可以获得数据(这里本地数据)。
                         

                               第一网关地址:http://192.168.127.141:6297/gate/users/all,能获取到数据表示一切成功。
                                  截图如下:
                                         
                                       刷新地址
                                         

                               第二网关地址:http://192.168.127.141:6298/gate/users/all,能获取到数据表示一切成功。
                                  截图如下:
                                         
                                       刷新地址
                                         

                               第三网关地址:http://192.168.127.141:6299/gate/users/all,能获取到数据表示一切成功。
                                  截图如下:
                                          
                                       刷新地址
                                          

                    (7)、Ocelot网关集群的Nginx服务已经在Docker-compose.yml配置启动。
                                目录地址:/root/microService/config/gatewayNginx/nginx.conf
                                配置信息:
                                          
                                       以下是docker-compose.yml有关nginx配置。
                                         

                     (8)、验证Ocelot网关集群的Nginx服务地址。
                               Nginx地址:http://192.168.127.141:8083/gate/users/all,能获取到数据表示一切成功。
                                   截图如下:
                                          
                                       刷新地址后
                                          
                          完美完成负载均衡,心里有些小激动。说明:客户端程序要访问的地址就是这个地址:http://192.168.127.141:8083/gate/users/all

            4、编译【PatrickLiu.MicroService.AuthenticationCenter】项目,发布鉴权、授权中心实例,独立进程承载,形成服务集群。

                     (1)、将【PatrickLiu.MicroService.AuthenticationCenter】项目源码上传到Linux服务器,并将Dockerfile文件存放在更目录。
                                
                                
    Dockerfile 文件内容:
                                
                     (2)、将【PatrickLiu.MicroService.AuthenticationCenter】项目生成镜像文件,切换到Dockerfile文件所在目录,执行生成镜像的命令。
                                命令:#docker build --no-cache -t authentor3.0v202127 -f Dockerfile .
                                 
                                 中间省略很多步骤。。。
                                 

            
            (3)、查看我们生成鉴权中心的镜像。
                                命令:#docker images
                                

                     (4)、查看我们生成鉴权中心的镜像。
                                命令:#docker run -itd -p 7200:80 authentor3.0v202127
                                

                     (5)、查看我们生成鉴权中心的容器实例。
                                命令:#dockder ps –a
                                 

                     (6)、通过PostMan来测试我们鉴权中心是否正常运行。
                                post 请求                 http://192.168.127.141:7200/connect/token

                  
                      
                     (7)、我们的网关设置了权限,现在要访问就要增加token,否则无权访问,返回403。
                                

                     (8)、基于Jwt.io网站验证Token数据。
                               访问地址:https://jwt.io/
                               

    三、在Linux系统中基于Docker容器搭建的微服务,我们通过客户端来看一下效果。
                 
            1、所有环境都在虚拟机上,客户端程序在本地,看看我辛苦的成果吧。
             
                     客户端我们自己实现的轮训策略,每次刷新,端口号都变,效果如图:

                        5726端口的数据:
                             

                        5727端口的数据:
                             

                        5728端口的数据:
                             

                        5729端口的数据:
                             

          2、我们的结论。
                  我们今天的测试虽然完成了,但是还是有很多要改进的地方,比如很多地方我们都可以使用Docker-Compose代替Dockerfile文件,单节点的Docker环境也是问题,可以把环境迁到K8s上,还有其他很多问题,这不是我们最后一版,我们继续努力,完善它。
             

    四、结束语
            
    好了,今天就写到这里了。这篇文章也花费了我两周的时间,解决NetCore3.1到Net5.0上所遇到的问题,坑真实不少。在Docker环境中部署东西,或者说在虚拟环境中部署东西,是有一些不一样的,有好处,当然也有弊端。不做不知道,做了才知道问题的多多。俗话说,兵来将挡水来土掩,只要我们勇往直前,道路一定是光明的,再者说,老天不会饿死努力的小鸟的。努力吧,每天进步一点点。

    天下国家,可均也;爵禄,可辞也;白刃,可蹈也;中庸不可能也
  • 相关阅读:
    【深入理解JAVA虚拟机】第一部分.走进Java
    【设计模式最终总结】桥接模式 VS 外观模式
    【设计模式最终总结】组合模式:树形结构的处理
    【设计模式最终总结】桥接模式(接口模式):处理多维度变化
    【设计模式最终总结】适配器模式
    深入编解码:ASCII,UNICODE,UTF8等
    好妈妈【第四章】培养良好的学习习惯
    【设计模式最终总结】建造者模式:复杂对象的组装与创建
    上火流鼻血
    Spring Data Jpa 学习笔记
  • 原文地址:https://www.cnblogs.com/PatrickLiu/p/14393664.html
Copyright © 2011-2022 走看看