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