微服務從程式碼到k8s部署應有盡有系列(二、閘道器)

kevinwan發表於2022-02-17

我們用一個系列來講解從需求到上線、從程式碼到k8s部署、從日誌到監控等各個方面的微服務完整實踐。

整個專案使用了go-zero開發的微服務,基本包含了go-zero以及相關go-zero作者開發的一些中介軟體,所用到的技術棧基本是go-zero專案組的自研元件,基本是go-zero全家桶了。

實戰專案地址:github.com/Mikaelemmmm/go-zero-loo...

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. 舉例

當我們在訪問使用者服務時候, 127.0.0.1:8888/usercenter/v1/user/d... , 訪問了外部埠8888,然後對映到nginx內部looklook閘道器8081上,然後location匹配到了/usercenter/ ,在該模組開始有一行 auth_request /auth, 所以nginx不會直接去請求usercenter-api:8002 , 而是會先跳到 location /auth 模組中,auth模組會訪問 identity-api:8001/identity/v1/verif...; ,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使用閘道器的概念就可以直接替換也是一樣的。

專案地址

github.com/zeromicro/go-zero

歡迎使用 go-zerostar 支援我們!

微信交流群

關注『微服務實踐』公眾號並點選 交流群 獲取社群群二維碼。

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章