云原生时代 RocketMQ 运维管控的利器 - RocketMQ Operator
作者 | 劉睿、杜恒
導(dǎo)讀:RocketMQ Operator 現(xiàn)已加入 OperatorHub,正式進(jìn)入 Operator 社區(qū)。本文將從實(shí)踐出發(fā),結(jié)合案例來(lái)說(shuō)明,如何通過(guò) RocketMQ Operator 在 Kubernetes 上快速搭建一個(gè) RocketMQ 集群,并提供一些 RocketMQ 集群管理功能包括 Broker 擴(kuò)容等。
本文主要分為三個(gè)部分:
- 首先簡(jiǎn)單介紹一下 RocketMQ Operator 的相關(guān)知識(shí);
- 然后結(jié)合案例詳細(xì)介紹 RocketMQ Operator 提供的自定義資源及使用方法;
- 最后介紹 Operator 社區(qū)目前的情況并展望 RocketMQ Operator 下一步的發(fā)展方向。
相關(guān)背景知識(shí)
1. RocketMQ
2012~2013 年期間,阿里巴巴中間件團(tuán)隊(duì)自主研發(fā)并對(duì)外開(kāi)源了第三代分布式消息引擎 RocketMQ,其高性能、低延遲、抗堆積的特性穩(wěn)定支撐了阿里巴巴 雙11 萬(wàn)億級(jí)數(shù)據(jù)洪峰業(yè)務(wù),其云產(chǎn)品 Aliware MQ 在微服務(wù)、流計(jì)算、IoT、異步解耦、數(shù)據(jù)同步等無(wú)數(shù)工況場(chǎng)景大放異彩。
2016 年,阿里巴巴向 Apache 軟件基金會(huì)捐贈(zèng)了 RocketMQ。次年,RocketMQ 順利從基金會(huì)畢業(yè),成為 Apache 頂級(jí)開(kāi)源項(xiàng)目,與 Apache Hadoop,Apache Spark 一起為全球分布式、大數(shù)據(jù)領(lǐng)域的開(kāi)發(fā)者帶來(lái)福音。然而,在云原生時(shí)代的今天,RocketMQ 作為有狀態(tài)的分布式服務(wù)系統(tǒng),如何在大規(guī)模集群上做到極簡(jiǎn)運(yùn)維,則是一個(gè)極具挑戰(zhàn)和價(jià)值的問(wèn)題。
RocketMQ 支持多種部署方式,以基本的雙主雙從架構(gòu)為例,如下圖所示。
RocketMQ 雙主雙從架構(gòu)
這里面包括了一共 7 個(gè) RocketMQ 服務(wù)實(shí)例:3 個(gè) name server 實(shí)例,2 個(gè) master broker 實(shí)例,以及 2 個(gè) slave broker 實(shí)例。
傳統(tǒng)的部署方式需要手動(dòng)或編寫(xiě)腳本在每個(gè)節(jié)點(diǎn)上進(jìn)行環(huán)境和文件配置。此外,隨著用戶業(yè)務(wù)的增加,存在對(duì)集群進(jìn)行無(wú)縫擴(kuò)容等需求。傳統(tǒng)方式是運(yùn)維人員訪問(wèn)不同節(jié)點(diǎn),依賴操作手冊(cè)和腳本按步驟進(jìn)行操作來(lái)完成,耗費(fèi)人力,且存在誤操作的可能。一些公司可能會(huì)使用一些平臺(tái)和工具如 Ansible 來(lái)幫助自動(dòng)化運(yùn)維,此外越來(lái)越多的公司開(kāi)始集成和使用基于 Kubernetes 的云原生生態(tài)。
使用 Kubernetes 提供的 Deployment 和 StatefulSet 等原生資源可以很好地解決無(wú)狀態(tài)應(yīng)用的管理問(wèn)題,但對(duì)于數(shù)據(jù)庫(kù)和 RocketMQ 這類有狀態(tài)應(yīng)用,則存在很多局限性。例如對(duì) RocketMQ 來(lái)說(shuō)擴(kuò)容不僅僅是拉起新的實(shí)例 Pod 就完成了,還需要同步復(fù)制 Broker 的狀態(tài)信息包括 Topic 信息和訂閱關(guān)系這些元數(shù)據(jù),同時(shí)要正確配置新 Broker 的 config 參數(shù),包括 brokerName 和 NameServer IP List 等,才能使得新擴(kuò)容的 Broker 可用,而這些僅僅靠用戶編寫(xiě) StatefulSet,修改 size 或 replicas 然后 apply 是無(wú)法做到的。
實(shí)際上 Kubernetes 開(kāi)發(fā)人員也發(fā)現(xiàn)了這些問(wèn)題,因此引入了自定義資源和控制器的概念,讓開(kāi)發(fā)人員可以直接用 Go 語(yǔ)言調(diào)用 Kubernetes API,編寫(xiě)自定義資源和對(duì)應(yīng)的控制器邏輯來(lái)解決復(fù)雜有狀態(tài)應(yīng)用的管理問(wèn)題,提供特定應(yīng)用相關(guān)的自定義資源的這類代碼組件稱之為 Operator。由具備 RocketMQ 領(lǐng)域知識(shí)的專家編寫(xiě) Operator,屏蔽了應(yīng)用領(lǐng)域的專業(yè)知識(shí),讓用戶只需要關(guān)心和定義希望達(dá)到的集群終態(tài),這也是 Kubernetes 聲明式 API 的設(shè)計(jì)哲學(xué)。
2. Kubernetes Operator
Operator 是在 Kubernetes 基礎(chǔ)上通過(guò)擴(kuò)展 Kubernetes API,用來(lái)創(chuàng)建、配置和管理復(fù)雜的有狀態(tài)應(yīng)用,如分布式數(shù)據(jù)庫(kù)等。Operator 基于 Kubernetes 1.7 版本以來(lái)引入的自定義控制器的概念,在自定義資源和控制器之上構(gòu)建,同時(shí)又包含了應(yīng)用程序特定的領(lǐng)域知識(shí)。實(shí)現(xiàn)一個(gè) Operator 的關(guān)鍵是 CRD(自定義資源)和 Controller(控制器)的設(shè)計(jì)。
Operator 站在 Kubernetes 內(nèi)部視角,為應(yīng)用的云原生化打開(kāi)了新世界的大門(mén)。自定義資源可以讓開(kāi)發(fā)人員擴(kuò)展添加新功能,更新現(xiàn)有的功能,并且可以自動(dòng)執(zhí)行一些管理任務(wù),這些自定義的控制器就像 Kubernetes 原生的組件一樣,Operator 可以直接使用 Kubernetes API 進(jìn)行開(kāi)發(fā),也就是說(shuō)他們可以根據(jù)這些控制器編寫(xiě)的自定義規(guī)則來(lái)創(chuàng)建和更改 Pods / Services、對(duì)正在運(yùn)行的應(yīng)用進(jìn)行擴(kuò)縮容。
快速開(kāi)始
本文使用 RocketMQ Operator 0.2.1 版本,展示如何使用 RocketMQ Operator 在 Kubernetes 上快速創(chuàng)建部署一個(gè) RocketMQ 服務(wù)集群。
-
準(zhǔn)備好 K8s 環(huán)境,可以使用 docker desktop 自帶的 K8s,或者 minikube;
-
克隆 rocketmq-operator 倉(cāng)庫(kù)到你的 K8s 節(jié)點(diǎn)上;
- 運(yùn)行腳本安裝 RocketMQ Operator;
- 檢查下 RocketMQ Operator 是否安裝成功
成功安裝時(shí),rocketmq-operator pod 處于類似上面例子的 running 狀態(tài)。
- 應(yīng)用 Broker 和 NameService 自定義資源,創(chuàng)建 RocketMQ 集群;
應(yīng)用 rocketmq-operator / example 中的 rocketmq_v1alpha1_rocketmq_cluster.yaml 文件,快速部署一個(gè) RocketMQ 集群。rocketmq_v1alpha1_rocketmq_cluster.yaml 文件內(nèi)容如下:
apiVersion: rocketmq.apache.org/v1alpha1 kind: Broker metadata:# name of broker clustername: broker spec:# size is the number of the broker cluster, each broker cluster contains a master broker and [replicaPerGroup] replica brokers.size: 1# nameServers is the [ip:port] list of name servicenameServers: ""# replicationMode is the broker replica sync mode, can be ASYNC or SYNCreplicationMode: ASYNC# replicaPerGroup is the number of each broker clusterreplicaPerGroup: 1# brokerImage is the customized docker image repo of the RocketMQ brokerbrokerImage: apacherocketmq/rocketmq-broker:4.5.0-alpine# imagePullPolicy is the image pull policyimagePullPolicy: Always# resources describes the compute resource requirements and limitsresources:requests:memory: "2048Mi"cpu: "250m"limits:memory: "12288Mi"cpu: "500m"# allowRestart defines whether allow pod restartallowRestart: true# storageMode can be EmptyDir, HostPath, StorageClassstorageMode: EmptyDir# hostPath is the local path to store datahostPath: /data/rocketmq/broker# scalePodName is broker-[broker group number]-master-0scalePodName: broker-0-master-0# volumeClaimTemplates defines the storageClassvolumeClaimTemplates:- metadata:name: broker-storagespec:accessModes:- ReadWriteOncestorageClassName: rocketmq-storageresources:requests:storage: 8Gi --- apiVersion: rocketmq.apache.org/v1alpha1 kind: NameService metadata:name: name-service spec:# size is the the name service instance number of the name service clustersize: 1# nameServiceImage is the customized docker image repo of the RocketMQ name servicenameServiceImage: apacherocketmq/rocketmq-nameserver:4.5.0-alpine# imagePullPolicy is the image pull policyimagePullPolicy: Always# hostNetwork can be true or falsehostNetwork: true# Set DNS policy for the pod.# Defaults to "ClusterFirst".# Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'.# DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy.# To have DNS options set along with hostNetwork, you have to specify DNS policy# explicitly to 'ClusterFirstWithHostNet'.dnsPolicy: ClusterFirstWithHostNet# resources describes the compute resource requirements and limitsresources:requests:memory: "512Mi"cpu: "250m"limits:memory: "1024Mi"cpu: "500m"# storageMode can be EmptyDir, HostPath, StorageClassstorageMode: EmptyDir# hostPath is the local path to store datahostPath: /data/rocketmq/nameserver# volumeClaimTemplates defines the storageClassvolumeClaimTemplates:- metadata:name: namesrv-storagespec:accessModes:- ReadWriteOncestorageClassName: rocketmq-storageresources:requests:storage: 1Gi注意到這個(gè)例子中 storageMode: EmptyDir,表示存儲(chǔ)使用的是 EmptyDir,數(shù)據(jù)會(huì)隨著 Pod 的刪除而抹去,因此該方式僅供開(kāi)發(fā)測(cè)試時(shí)使用。一般使用 HostPath 或 StorageClass 來(lái)對(duì)數(shù)據(jù)進(jìn)行持久化存儲(chǔ)。使用 HostPath 時(shí),需要配置 hostPath,聲明宿主機(jī)上掛載的目錄。使用 storageClass 時(shí),需要配置 volumeClaimTemplates,聲明 PVC 模版。具體可參考 RocketMQ Operator 文檔。
應(yīng)用上面的 yaml 文件,輸入命令:
$ kubectl apply -f example/rocketmq_v1alpha1_rocketmq_cluster.yaml broker.rocketmq.apache.org/broker created nameservice.rocketmq.apache.org/name-service created查看集群 Pod 狀態(tài):
$ kubectl get pods -owide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES broker-0-master-0 1/1 Running 0 27s 10.1.2.27 docker-desktop <none> <none> broker-0-replica-1-0 1/1 Running 0 27s 10.1.2.28 docker-desktop <none> <none> name-service-0 1/1 Running 0 27s 192.168.65.3 docker-desktop <none> <none> rocketmq-operator-76b4b9f4db-x52mz 1/1 Running 0 3h25m 10.1.2.17 docker-desktop <none> <none>使用默認(rèn)的 rocketmq_v1alpha1_rocketmq_cluster.yaml 文件配置,我們看到集群中拉起了 1 個(gè) name server 服務(wù)(name-service-0)和 2 個(gè) broker 服務(wù)(1 主 1 從)。
好啦!到這里你已經(jīng)成功通過(guò) Operator 提供的自定義資源部署了一個(gè) RocketMQ 服務(wù)集群。
- 訪問(wèn)這個(gè) RocketMQ 集群中的 Pod 來(lái)驗(yàn)證集群是否能正常工作;
使用 RocketMQ 的 tools.sh 腳本運(yùn)行 Producer example:
$ kubectl exec -it broker-0-master-0 bash bash-4.4# sh ./tools.sh org.apache.rocketmq.example.quickstart.Producer OpenJDK 64-Bit Server VM warning: ignoring option PermSize=128m; support was removed in 8.0 OpenJDK 64-Bit Server VM warning: ignoring option MaxPermSize=128m; support was removed in 8.0 06:56:29.145 [main] DEBUG i.n.u.i.l.InternalLoggerFactory - Using SLF4J as the default logging framework SendResult [sendStatus=SEND_OK, msgId=0A0102CF007778308DB1206383920000, offsetMsgId=0A0102CF00002A9F0000000000000000, messageQueue=MessageQueue [topic=TopicTest, brokerName=broker-0, queueId=0], queueOffset=0] ... 06:56:51.120 [NettyClientSelector_1] INFO RocketmqRemoting - closeChannel: close the connection to remote address[10.1.2.207:10909] result: true bash-4.4#在另一個(gè)節(jié)點(diǎn)上運(yùn)行 Consumer example:
$ kubectl exec -it name-service-0 bash bash-4.4# sh ./tools.sh org.apache.rocketmq.example.quickstart.Consumer OpenJDK 64-Bit Server VM warning: ignoring option PermSize=128m; support was removed in 8.0 OpenJDK 64-Bit Server VM warning: ignoring option MaxPermSize=128m; support was removed in 8.0 07:01:32.077 [main] DEBUG i.n.u.i.l.InternalLoggerFactory - Using SLF4J as the default logging framework Consumer Started. ConsumeMessageThread_1 Receive New Messages: [MessageExt [queueId=0, storeSize=273, queueOffset=19845, sysFlag=0, bornTimestamp=1596768410268, bornHost=/30.4.165.204:53450, storeTimestamp=1596768410282, storeHost=/100.81.180.84:10911, msgId=6451B45400002A9F000014F96A0D6C65, commitLogOffset=23061458676837, bodyCRC=532471758, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='TopicTest', flag=0, properties={MIN_OFFSET=19844, TRACE_ON=true, eagleTraceId=1e04a5cc15967684102641001d0db0, MAX_OFFSET=19848, MSG_REGION=DefaultRegion, CONSUME_START_TIME=1596783715858, UNIQ_KEY=1E04A5CC0DB0135FBAA421365A5F0000, WAIT=true, TAGS=TagA, eagleRpcId=9.1}, body=[72, 101, 108, 108, 111, 32, 77, 101, 116, 97, 81, 32, 48], transactionId='null'}]] ConsumeMessageThread_4 Receive New Messages: [MessageExt [queueId=1, storeSize=273, queueOffset=19637, sysFlag=0, bornTimestamp=1596768410296, bornHost=/30.4.165.204:53450, storeTimestamp=1596768410298, storeHost=/100.81.180.84:10911, msgId=6451B45400002A9F000014F96A0D7141, commitLogOffset=23061458678081, bodyCRC=1757146968, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='TopicTest', flag=0, properties={MIN_OFFSET=19636, TRACE_ON=true, eagleTraceId=1e04a5cc15967684102961002d0db0, MAX_OFFSET=19638, MSG_REGION=DefaultRegion, CONSUME_START_TIME=1596783715858, UNIQ_KEY=1E04A5CC0DB0135FBAA421365AB80001, WAIT=true, TAGS=TagA, eagleRpcId=9.1}, body=[72, 101, 108, 108, 111, 32, 77, 101, 116, 97, 81, 32, 49], transactionId='null'}]] ...- 刪除集群,清理環(huán)境;
清除 RocketMQ 服務(wù)集群實(shí)例:
$ kubectl delete -f example/rocketmq_v1alpha1_rocketmq_cluster.yaml清除 RocketMQ Operator:
$ ./purge-operator.sh按照 OperatorHub 官網(wǎng)指導(dǎo)安裝 RocketMQ Operator
- 在 OperatorHub.io?網(wǎng)頁(yè)搜索 RocketMQ Operator;
選擇 Streaming & Messaging 類別,點(diǎn)擊 RocketMQ Operator:
- 進(jìn)入 RocketMQ Operator 頁(yè)面,點(diǎn)擊 Install 按鈕;
- 按照說(shuō)明安裝 OLM 和 RocketMQ Operator;
本地安裝 OLM 來(lái)使用 RocketMQ Operator
- 本地安裝和動(dòng) OLM(Operator Lifecycle Manager) console;
參考:OLM 安裝文檔。
- 本地啟動(dòng) UI 界面控制臺(tái);
- 訪問(wèn) http://localhost:9000 查看控制臺(tái);
OperatorHub
-
搜索 RocketMQ 或點(diǎn)擊 All Items 分類中的 Streaming & Messaging,找到 RocketMQ Operator 并進(jìn)行安裝;
-
安裝完 RocketMQ Operator 后可以在 Installed Operators 中找到 RocketMQ Operator;
已安裝的 Operators 界面
RocketMQ Operator 介紹界面
通過(guò) UI 界面創(chuàng)建 NameService 自定義資源
可以在 UI 中創(chuàng)建指定 Namespace 下的 NameService 和 Broker 實(shí)例,并對(duì)已創(chuàng)建的實(shí)例進(jìn)行瀏覽和管理。我們也可以通過(guò)命令查看當(dāng)前 K8s 集群中的 Pod 狀態(tài),例如:
$ kubectl get pods -A NAMESPACE NAME READY STATUS RESTARTS AGE docker compose-78f95d4f8c-8fr5z 1/1 Running 0 32h docker compose-api-6ffb89dc58-nv9rh 1/1 Running 0 32h kube-system coredns-5644d7b6d9-hv6r5 1/1 Running 0 32h kube-system coredns-5644d7b6d9-mkqb6 1/1 Running 0 32h kube-system etcd-docker-desktop 1/1 Running 0 32h kube-system kube-apiserver-docker-desktop 1/1 Running 0 32h kube-system kube-controller-manager-docker-desktop 1/1 Running 1 32h kube-system kube-proxy-snmxh 1/1 Running 0 32h kube-system kube-scheduler-docker-desktop 1/1 Running 1 32h kube-system storage-provisioner 1/1 Running 1 32h kube-system vpnkit-controller 1/1 Running 0 32h marketplace broker-0-master-0 1/1 Running 0 5h3m marketplace broker-0-replica-1-0 1/1 Running 0 5h3m marketplace name-service-0 1/1 Running 0 5h3m marketplace marketplace-operator-69756457d8-42chk 1/1 Running 0 32h marketplace rocketmq-operator-0.2.1-c9fffb5f-cztcl 1/1 Running 0 32h marketplace rocketmq-operator-84c7bb4ddc-7rvqr 1/1 Running 0 32h marketplace upstream-community-operators-5b79db455f-7t47w 1/1 Running 1 32h olm catalog-operator-7b788c597d-gjz55 1/1 Running 0 32h olm olm-operator-946bd977f-dhszg 1/1 Running 0 32h olm operatorhubio-catalog-fvxp9 1/1 Running 0 32h olm packageserver-789c7b448b-7ss7m 1/1 Running 0 32h olm packageserver-789c7b448b-lfxrw 1/1 Running 0 32h可以看到在 marketplace 這個(gè) namespace 中也成功創(chuàng)建了對(duì)應(yīng)的 name server 和 broker 實(shí)例。
以上是基于 OperatorHub 和 OLM 安裝使用 RocketMQ Operator 的案例,我們將持續(xù)推送和維護(hù)新版本的 RocketMQ Operator 至該平臺(tái),方便用戶獲取最新更新或選擇合適的 Operator 版本。
社區(qū)
RocketMQ Operator 是 Apache 社區(qū)的開(kāi)源項(xiàng)目,服務(wù)于阿里巴巴 SaaS 類交付專有云,產(chǎn)品私有云環(huán)境部署等場(chǎng)景,同時(shí)也收到來(lái)自愛(ài)奇藝等互聯(lián)網(wǎng)公司開(kāi)源貢獻(xiàn)者的代碼提交。歡迎廣大用戶來(lái)社區(qū)項(xiàng)目中進(jìn)行反饋,點(diǎn)擊下方鏈接留下您的信息,讓我們更好地完善 RocketMQ Operator。
鏈接:https://github.com/apache/rocketmq-operator/issues/20
目前,RocketMQ Operator v0.2.1 的 PR 已合并進(jìn)入 community-operators 倉(cāng)庫(kù),RocketMQ Operator 進(jìn)入 OperatorHub.io 后,用戶可以通過(guò)使用 OLM(Operator Lifecycle Manager) 來(lái)安裝、訂閱 RocketMQ Operator,獲得持續(xù)的服務(wù)支持。
未來(lái)展望
RocketMQ Operator v0.2.1 支持的功能主要包括:Name Server 和 Broker 集群的自動(dòng)創(chuàng)建,Name Server 集群的無(wú)縫擴(kuò)容(自動(dòng)通知 Broker 集群更新 Name Server IP 列表),非順序消息下的 Broker 集群無(wú)縫擴(kuò)容(新 Broker 實(shí)例會(huì)從 Broker CRD 指定的源 Broker Pod 中同步元數(shù)據(jù),包括 Topic 信息和訂閱信息),以及 Topic 遷移等。
下一步我們希望和社區(qū)一起進(jìn)一步完善 RocketMQ Operator 項(xiàng)目,包括灰度發(fā)布,數(shù)據(jù)的全生命周期管理,容災(zāi)備份恢復(fù),流量等指標(biāo)監(jiān)控、自動(dòng)彈性擴(kuò)縮容等方面,最終實(shí)現(xiàn)通過(guò) Operator 可以覆蓋 RocketMQ 服務(wù)全生命周期的管理。
歡迎大家使用 RocketMQ Operator,提出寶貴建議。
相關(guān)鏈接
- RocketMQ Operator 項(xiàng)目:https://github.com/apache/rocketmq-operator
- OperatorHub:https://operatorhub.io/
- Operator Framework:https://github.com/operator-framework
- RocketMQ 官網(wǎng):https://rocketmq.apache.org/
- Apache RocketMQ 倉(cāng)庫(kù):https://github.com/apache/rocketmq
課程推薦
去年,CNCF 與 阿里云聯(lián)合發(fā)布了《云原生技術(shù)公開(kāi)課》已經(jīng)成為了 Kubernetes 開(kāi)發(fā)者的一門(mén)“必修課”。
今天,阿里云再次集結(jié)多位具有豐富云原生實(shí)踐經(jīng)驗(yàn)的技術(shù)專家,正式推出《云原生實(shí)踐公開(kāi)課》。課程內(nèi)容由淺入深,專注講解“ 落地實(shí)踐”。還為學(xué)習(xí)者打造了真實(shí)、可操作的實(shí)驗(yàn)場(chǎng)景,方便驗(yàn)證學(xué)習(xí)成果,也為之后的實(shí)踐應(yīng)用打下堅(jiān)實(shí)基礎(chǔ)。
點(diǎn)擊即可免費(fèi)觀看課程:https://developer.aliyun.com/learning/roadmap/cloudnative2020
“阿里巴巴云原生關(guān)注微服務(wù)、Serverless、容器、Service Mesh 等技術(shù)領(lǐng)域、聚焦云原生流行技術(shù)趨勢(shì)、云原生大規(guī)模的落地實(shí)踐,做最懂云原生開(kāi)發(fā)者的公眾號(hào)?!?/p>
總結(jié)
以上是生活随笔為你收集整理的云原生时代 RocketMQ 运维管控的利器 - RocketMQ Operator的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 进击的 Spring Cloud Ali
- 下一篇: 用 Arthas 神器来诊断 HBase