本篇博客主要介紹了自動化工具這個概念,在微服務集群當中的作用,算拋磚引玉,歡迎大家提出自己的見解。
寫在前面
在了解自動化工具的概念之前,我們先了解一下微服務和集群的概念。
什么是微服務
這個概念其實有些廣泛,而我的知識廣度也有限,我會盡量用通俗的語言來描述什么是微服務,什么是集群,以及為什么我們需要微服務集群 。為什么需要集群可以去看看《小強開飯店-從單體應用到微服務》,這篇文章用非常通俗的語言和配圖,通過一個漫畫故事簡單的解釋了為什么我們需要微服務集群。
微服務
傳統的后端服務多為單體應用,例如使用Sprint Boot或者Node又或者Gin搭建的簡單的后端服務,在此基礎之上,實現了基本的業務之后再部署到服務器上運行起來,這就成為了一個單體應用。
隨着業務需求的增加、業務代碼慢慢的累加,單體應用變的也越來越大。同時各個模塊的大量業務代碼相互糾纏在一起,開發以及維護變得尤其困難。想象一下一個剛剛加入項目的新人看到相互糾纏的、邏輯復雜的業務代碼的絕望。
這個時候我們就需要了解微服務的概念了。如果想要講這個龐大的單體應用可維護、可擴展以及高可用,我們就需要對單體應用按照模塊進行業務拆分 。
例如將用戶相關的所有邏輯單獨搞成一個服務,又例如訂單、庫存可以搞成一個單獨的服務。這樣一來,業務代碼被分散到幾個單獨的服務中,每個服務只需要關心、處理自己這個模塊的業務邏輯。這樣一來,業務代碼的邏輯清晰,對開發人員來說,條理以及思路都很清晰。即使是后加入的項目開發人員,面對業務邏輯清晰的代碼也十分容易上手。
微服務的拆分
其實我看到很多的文章關於微服務的介紹就基本到這了,但是還有個值得提的概念。首先,微服務怎么拆分其實是沒有一個標准的。
你按照什么樣的粒度去拆分你的服務其實是跟業務強相關的。並不是說一個服務的代碼一定就很少,根據你的業務的量度,例如你的系統用戶量特比的大,那么一個用戶服務的代碼量上千上萬行我覺得都很正常。
當然我也見過用戶不是很多,只是為了高可用和快速定位,而將系統拆分的非常細的系統,有好幾十個服務。那么問題來了,有這么多服務,前端需要去維護的后端API的地址就相當的龐大了。
我們暫且先不討論所有拆分的服務是否運行在同一個服務器上,就算是,那也得是不同的端口。前端也需要根據后端拆分的服務模塊,去維護這樣一張API的映射表。所以我們需要提出一個BFF,AKA Backend For Frontend.
BFF
其實BFF層最初被提出來,其實不是為了微服務拆分模塊中提到的目的。其設計的目的是為了給不同的設備提供不同的API。例如一個系統的后端服務,同時需要支持不同的終端,例如移動端的iOS和Android,PC端。
這樣一來,可以根據不同設備上的需求來提供對應的API,而且不需要更改我們現有的微服務。
這樣一來,我們的底層服務群就具有了很強的擴展性,我們不需要為一個新增的客戶端來更改底層的服務代碼,而是新增一層BFF層,來專門針對該終端類型去做適配。
大家從上面的圖可以看出來,客戶端都沒有直接訪問我們的底層服務。而是都先經過BFF層提供的接口,再由BFF層來根據不同的路由來調用不同的底層服務。總結一下,加了BFF層的優點如下。
- 擴展性強,可以適應不同的客戶端
- 統一的API管理,客戶端無須再維護API的映射表
- 可做集中鑒權,所有的請求都會先經過BFF,可在這一層對調用接口的合法性進行驗證
當然,BFF也有缺點。
- 處理不當會有大量的代碼冗余
- 因需要調用不同底層的服務而增大開發的工作量
當然在實際的生產環境下,我們也很少會將BFF層直接暴露給客戶端。我們通常會在BFF層上再加一層網關。網關可以在請求還沒有到BFF的時候,實現權限認證,限流熔斷等等其他的功能。
集群
上面簡單的聊了一下什么是微服務,現在我們來聊聊什么是集群。我們知道,當一個單體應用大的已經很難維護的時候,最好的辦法就是將其拆分成微服務。這樣有什么好處呢?
- 便於維護。每個微服務專注於自己這個模塊的業務邏輯,不會存在各個模塊的業務邏輯纏在一起的狀況。
- 提高可用性。當單體應用掛掉的時候,我們系統的所有模塊都將不可用。而拆分成微服務就可以盡量的避免這個問題。單個服務掛掉了,不會影響到其他服務的正常運行。
- 便於運維。單體應用重新部署的時候,會使整個系統不可用。而在微服務中,單個服務重新部署的代價明顯要小的多。
概念
說了這么多,我們來給集群一個概念吧。集群就是將同一套服務部署在不同的服務器上,對外提供服務。
例子
我舉個具體的例子。例如我們使用Docker Swarm來提供容器的集群服務。
在Docker Swarm中有節點這樣一個概念,凡是運行了Docker的主機都可以主動的創建一個Swarm集群或者加入一個已經存在的集群,一旦加入,這個主機就成為了這個集群中的一個節點。在集群中節點分為兩類,分別是管理節點(manager)和工作節點(worker)。我們可以用Portainer來管理Docker主機和Swarm集群。
我們以一個集群中的請求來舉個例子。
首先進入系統之后會先進入一個統一鑒權的系統去鑒權,鑒權成功之后就會到我們的微服務網關,如果這個地方還有系統自己的特殊鑒權的話,再次進行鑒權。之后網關這邊會將我們的請求根據配置的路由來分發到具體的某個服務器上的某個容器中。
自動化工具
自動化工具的都包含了哪些技術呢?
其中的Java只是一個類比,代表你的編程語言。微服務中其實不是很關心具體用的什么語言,甚至每個服務都用不同的技術棧都行。
那么自動化工具是什么呢?其作用是什么?在集群中扮演了什么樣的角色呢?我們通過一張圖來簡單的了解一下。
構建
簡單的梳理一下邏輯。
- 首先自動化工具將Jenkins構建所需要的參數組織好,調用Jenkins的構建API,並記錄構建操作到自動化工具的數據庫
- 然后Jenkins用配置好的憑證去Gitlab的對應的項目的分支拉取代碼,根據配置好的構建腳本開始構建,記錄構建記錄到自動化工具的數據庫
- 構建好后再推送到docker的倉庫中,並記錄到自動化工具的數據庫
到此構建的邏輯結束。
其他的功能
自動化工具還可以直接在項目列表中,選擇查看當前項目的日志,而不需要每次重新打開Kibana然后再加篩選filter。
自動化工具的項目設置中,我們還可以更改docker容器的配置,而不需要再去portainer中或者通過命令行去修改;如果想要命令行進入容器,首先我們得找到對應的service,然后找到對應運行的service實例,然后才能進入,而如果我們直接使用portainer的Api,在endpoint已知的情況下,可以直接將這個功能做到自動化工具中,直接使用webshell一鍵連接。
其好處是什么呢?
- 對大部分開發屏蔽Swarm集群。對項目中非管理員的開發屏蔽Portainer,因為這個權限非常大,一旦不熟悉導致了誤操作,那么有可能直接影響到線上的服務
- 統一權限控制。在自動化工具里做權限以及環境的統一控制
- 上手成本低。比起直接操作portainer和Jenkins和Kibana,自己搭建的自動化工具十分容易上手
功能總結
總結一下,其功能主要為以下幾個。
- 構建
- 部署
- 回滾
- 查看elk日志
- 更改docker配置
- 管理集群的環境、項目和容器
- 命令行連接具體項目的容器
- …...
看到這大家可能會有疑問。
- 構建?你的意思是我Jenkins是擺設咯?
- 部署?更改 docker配置?命令行連接具體項目的容器?我的Iterm2也是個擺設?
- 回滾?等於是我之前的docker鏡像的tag白打了?
- elk日志?我的Kibana是拿來看新聞的嗎?
功能詳解
構建
其實在構建這塊,我個人認為自動化工具和Jenkins都很方便。而且自動化工具本身就是用的Jenkins,只不過是調用了Jenkins的API,傳遞了構建的參數,最終真正去構建的還是Jenkins。
只不過對於剛剛加入項目的測試來說,自己開發的Web UI對新人更加的友好,而且可以在自動化工具中做到權限控制。
部署和回滾
部署在自動化工具的后端通過docker-client實現。首先我們根據配置,創建docker client。然后如果已經有在運行的服務了,就調用update service更新服務,否則就創建服務。
回滾與其本質相同,只不過是用了之前的參數和不同的tag。
elk日志
首先,每個環境的配置中,會配置上kibana_host以及kibana_index,然后根據系統的projectKey,拼接成相應的Kibana日志的url,然后使用iframe嵌入到自動化工具中。這樣一來就不用再手動的打開Kibana再去設置對應的filter了。特別是當你系統特別多的時候,添加和刪除filter是很廢時間的。
更新容器配置
這里也同樣是調用對應的API更新對應服務的配置,而不用登錄portainer去修改。
同時,在自動化工具中還可以針對不同的環境配置不同的Base Setting。后續在該環境下添加的應用不用再單獨配置,直接繼承環境的Docker Setting即可。
管理集群的環境、項目和容器
可以通過自動化工具統一的來創建和管理環境,同樣有三種環境,研發、測試、生產環境。然后可以在自動化工具中創建角色和用戶,分配給不同的角色不同的權限來達到控制權限的目的。
命令行連接具體項目的容器
通常我們因為某個需求,需要進入到容器中查看,然而此時我們就面臨兩種選擇。
- 通過portainer進入對應service,找個某個具體的container,點擊連接
- 命令行到容器具體運行的某個服務器上,然后再通過命令行連接
但是有了自動化工具,我們就有了第三種選擇。
- 點擊連接
怎么實現的呢?實際上就是通過endpointId去獲取到所有的container的信息,然后遍歷所有的container,找到與當前選中的containerId相同的容器,獲取到其NodeName,這樣一來我們就知道當前這個容器到底運行在哪個節點上的了。
然后通過已有的信息,構建WebSocket的url,最后前端通過xterm來建立ws連接,就這樣直接連接了正在運行的容器實例。
總結
自動化工具只是一種思路,一種解決方案,它的好處在上面也列出了很多。當然,它肯定也有壞處,那就是需要專門投入人力和資源去開發。
這對於人手緊缺和項目周期較短的項目組來說,十分的不現實。但是如果一旦有精力和時間,我覺得值得一試。同時,基於portainer的API,我們還有可能將更多與集群相關的功能,集成到自動化工具上。
往期文章:
- 什么?你竟然還沒有用這幾個chrome插件?
- 手把手教你從零開始搭建SpringBoot后端項目框架
- 用go-module作為包管理器搭建go的web服務器
- WebAssembly完全入門——了解wasm的前世今身
- 小強開飯店-從單體應用到微服務
相關:
- 微信公眾號: SH的全棧筆記(或直接在添加公眾號界面搜索微信號LunhaoHu)