写点什么

微服务从代码到 k8s 部署应有尽有系列(二、网关)

作者:万俊峰Kevin
  • 2022 年 2 月 16 日
  • 本文字数:2867 字

    阅读完需:约 9 分钟

微服务从代码到k8s部署应有尽有系列(二、网关)

我们用一个系列来讲解从需求到上线、从代码到 k8s 部署、从日志到监控等各个方面的微服务完整实践。


整个项目使用了 go-zero 开发的微服务,基本包含了 go-zero 以及相关 go-zero 作者开发的一些中间件,所用到的技术栈基本是 go-zero 项目组的自研组件,基本是 go-zero 全家桶了。


实战项目地址:https://github.com/Mikaelemmmm/go-zero-looklook

1. go-zero 网关概念

go-zero 架构往大的说主要由两部分组成,一个是 api,一个是 rpc。api 主要是 http 对外访问的,rpc 主要就是内部业务交互使用的是 protobuf+grpc,当我们项目体量还不大的时候,我们可以使用 api 来做一个单体项目,等后续量上来之后,可以拆分到 rpc 做微服务,从单体转向微服务十分容易,很像 java 的 springboot 转像 springcloud,非常方便。


api 被很多同学理解成了网关,实际意义上来说当你的项目在使用 go-zero 做微服务时候,你把 api 当成网关也没什么大的问题,不过这样做导致的问题就是一个 api 对应后面多个 rpc,api 充当了网关,这样如果我在更新后续业务代码时候,更新任何业务都要去改动这个 api 网关,比如我只是改了一个小小的不起眼的服务,那就要重新构建整个 api,这样不太合理,效率极低也很不方便。所以,我们只是把 api 当成一个聚合服务,可以拆分成多个 api,比如用户服务有用户服务的 rpc 与 api,订单服务,有订单服务的 rpc 与 api,这样当我修改用户服务时候,我只需要更新用户的 rpc 与 api,所有的 api 只是用来聚合后端 rpc 的业务。那有的同学就会说,我总不能每个服务解析个域名对应你的 api 吧,当然不能,这时候 api 前面就要有一个网关了,这个网关才是真正意义上的网关,比如我们常说的 nginx、kong、apisix,很多微服务都内置了网关,比如 springcloud 提供了 springcloud-gateway , go-zero 没有提供,实际也用不着单独去写一个网关,市面上的网关已经够多了,go-zero 官方在晓黑板中用的 nginx 足够用了,当然你如果更熟悉 kong、apisix 都可以替换,本质上没什么不一样的,只是一个统一流量入口,统一鉴权等。

2. nginx 网关

【注】:在看这里的时候,建议先看一下前一节的业务架构图



本项目中实际也使用了 nginx 做为网关,使用 nginx 的 auth_request 模块作为统一鉴权,业务内部不做鉴权(设计到资产的最好业务内部做二次鉴权,主要多一层安全),nignx 的网关配置在项目的 data/nginx/conf.d/looklook-gateway.conf


server{    listen 8081;    access_log /var/log/nginx/looklook.com_access.log;    error_log /var/log/nginx//looklook.com_error.log;
location /auth { internal; proxy_set_header X-Original-URI $request_uri; proxy_pass_request_body off; proxy_set_header Content-Length ""; proxy_pass http://identity-api:8001/identity/v1/verify/token; }
location ~ /usercenter/ { auth_request /auth; auth_request_set $user $upstream_http_x_user; proxy_set_header x-user $user;
proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header REMOTE-HOST $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://usercenter-api:8002; }
location ~ /travel/ { auth_request /auth; auth_request_set $user $upstream_http_x_user; proxy_set_header x-user $user;
proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header REMOTE-HOST $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://travel-api:8003; }

location ~ /order/ { auth_request /auth; auth_request_set $user $upstream_http_x_user; proxy_set_header x-user $user;
proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header REMOTE-HOST $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://order-api:8004; }
location ~ /payment/ { auth_request /auth; auth_request_set $user $upstream_http_x_user; proxy_set_header x-user $user;
proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header REMOTE-HOST $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://payment-api:8005; }}
复制代码


容器内部 nginx 端口是 8081,使用 docker 暴露出去 8888 映射端口 8081,这样外部通过 8888 来访问网关,使用 location 来匹配每个服务,当然会有人说,每加一个 api 服务都要来 nignx 配置太麻烦,你也可以使用 confd 统一配置,自行百度。

3. 举例

当我们在访问用户服务时候, http://127.0.0.1:8888/usercenter/v1/user/detail , 访问了外部端口 8888,然后映射到 nginx 内部 looklook 网关 8081 上,然后 location 匹配到了/usercenter/ ,在该模块开始有一行 auth_request /auth, 所以 nginx 不会直接去请求 http://usercenter-api:8002 , 而是会先跳到 location /auth 模块中,auth 模块会访问 http://identity-api:8001/identity/v1/verify/token; ,identity-api 也是我们内部的服务,是由我们自己写的鉴权服务,实际也是用的 go-zero 的 jwt


进入 identity-api 只做了 2 件事情(具体可以看 looklook 项目中的 identity-api 代码)


1、判断当前访问的路由(usercenter/v1/user/detail )是否需要登录。这里的路由是否需要登录,可以在 identity-api 中配置,代码已经实现好了。



2、解析传递的 token 到 header 中


  • 如果当前访问的路由需要登录:

  • token 解析失败:就会返回给前端 http401 错误码;

  • token 解析成功:就会将解析出来的 userId 放入 header 的 x-user 中返回给 auth 模块,auth 模块会把 header 传递给对应访问的服务(usercenter), 这样我们在 usercenter 直接就可以拿到该登录用户的 id 了

  • 如果当前访问的路由不需要登录:

  • 前端 header 中传递了 token

  • 如果 token 校验失败:返回 http401;

  • 如果 token 校验成功:就会将解析出来的 userId 放入 header 的 x-user 中返回给 auth 模块,auth 模块会把 header 传递给对应访问的服务(usercenter), 这样我们在 usercenter 直接就可以拿到该登录用户的 id 了

  • 前端 header 中没传递 token:userid 会传递 0 给后端服务

4、总结

这样我们就可以统一入口,统一鉴权,也可以统一收集日志上报,用作错误分析,或者访问用户的行为分析。因为我们日常对 nginx 用的比较多,也比较熟悉,如果各位同学对 kong、apisix 比较熟悉,在了解了上方 go-zero 使用网关的概念就可以直接替换也是一样的。

项目地址

https://github.com/zeromicro/go-zero


欢迎使用 go-zerostar 支持我们!

微信交流群

关注『微服务实践』公众号并点击 交流群 获取社区群二维码。

发布于: 2022 年 02 月 16 日阅读数: 31
用户头像

保持简单 2017.10.24 加入

go-zero作者

评论

发布
暂无评论
微服务从代码到k8s部署应有尽有系列(二、网关)