写点什么

微服务框架搭建过五关斩六将—第一关 (网关)

作者:为自己带盐
  • 2022 年 9 月 28 日
    河北
  • 本文字数:5774 字

    阅读完需:约 19 分钟

微服务框架搭建过五关斩六将—第一关(网关)

闯关之前

原由

我们线上的一个项目,之前是通过 nginx 做了简单的分布式,但每次更新维护仍然是人肉的方式进行,效率低下,而且随着日益多样化的需求和节节攀升的访问量,项目本身已经负重不堪,寸步难行,项目改造已经是迫在眉睫。

而当下这个时代,正式云原生的时代,微服务作为云原生开发体系中核心的环节,作为改造方向最为合适。对我们这个团队来讲,虽然在微服务框架的经验非常欠缺,但单体应用在未来已经没有任何生存空间,商量过后,决定长痛不如短痛,做好了 all in cloud 的心理准备,全面开干!

总的来说就是四个字,大势所趋!

盘点

因为是摸着石头过河,所以我觉得很多经验还是非常宝贵的,甚至可能会给一些还没有接触过微服务架构的同学带来一点点经验。

那么在开始闯关之前,我做的第一件事,就是盘点了一下要做的这个项目现在都有些什么,主要是从业务层面,目的是划分服务边界。

经过一番总结,大概生成了这样一张草图👇


因为也是第一次从头到尾,来设计微服务的框架,所以进行的很慢,甚至每走一步都要查很多资料,做很多可行性验证,造成了前期探索的时间比较长,这也就引出了今天的话题 —— 网关。

对了,我这里还想再简单说两句为什么微服务架构要用网关。

它是整个框架系统的入口,当我们把单体应用以某种形式分割成数个微服务应用之后,会带来一系列问题,比如便利性的问题,单体应用我们基本项目跑起来之后,通过接口地址,前后配合就可以进行业务开发了,但微服务不同,多个项目分别部署,会产生多个接口地址,给开发和测试都造成困扰。

再比如安全性问题,单体应用的认证,只需要访问应用的地址,进行授权认证就可以了,而微服务又不一样,不可能每个服务都单独上一套认证模块吧。

还有很多,诸如此类在单体应用很简单,到了微服务应用变得很复杂的问题,而为了让微服务开发也尽可能的减少这种复杂性,提示把我们的系统变得易于横向扩展,网关技术就应运而生了。

所以,网关就是整个微服务架构的门户,相当的重要!

第一关

选型

因为懂得少,所以走的慢。为了给项目找一个合适的网关,我翻了很多资料,基本确定了几个方向,分别是

ocelot,kong,envoy 和 apisix。


因为是我们现在用的方案是 nginx,而且它的定位也只是做的反向代理,公司所有项目的出口都是通过 nginx 做的反代。怎么说呢,虽然 nginx 小巧强悍,但在扩展性上还是差了一些,也不利于二次开发,配置文件也不算简单,所以在选型的时候就直接抛弃~~对不起,也可能是我对 nginx 懂得太少~~


那这几个怎么选呢?网上的资料说什么的都有,我的做法非常简单粗暴——既然不懂,而且时间也允许,那就挨个都试试吧(浅试,浅试~)!

ocelot

我最先尝试的 ocelot,因为我们是微软技术栈,而 ocelot 本身就是用 dotnetcore 开发的,算是老乡见老乡两眼泪汪汪那种感觉!

实际的上手体验,也让我发现,用 ocelot 来做微服务的网关代理入口,也是非常不错的一个选择。我根据官方的文档,本地跑通了用 ocelot 作为网关的案例。

安装

新建一个 webapi 项目,然后直接在程序包管理控制台输入命令安装 ocelot

Install-Package Ocelot
复制代码

或者在 nuget 包中搜索 ocelot,选择 ocelot,安装即可

截止到 2022.9.28,最新的版本是 18.0.0


配置

根据文档的指引,创建一个 ocelot.json 的配置文件,这个文件,官方给的案例里有一个快速上手的配置,直接拷过来就可以用,然后我这里把我这个测试的配置也贴出来,加上了我新增的两个 API。

{  "Routes": [    {    //官方的案例      "DownstreamPathTemplate": "/todos/{id}",      "DownstreamScheme": "https",      "DownstreamHostAndPorts": [        {          "Host": "jsonplaceholder.typicode.com",          "Port": 443        }      ],      "UpstreamPathTemplate": "/todos/{id}",      "UpstreamHttpMethod": [ "Get" ]    },    // API:Front-Reader.API    {      "DownstreamPathTemplate": "/{url}",      "DownstreamScheme": "http",      "DownstreamHostAndPorts": [        {          "Host": "localhost",          "Port": 6001        }      ],      "UpstreamPathTemplate": "/FrontReader/{url}",      "UpstreamHttpMethod": [ "Get", "Post" ]    },    // API:Back-Manager.API    {      "DownstreamPathTemplate": "/{url}",      "DownstreamScheme": "http",      "DownstreamHostAndPorts": [        {          "Host": "localhost",          "Port": 6002        }      ],      "UpstreamPathTemplate": "/BackManager/{url}",      "UpstreamHttpMethod": [ "Get", "Post" ]    }  ],
"GlobalConfiguration": { "BaseUrl": "https://localhost:7279" }}
复制代码


这个配置里,有几个关键的参数,文档里也有说明,我这里简单啰嗦两句

  1. DownstreamPathTemplate:实际代理的接口的访问路径,

  2. DownstreamScheme:协议,http 或者 https

  3. DownstreamHostAndPorts:这个就是代理的接口地址的地址,包括 host 和 port,host 可以是 ip 也可以是域名

  4. UpstreamPathTemplate:代理后的地址,也就是用户实际访问的地址,比如原来的接口访问地址是:http://www.a.com/api/action,http://www.b.com/api/action,设置代理地址后,就是 http://www.one.com/aapi/action,http://www.one.com/bapi/action.

  5. UpstreamHttpMethod:请求方法,get,post

注意,这里的配置和 nginx 配置代理转发很相似,只不过,nginx 的配置里,upstream 代表的是上游服务,但在 ocelot 的 upstream 是下游,含义是相反的,我当时就在这里栽了一下。

配置好后,在 Program.cs 文件里添加如下代码(我这里用的是.net6,如果是之前的框架,需要到 startup.cs 里进行配置)

var builder = WebApplication.CreateBuilder(args);            IConfiguration configuration = new ConfigurationBuilder()                                        .AddJsonFile("ocelot.json")                                        .Build();            builder.Services.AddControllers();            builder.Services.AddOcelot(configuration);////添加Ocelot服务            var app = builder.Build();                        app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers(); app.UseOcelot().Wait();//使用Ocelot中间件 app.Run();
复制代码

看下效果

  • 这是通过代理访问文档里的接口👇

  • 这是通过代理访问自己的接口👇


小结

由于是在摸索阶段,后续的集成,包括 ocelot 和缓存,认证,服务发现,日志等配套的集成我就没有在继续了,但可以肯定这些都是支持的。实际上我们的这个项目用 ocelot 也是完全没有问题的,它足够简单,而且配套也很完善,但我们最终还是没有选择 ocelot,有以下几个原因

  • 官方文档有点老,最新的 ocelot 已经注明了支持.net6,但文档的相关内容却没有跟上,很多介绍还是按照原来 ocelot 版本来的;

  • 没有中文文档,如此重要的微服务组件,我不想根据一些零散的中文博客来搭建,还是得靠文档,而大段的英文内容对理解实在是一种考验;

  • ocelot 不是无侵入的,而且后续的插件引用,有一定的开发成本,虽然成本很低,但它还是和项目本身是一种强绑定关系;

  • 有更好的选择,而且都是平台无关的,可以做到无侵入,高性能,扩展性更加丰富,更适合当下的云原生时代。


Kong & Envoy

这两个我都试了一下,但最终也没有用它们,主要原因其实就一个——那就是中文资料偏少,全都翻英文资料,影响效率,这只是我个人的感觉,其实一般的小插件,我还是原因去翻英文文档的,因为内容不太多,理解起来难度不大,但网关毕竟是一个比较大的应用,文档内容非常多,尤其在摸索阶段,全英文的文档会对我产生困扰。

这里也简单的记录一下使用的经历吧

Kong

关于 Kong 的尝试,我是看到了一位博主最近再写相关的内容,写的挺详细的,然后我就按照它的方案,简单尝试了一下,原文地址在这里👉:https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzA4NzQzNTg4Ng==&action=getalbum&album_id=2553351441126653953&scene=173&from_msgid=2651739319&from_itemidx=1&count=3&nolastread=1#wechat_redirect

Kong 的介绍,大家还是到官方网站去了解,我这里只简单介绍一下

  • 安装

kong 时依赖 postgresql 的,所以也要同步安装 pg。我按照上述博主的方案,通过 docker-compose 的形式进行的安装,docker-compose.yaml 文件如下

version: "3.8"
volumes: kong_data: {}
networks: kong-net:
services: ####################################### # Postgres: The database used by Kong ####################################### kong-database: image: postgres:10 container_name: kong-postgres restart: on-failure networks: - kong-net volumes: - kong_data:/var/lib/postgresql/data environment: POSTGRES_USER: kong POSTGRES_PASSWORD: ${KONG_PG_PASSWORD:-kong} POSTGRES_DB: kong ports: - "5432:5432" healthcheck: test: ["CMD", "pg_isready", "-U", "kong"] interval: 30s timeout: 30s retries: 3
####################################### # Kong database migration ####################################### kong-migration: image: ${KONG_DOCKER_TAG:-kong:latest} command: kong migrations bootstrap networks: - kong-net restart: on-failure environment: KONG_DATABASE: postgres KONG_PG_HOST: kong-database KONG_PG_DATABASE: kong KONG_PG_USER: kong KONG_PG_PASSWORD: ${KONG_PG_PASSWORD:-kong} depends_on: - kong-database
####################################### # Kong: The API Gateway ####################################### kong: image: ${KONG_DOCKER_TAG:-kong:latest} restart: on-failure networks: - kong-net environment: KONG_DATABASE: postgres KONG_PG_HOST: kong-database KONG_PG_DATABASE: kong KONG_PG_USER: kong KONG_PG_PASSWORD: ${KONG_PG_PASSWORD:-kong} KONG_PROXY_LISTEN: 0.0.0.0:8000 KONG_PROXY_LISTEN_SSL: 0.0.0.0:8443 KONG_ADMIN_LISTEN: 0.0.0.0:8001 depends_on: - kong-database healthcheck: test: ["CMD", "kong", "health"] interval: 10s timeout: 10s retries: 10 ports: - "8000:8000" - "8001:8001" - "8443:8443" - "8444:8444"
####################################### # Konga database prepare ####################################### konga-prepare: image: pantsel/konga:latest command: "-c prepare -a postgres -u postgresql://kong:${KONG_PG_PASSWORD:-kong}@kong-database:5432/konga" networks: - kong-net restart: on-failure depends_on: - kong-database
####################################### # Konga: Kong GUI ####################################### konga: image: pantsel/konga:latest restart: always networks: - kong-net environment: DB_ADAPTER: postgres DB_URI: postgresql://kong:${KONG_PG_PASSWORD:-kong}@kong-database:5432/konga NODE_ENV: production depends_on: - kong-database ports: - "1337:1337"
复制代码


这段配置里,除了安装了 kong,pg 还有一个来着社区的管理 UI——Konga,因为官方的 Kong Konnect 是收费的,只有 14 天的试用期,而且价格不菲~


而 Konga 来自社区,免费,也很好用。

执行脚本

docker-compose up -d
复制代码

上面的脚本执行完成后,如果你也用的 windows 作为的开发机器,那可以在 dockerdesktop 里看到容器的运行情况


在 linux 里也可以通过命令行来查看


好了,就可以打开 konga 的界面了,设置 kong 的 admin url,注意端口号是 8001


然后根据提示,设置账号密码,就可以进入主界面

接下来就是配置代理服务,和 ocelot 是一样的,不过这里有一个可视化的操作界面,更加的友好。

具体的配置流程,我上面贴的那个链接里也有详细介绍,这里还是只简单罗嗦两句

  • 在 SERVICES 栏目里,点击【ADD NEW SERVICE】,根据页面提示填写信息,实际就是填写实际代理的接口地址信息


  • 配置路由,进入【ROUTES】栏目,新建/编辑路由,页面提示也比较全,根据提示操作即可,我这里圈几个关键点



  • 增加上游服务,这就是要指定实际的后台访问接口了,进入【UPSTREAMS】栏目,新增/编辑 upstream,也是根据提示填写即可,比较易懂,需要注意的是,upstream 里的【Name】属性和上面服务和路由里填的要保持一致,另外,healthcheck 的地址需要自己配置


  • 上游服务配置完成后,填写【Targets】,就是配置 ip 和端口号了,配置完成后,如果上面的操作配置了健康检查地址,可以开启健康检查(如果健康检查失效,进行代理访问会失败,所以即便开始配置时没有配置健康检查,后续也要补上这一步,健康检查的接口方法需要自己在实际的服务接口里实现)


  • 修改 hosts,把我们配置的自定义域名和 hosts 文件绑定一下

然后,就可以通过自定义域名访问接口了,效果如下

注意 kong 的代理端口是 8000,本地通过自定义的域名访问时,需要加上端口号。

看起来不错!

Envoy

再来简单说下,envoy 我在本地试了一下官方提供的镜像资源,也按照官方的指引,试了一下默认配置和自定义配置的区别

总体来说,envoy 的使用体验也很好,但我看到它的配置文件时,我被劝退了,所以就直接 pass 掉了。

它和 k8s 的配置文件很像,但又有一些区别,总之给我的第一感觉就是有点眼花缭乱,所以我就凭着感觉也 pass 掉 envoy 了


这里需要多说一句,虽然我个人鼠目寸光没有采用 envoy,但实际上国内外很多大厂都在用,好像网易和 BillBill 的一些产品网关就是用的 Envoy,它还是非常厉害的软件的!


APISIX

最终的选择还是国家级选手 APISIX 啊,但我发现文章写到这里已经太长了啊,在从头开始介绍实在是长篇大论了,所以这篇就先到这吧,下篇再继续聊~~

发布于: 刚刚阅读数: 6
用户头像

学着码代码,学着码人生。 2019.04.11 加入

狂奔的小码农 http://www.tonydf.top (这是个循环圈)

评论

发布
暂无评论
微服务框架搭建过五关斩六将—第一关(网关)_微服务_为自己带盐_InfoQ写作社区