庐山真面目之十二微服务架构基于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文档://www.consul.io/docs
    Consul官网://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运行后,会提供一个//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服务是否安装成功。
             
             第一主服务器: //192.168.127.141:8500
                           第二从服务器: //192.168.127.141:9500
                           第三从服务器: //192.168.127.141:10500
                           Consul客户端: //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 = "//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="[email protected]", Role="Admin", LoginTime=DateTime.Now },
23             new User {ID=2,Name="洪熙官",Account="HongXiGuan",Password="HongXiGuan54667",Email="[email protected]", Role="Admin", LoginTime=DateTime.Now.AddDays(-5) },
24             new User {ID=3,Name="方世玉",Account="FangShiYu",Password="FangShiYu112233",Email="[email protected]", Role="Admin", LoginTime=DateTime.Now.AddDays(-30) },
25             new User {ID=4,Name="苗翠花",Account="MiaoCuiHua",Password="MiaoCuiHua887766",Email="[email protected]", Role="Admin", LoginTime=DateTime.Now.AddDays(-90) },
26             new User {ID=5,Name="严咏春",Account="YanYongChun",Password="YanYongChun09392",Email="[email protected]", 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("//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 = $"//{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 = "//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": "//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","[email protected]")
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服务。
                           访问地址://192.168.127.141:8500
                                       //192.168.127.141:9500
                                       //192.168.127.141:10500
                                       //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 地址是否有效。
                           访问地址://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)、开始验证,在客户端访问我们的客户端是否可以获得数据(这里本地数据)。
                     

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

        
                                   刷新地址
                            

        

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

        
                                   刷新地址
                            

        

                           第三网关地址://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地址://192.168.127.141:8083/gate/users/all,能获取到数据表示一切成功。
                               截图如下:
                             

        
                                   刷新地址后
                             

        
                      完美完成负载均衡,心里有些小激动。说明:客户端程序要访问的地址就是这个地址://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 请求                 //192.168.127.141:7200/connect/token

              
                  

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

        

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

        

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

                    5726端口的数据:
                  

      

                    5727端口的数据:
                  

      

                    5728端口的数据:
                  

      

                    5729端口的数据:
                  

      

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

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