庐山真面目之十二微服务架构基于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模式不可以。
-ui:consul运行后,会提供一个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环境中部署东西,或者说在虚拟环境中部署东西,是有一些不一样的,有好处,当然也有弊端。不做不知道,做了才知道问题的多多。俗话说,兵来将挡水来土掩,只要我们勇往直前,道路一定是光明的,再者说,老天不会饿死努力的小鸟的。努力吧,每天进步一点点。