1. 程式人生 > >基於Kubernetes(k8s)的RabbitMQ 叢集_Kubernetes中文社群

基於Kubernetes(k8s)的RabbitMQ 叢集_Kubernetes中文社群

目前,有很多種基於Kubernetes搭建RabbitMQ叢集的解決方案。今天筆者今天將要討論我們在Fuel CCP專案當中所採用的方式。這種方式加以轉變也適用於搭建RabbitMQ叢集的一般方法。所以如果你想要設計自己的解決方案,你應該收集一些更符合你定製化需求的文章。

命名你的叢集

在Kubernetes內部執行RabbitMQ叢集會遇到一系列有意思的問題。最先會遇到的問題是為了使各個節點之間互相可見,我們應該如何命名各個節點。以下是一些符合規範的不同的命名方法:

在你嘗試著啟動第一個節點之前,你需要確定容器之間可以通過選取名字的方式互通。例如,Ping命令可以訪問@符號後面的節點名稱。

Erlang分散式方案(RabbitMQ所基於的實現方式)可以執行在兩種命名方案當中的一種:短節點名或者長節點名。區別的關鍵點在於:名字中如果存在“.”,就屬於長節點名;否則就是短節點名。在以上節點名舉例當中,第一個就屬於短節點名;第二個和第三個則屬於長節點名。

綜合以上要求,我們可以有以下節點命名規則以供選擇:

  • 使用Pet集合(或者叫有狀態集合):我們可以使用相對固定的DNS名字。與一般可以“丟棄”的副本出故障時可以輕易的踢出叢集相對應,Pet集合是一組有狀態的Pod,每個Pod有著可以表示其狀態的識別符號。
  • 使用IP地址以及一些具有自動發現叢集節點的工具(例如,autocluster外掛可以使RabbitMQ節點自動發現叢集子節點)。

以上的命名規則均需要採用長名字模式。但是DNS/節點名在K8S Pod內部配置的方式需要RabbitMQ 3.6.6以後版本才可以支援。所以如果你採用這種方式,請確認你的RabbitMQ的版本。

Erlang的Cookie問題

第二個成功的關鍵問題是RabbitMQ節點需要共享一個金鑰Cookie。預設情況下RabbitMQ從一個檔案當中讀取這個Cookie(如果該檔案不在,則自動生成一個)。為確保該Cookie在所有節點一致,我們有以下方案:

  • 在製作Docker映象的時候生成該Cookie檔案。這種方法並不推薦,因為該Cookie可以讓你對整個RabbitMQ內部有完整的訪問許可權。
  • 用一個Entrypoint指令碼檔案來生成該Cookie檔案。生成時可以用環境變數來傳輸密文。如果我們還需要Entrypoint指令碼檔案來做其他事情,這個方案和下一個方案都可以使用。
  • 通過環境變數的方式給RabbitMQ傳遞:
    RABBITMQ_CTL_ERL_ARGS=”-setcookie ”
    RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS=”-setcookie ”

叢集的缺陷

於RabbitMQ叢集另外一個必須知道是事情是當一個節點加入叢集時,該節點的資料將會丟失,無論是什麼樣的資料。在常見的用例當中,這點可能無關緊要。例如,當一個空節點加入到叢集當中的時候,這時候該節點不存在任何資料丟失的問題。但是,當我們有兩個節點,他們已經相對獨立的執行過一段時間之後,並且已經累積了一些資料時。這時候我們無法在不損失任何資料的前提下將他們合併(注意:在網路中斷或者節點宕機後回覆一個叢集都會有同樣的問題,同樣會有資料丟失)。對於特殊的資料,你可以使用一些其他的解決方案。例如,把需要重置的節點中的資料先備份出來。但是,目前沒有一個健壯的、自動的、全域性的解決方案。

所以我們的自動化叢集解決方案受到我們能容忍什麼樣的資料丟失這一方面的影響。

Cluster formation叢集資訊

假設你已經解決了所有命名規則相關的問題,並且用rabbitmqctl命令手工的建立了叢集。現在是把我們的RabbitMQ封裝成自動化叢集的時候了。就像我們以前遇到的問題一樣,沒有一個解決方案可以解決所有的問題。

一個特定的解決方案只適合我們並不關心服務停止或者連結丟失時資料丟失的問題。這種場景的一個例子就是當你使用RPC傳送請求時,客戶端可以在超時或者收到錯誤時重發請求。當服務恢復之後,RPC請求將不再有效,相關資料也不再有任何意義。幸運的是各個OpenStack元件之間的RPC呼叫正是這種情況。

在思考過以上所有問題之後,現在我們可以搭建我們自己的解決方案了。無狀態是我們的首選,所以我們選擇了IP地址而不是Pet集合。Autocluster外掛將是我們組織動態節點叢集的首選。

檢視過Autocluster的文件之後,我們得出了以下配置項:

  • {backend, etcd}: 這幾乎是我們唯一的選擇。Consul或者K8S可以很好的工作。選擇它的唯一理由也是因為測試起來很簡單。你可以下載etcd的二進位制版本,不需要任何引數就可以執行,這樣可以搭建起一個基於本地的叢集。
  • {autocluster_failure, stop}:如果一個pod無法加入叢集對於我們來說就沒有任何價值。這個pod將會被移除叢集,並在一個相對安全的環境中重啟。
  • {cluster_cleanup, true}, {cleanup_interval, 30},{cleanup_warn_only, false}, {etcd_ttl, 15}:一個節點只有在完全啟動,並且成功加入叢集之後才可以在etcd中註冊。只要該節點還可用,註冊用的TTL將會不間斷的被更新。如果該節點停掉(或者由於某種原因無法更新TTL),他將會被強制從叢集中刪除。即使該節點重啟後獲得了相同的IP地址,它也會被認為是重新加入叢集。

無法預料的競爭

如果你嘗試著按照以上搭建了幾次叢集,你會發現有時整個叢集會分裂成幾個互相無法聯通的小叢集。問題產生的原因是啟動時對於競爭問題的唯一保護措施在節點啟動時會有隨機的延遲現象。在最壞的情況下,每個節點會認為它是第一個節點(例如這時在etcd中沒有任何記錄),所以這個節點就以無叢集模式啟動了。

Autocluster最終為該問題提出了一個很大的補丁。它在啟動的過程中增加了鎖機制:節點在啟動時最先申請啟動鎖資源,最後在該節點成功在後臺註冊之後才釋放。目前只有etcd這個平臺支援該功能。但是其它平臺也可以很容易的支援該功能(在後臺當中增加兩個新的回撥函式)。

另一個問題是:K8S、Pet集合他們可以在啟動的時候進行編排工作;在任何時間都只有一個節點處於啟動狀態。 該功能只處於初期測試階段。提供該功能的補丁不僅僅提供給K8S的使用者,而是提供給所有平臺的開發者。

監控

目前唯一遺留的問題就是為我們執行在非看管狀態的叢集增加一個監控系統。我們需要監控rabbitmq的健康狀況以及它是否和叢集其它節點良好的工作在一起。

你也許還記得以前可以通過執行rabbitmqctl list_queues或者rabbitmqctl list_channels來監控。但是這種方案並不完美,因為它無法區別本地和遠端的問題。同時它又明顯的增加了網路負載。為了彌補這個缺陷,3.6.4版本之後推出了新的、輕量級的rabbitmqctl node_health_check。這是檢查rabbitmq叢集當中單節點健康狀況最好的方法。

檢查一個節點是否正確的加入叢集需要做幾方面的檢查:

  • 新加入的節點應當與Autocluster後臺最優節點在一起註冊成叢集。這個最優節點是在註冊成功列表裡按字母順序排在最前面的節點。
  • 即使當節點已經與現有節點形成了叢集,但它的資料可能還是分開的。對於這個檢查並不是分開的,我們需要在當前節點和新發現節點都檢查分割槽列表。

所有的這些可以通過獨立的檢查完成,檢查可以使用以下命令:
rabbitmqctl eval ‘autocluster:cluster_health_check_report().’

使用rabbitmqctl命令我們可以檢測出rabbitmq節點的任何問題,也可以通過該命令將該節點停掉。因此,K8S可以有機會施展魔法重啟該節點。

搭建你自己的RabbitMQ叢集

如果你自己親自按照這個方案搭建這個叢集,你需要最新版本的RabbitMQ以及autocluster外掛的定製化版本(目前啟動鎖機制這個補丁還沒有合併到主版本當中)。

你可以檢視Fuel CCP如何搭建叢集,或者用你自己的實現方法使用獨立的版本來搭建。

為了提示你該方案案如何實施,讓我們假設你已經複製了第二個repository,並且你已經有了一個叫做“demo”的K8S的名稱空間。Etcd的服務已經在K8S叢集中執行,並且可以通過”etcd”這個名字訪問。你可以通過以下命令來搭建環境:

kubectl create namespace demo
kubectl run etcd --image=microbox/etcd --port=4001 \
--namespace=demo -- --name etcd
kubectl --namespace=demo expose deployment etcd

完成以上步驟後,用以下命令搭建RabbitMQ:

1. 用合適的RabbitMQ和Autocluster版本建立Docker映象,並設定相應配置檔案。

$ docker build . -t rabbitmq-autocluster

2. 儲存Erlang的Cookie到K8S當中。

$ kubectl create secret generic --namespace=demo erlang.cookie \
--from-file=./erlang.cookie

3. 建立3節點RabbitMQ叢集。為了簡化操作,你們可以從以下連結下載rabbitmq.yaml檔案https://github.com/binarin/rabbit-on-k8s-standalone/blob/master/rabbitmq.yaml.

$ kubectl create -f rabbitmq.yaml

4. 檢查叢集是否正常工作

$ FIRST_POD=$(kubectl get pods --namespace demo -l 'app=rabbitmq' \
-o jsonpath='{.items[0].metadata.name }')
$ kubectl exec --namespace=demo $FIRST_POD rabbitmqctl \
cluster_status

你應該得到如下輸出:

Cluster status of node '[email protected]' ...
[{nodes,[{disc,['[email protected]','[email protected]',
                '[email protected]']}]},
 {running_nodes,['[email protected]','[email protected]','[email protected]']},
 {cluster_name,<<"[email protected]">>},
 {partitions,[]},
 {alarms,[{'[email protected]',[]},
          {'[email protected]',[]},
          {'[email protected]',[]}]}]

這裡最關鍵的一點是nodes與running nodes集合均有三個節點。

原文:hwww.mirantis.com/blog/clustered-rabbitmq-kubernetes/

RabbitMQ官網:www.rabbitmq.com/