C# 開源一個基於 yarp 的 API 網關 Demo,支持綁定 Kubernetes Service

關於 Neting

剛開始的時候是打算使用微軟官方的 Yarp 庫,實現一個 API 網關,後面發現坑比較多,弄起來比較麻煩,就放棄了。目前寫完了查看 Kubernetes Service 信息、創建 Route 和 Cluster 和綁定 Kubernetes Service。簡單來說,就是完成了基礎部分,配置路由和後端服務綁定,如果想實現動態路由和直接轉發等功能,只需要按照官方的文檔,增加中間件即可。

原本打算使用 .NET 6 的 AOT(一共40MB) ,但是打包運行會容易出現一些依賴問題和環境問題,因此放棄了,依然採用 Runtime + 應用 的方式部署,進行總共 120 MB 左右。

後端項目地址:https://github.com/whuanle/neting

前端項目地址:https://github.com/whuanle/neting-web

體驗地址:http://neting.whuanle.cn:30080/

大概界面是這樣的:

Route:即來源入口,支持 http/https 和 gRPC,Route 是設計進入集羣前的訪問者流量如何綁定後端服務,可以配置訪問者 URL 的區配規則;

Cluster:後端服務,一個 Cluster 可以綁定多個類型的後端服務,主要實現一個域名不同的後綴訪問多個微服務,或者同一個實例負載均衡等;

Service:查看 Kubernetes Service 的一些網絡信息;

Neting 目前只實現了簡單的配置,僅供讀者瞭解 Yarp 以及入門 Kubernetes API 開發、監控集羣資源等。讀者也可以從中瞭解 etcd 的使用,如何設計一個 Kubernetes Controller 應用。

基礎功能已經做了,讀者可根據需求,自行增加中間件即可。

下面介紹如何部署 Neting 項目,需要讀者提前創建好集羣。

談談對 Yarp 的看法。

首先,Yarp 的倉庫地址是 https://github.com/microsoft/reverse-proxy

倉庫在微軟的官方賬號下,從瞭解到的信息來看,Yarp 的出現主要是解決 Microsoft 內部的需求,也有人說是爲了給 Azure 用。倉庫代碼目標也是主要解決微軟內部需求,很多 API 對外部開發者也不是很友好,實際開發起來有一定難度,當然可定製性也比較多,主要從 ASP.NET Core 的中間件下手,做各方面的擴展。

另外這個項目不是成熟項目,Yarp 只是一個庫,它不是一個完整應用,很多地方還沒有確定其穩定性,也沒有性能測試報告等,也沒有基於此的成熟的應用出現。API 上和其他方面,開發難度還是比較複雜的,包括文檔很多地方也沒有說清楚。

部署 etcd

Neting 的主要設計,是 etcd 作爲數據存儲後端,當用戶創建反向代理或者其他類型的規則時,etcd Watch 自動通知 Neing 實例,刷新這些配置到內存中,交由 Yarp 使用(當然也可以不放到內存,在需要使用的時候,自動從 etcd 中取)。

Neting 使用 etcd 作爲存儲後端,etcd 支持集羣,但是這裏爲了方便使用單個 etcd 實例。因爲 etcd 是有狀態應用,因此需要綁定一個存儲卷。另外 etcd 也需要創建一個 service,以便在集羣中訪問實例。

etcd 集羣(這裏是單實例集羣) ->  Service(名稱爲neting-svc)
     ↓
PersistentVolumeClaim
     ↓
PersistentVolume

你可以在項目的 yaml 下面,找到 etcd.yaml 和 etcds.yaml 、neting-etcd.yaml 三個文件,查看如何部署 etcd 集羣。

爲了方便,創建的存儲卷是本地卷,不能跨節點共享數據。當然你也可以通過修改 neting-etcd.yaml 文件,使用其他類型的卷。

  hostPath:
      # 宿主上目錄位置,需要先提前創建
    path: /data/etcd
      # 此字段爲可選
    type: Directory

將 neting-etcd.yaml 文件上傳到集羣,然後創建 etcd 實例。

root@master:~/neting# kubectl apply -f neting-etcd.yaml 
service/neting-etcd created
statefulset.apps/neting-etcd created
persistentvolume/neting-etcd created

創建 etcd 集羣的時候,會創建多個相關的資源。

root@master:~/neting# kubectl get statefulset
NAME          READY   AGE
neting-etcd   1/1     36s

root@master:~/neting# kubectl get pv
NAME          CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS
neting-etcd   1Gi        RWO            Recycle          Available

root@master:~/neting# kubectl get svc
NAME           TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                               AGE
neting-etcd    ClusterIP   10.96.206.255    <none>        2379/TCP,2380/TCP                     54s

其實還包括 PersistentVolumeClaim,可以執行 kubectl get pvc 查看。

創建 secret

secret 的主要作用是給 Neting 提供用戶登錄的賬號密碼,即前面提到的 admin/admin123,這個配置寫在了 secret.yaml。

secret.yaml 的全部內容如下:

apiVersion: v1
kind: Secret
metadata:
  name: neting-basic-auth
type: Opaque
stringData:
# Neting 的登錄賬號密碼
  NETING_USER: admin
  NETING_PASSWORD: admin123
  NETING_TOKENKEY: dzbfhisj@3411DDFF5%$%^&&

這個配置很簡單,其中 NETING_TOKENKEY 表示簽名 token 的密鑰,Neting 使用 Jwt Token 做用戶憑證,在頒發憑證給用戶時,需要加密用戶信息簽名。

上傳 secret.yaml 到集羣中,然後創建它。Secret 中的信息最終會生成 base64,Kubernetes 的 etcd 中(注,不是前面自行創建的 etcd)。secret 中的信息,最終會以環境變量的形式出現在 Neting Pod 中。

root@master:~/neting# kubectl apply -f secret.yaml 
secret/neting-basic-auth created

root@master:~/neting# kubectl get secret
NAME                      TYPE                                  DATA   AGE
neting-basic-auth         Opaque                                3      10s
...
data:
  NETING_PASSWORD: YWRtaW4xMjM=
  NETING_TOKENKEY: ZHpiZmhpc2pAMzQxMURERkY1JSQlXiYm
  NETING_USER: YWRtaW4=
kind: Secret

部署 Neting

Neting 的依賴關係如下:

Neting -> 啓動(Secret)
 ↓
Service - etcd
 ↓
etcd 實例

Neting 是由 ASP.NET Core API + React/Ant Design 編寫的 Web 項目,爲了結構簡單,Neting 在 wwwroot 目錄託管了前端靜態文件,以便在同一個端口下訪問,並且減少跨域、綁定 IP 等事情。

Neting 已被上傳到阿里雲鏡像倉庫中,docker pull 地址 : registry.cn-hangzhou.aliyuncs.com/whuanle/neting:review1.0

Neting 是需要在 Pod 中連接到 Kubernetes API Server 的,因此需要配置 ServiceAccount 或者直接使用 Kubeconfig。遺憾的是,C# 的 KubernetesClient 對 ServiceAccount 支持並不好,因此只能使用 Kubeconfig,當然直接使用 Kubeconfig 可能會帶來一些安全問題,好在這是 Demo,Neting 只會使用 獲取 Servive 和 Endpoint 部分的信息,不會對集羣進行修改、刪除等操作,因此如果需要更高安全級別的操作,可嘗試自行解決 Kubenetes - C# 的 ServiceAccount 問題。

Kubernetes 和 etcd 的 C# SDK 體驗不佳,讀者搞雲原生中間件的時候,還是用 Go 搞比較好,C# 適合寫業務。

將你的 Kubernetes 管理配置文件複製到 /root/.kube/config 中。注意,這一步一定要在會被調度 Pod 運行的節點上處理,因爲這個配置文件不能跨節點使用。

cp -f /etc/kubernetes/admin.conf /root/.kube/config

然後啓動 Neting:

kubectl apply -f neting.yaml

接着,爲 Neting 創建 Service,以便在外網訪問。

root@master:~/neting# kubectl apply -f neting-svc.yaml 
service/neting created

root@master:~/neting# kubectl get svc -o wide
neting         NodePort    10.102.240.255   <none>        80:30080/TCP                          11s   app=neting
neting-etcd    ClusterIP   10.96.206.255    <none>        2379/TCP,2380/TCP                     31m   app=neting-etcd

部署完成後,可以通過節點的 IP 和 30080 端口,訪問到。

接着隨便點擊一個菜單,便會要求登錄。

賬號密碼分別是 adminadmin123

登錄後,憑證會存儲到你的瀏覽器中,有效期爲 7 天。

點擊 Service 可以看到集羣中的 Service 的信息。

使用

接着我們來創建 Yarp 反向代理 配置。

Yarp 的反向代理對象綁定分爲兩個部分,Route 和 Cluster。

Cluster 即是服務後端實例,如你有一個應用部署了 N 個實例,每個實例都有一個 IP,那麼 Cluster 需要記錄你這些實例的 IP,以便在訪問時,通過負載均衡算法選擇其中一個訪問。YARP 帶有內置的負載平衡算法,但也爲任何自定義負載平衡方法提供了可擴展性。這裏就不展開來講。

讀者可以參考 https://microsoft.github.io/reverse-proxy/articles/load-balancing.html

我的 Kubernetes 中,有測試 Ingress 時留下來的兩個應用, web1 和 web2,這裏可以使用一下。

接着,筆者到域名管理處,解析了一個域名綁定應用。

接着創建 Route。

是可以基於 Yarp 項目設計一個 API 網關,或者代替 Kubernetes 的 Ingress ,實現流量入口,API 網關 + 負載均衡。

說不定你還可以編寫類似 Dapr 的服務網格功能,使用邊車模式爲集羣中的應用提供非侵入式流量代理服務。

介紹一下項目

Neting 就是後端項目,NetingCrdBuilder 跟當前項目無關,是筆者本來打算做類似 Dapr,創建自定義資源以及以及 Kubernetes Operater 用的,不想寫了,就不寫了。Yarp.ReverseProxy 是 Yarp 基礎庫,爲了發表調試和查看源碼,不通過 Nuget 引用,而是抽取源碼,通過代碼直接引用。

後端項目大部分都寫了註釋,這裏就不再多說了。

如果想在本地測試和開發,可以先把前後端項目拉下來。

本地開發,你需要在後端項目的 appsettings.json 或 appsettings.Development.json 文件修改配置。

其中 admin.conf 是 Kubernetes API Server 連接的驗證配置文件,通過配置文件與 Kuberntes 連接的時候才能通過授權訪問資源。代碼在 KubernetesExtensions 中,你也可以通過 Kubernetes proxy 等方式訪問 Kubernetes 進行開發。

然後需要在前端的 Constants.js 文件中,配置你本地的後端地址。

export const Options = {
    // host: "http://127.0.0.1:80"  // 開發配置
    host: ""                        // 部署配置
}

如果前後端都在同一個端口下,則 host:"" 即可。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章