如何在 k8s 上部署 Quorum HA & IPFS Cluster

Denny
BSOS Taiwan
Published in
5 min readMay 14, 2021

前言:

在很多區塊鏈應用場景中,都需要搭配一個去中心化的儲存系統(如ipfs)來儲存檔案,再利用區塊鏈做存證。我們公司因業務上的需求,需要搭建高可用性的 Quorum 聯盟鏈,並且搭配 IPFS 做資料儲存。但是在我們公司內部的實測發現如果節點擁有者沒有做到 redundancy,這會造成系統的不穩定,當 Quorum 節點掛掉或是 IPFS 掛掉時,系統就會有 down time。

為了確保系統的可用度高達 99.9% 以及做到冗余備份,因此必須搭建一個 High Availability 的 Quorum 節點以及一個 IPFS Cluster。我們公司的產品都圍繞著 Cloud Native 設計,並部署在 k8s 上,因此當然也要把 Quorum 跟 IPFS Cluster 架設在 k8s 上。底下介紹的程式碼都會公開在這個 repo,有任何問題都歡迎直接發 issue 來跟我們討論。

接下來會分兩個部分,Quorum 跟 IPFS Cluster 的部署

Quorum HA Setup:

一開始,我先參考了 Quorum 的官方文件來實作符合高可用性的部署,但因官方並沒有提供具體的範例,因此我們必須發揮創造力來填補這張架構圖所空缺部分。

Source: https://docs.goquorum.consensys.net/en/stable/HowTo/Configure/HighAvailability/

當我一開始看到這張圖時,相信其他人也會有跟我一樣的思路:

圖中的 Q1–1 跟 Q1–2 應該是同一個 node,要用同一個 pv(因為 Quorum 有 block data 要儲存,因此需要一個 pv)。然後用 deployment 起兩個 Quorum Nodes 的 Pod,並且 bound 在同個 pv,如此一來兩個 Quorum nodes 會共用同一個 coinbase 以及同個 enode ID。並且達到了 redundancy 的效果。但實作下來很快就發現了問題,因為 Quorum 底層會開一個 LevelDB,這個 LevelDB 是不支援多個 processes 同時讀寫,因此不能把多個 Pods 共同 bound 在同個 pv 上。所以得另闢蹊徑。

第二個思路就改進了第一個思路的作法,我將兩個 pv 隔開,給兩個 deployment bound 不同的 pv,但是還是共用同一個 coinbase 以及 enode ID,以此來解決 LevelDB 的多個 processes 同時讀寫的問題。但實作下來又發現了另一個問題,就是因為 enode ID 是一樣的,導致 Quorum 的這兩個節點不會自動同步,因為在 p2p 的連線中他們會視為同一個節點而不會同步資料。所以這個方式後來也是行不通。

第三個思路就是最終實踐的結果,把 Q1–1 跟 Q1–2 當成不同的 nodes,兩者各有不同的 coinbase、enode ID、不同的 pv,再把這兩個 node 利用 p2p 連起來,但是這兩個 nodes 背後接的 constellation nodes 必須要是用同一把公私鑰,如此一來才可以做到節點的私狀態是同步的。詳細的部署過程可以參考我的部署檔。(因為每個 infra 的條件不一樣,因此部署檔必須根據現有的 infra 去調整,不能保證可以一鍵部署)

最後部署起來會有三個 StatefulSet 的 Quorum Nodes 各自對應相應的 constellation nodes。這邊我們採用的 constellation 是 crux,本來這個 crux 的專案並沒有支援 Relation DB 來儲存資料,也是透過 LevelDB 來保存資料,所以我們還要對他新增支援 MySQL 的儲存。這樣一來才能夠實現官方提供的那張圖的架構。

那接下來是關於 IPFS HA 的處理

IPFS Cluster Setup:

IPFS Cluster 的官方有提供一個 k8s 的部署教學,可是我照著做發現跑不起來🙃

幸好我發現官方有提供一個 docker-compose.yml,因此還是提供給我們一個很好的方向來拆解要如何部署 IPFS Cluster 在 k8s 上。我們透過這個 yaml 檔可以看出來,一個 ipfs 節點就必須搭配一個 ipfs cluster 節點因此我將 ipfs 跟 ipfs cluster 放在同一個 pod 裡面(sidecar 模式),然後照著這個 docker-compose 的架構改成 k8s 的 helm 檔,但是中間還是踩到了一個坑,就是 ipfs cluster 節點並不會主動發現其他的 ipfs cluster 的節點,為了解決這個問題,必須修改 ipfs cluster container 裡的 peerstore 這個檔案並重啟。

但是事情並沒有這麼順利解決,ipfs cluster 在重啟的過程中會進行一些初始化的設定,所以手動添加完其他 ipfs cluster 的資訊進 peerstore 之後,Pod 重啟就會把 peerstore 清掉,所以最後的作法就是利用 configmap 的 ReadOnly 的特性,把 peerstore 掛載進去,如此一來重啟才不會被清掉。

結論:

在做分散式系統 HA 的架構設計以及部署時,總會發現不少坑要去踩,而且網路上的資源又相對少,甚至有些 case 連開源社群也無法提供支持,所以我們在這裡貢獻給大家這些踩過的坑的經驗,以及要如何去設計這種分散式系統的 HA 部署的思路,希望對各位有所啟發。

--

--