kubernetes容器化常用中間件之rabbitmq

rabbitmq

RabbitMQ是實現了高級消息隊列協議的開源消息代理軟件。RabbitMQ服務器是用Erlang語言編寫的,而聚類和故障轉移是構建在開放電信平臺框架上的。所有主要的編程語言均有與代理接口通訊的客戶端庫。同時rabbitmq的使用非常的廣泛,所以使用容器化的方式快速部署rabbitmq集羣非常的有必要。

關於rabbitmq服務組成

rabbitmq服務實質郵4大部分組成

  1. epmd服務,rabbitmq起來後會自動的啓動epmd服務,empd服務是erlang的一個小程序,專門用來做端口管理的。通常端口是4369
  2. rabbitmq amqp server,這個服務就是我們通常使用rabbitmq服務的時候,鏈接的5672端口的服務,使用來支持amqp服務的。通常端口是5672
  3. rabbitmq cluster server,主要是用來做cluster節點之間的心跳發現的,通常端口是25672
  4. 如果開啓來rabbitmq manager plugin,會有一個manager api服務,通常端口是15672

除以上的服務之外,還有一個是erlang自帶的數據庫,專門用來做分部署服務發現的: mnesia數據庫。可以從官網查看詳細的文檔rabbitmq官網

容器化步驟

容器化的第一步是製作rabbitmq鏡像,rabbitmq是基於erlang語言開發的,所以需要在erlang環境中運行,製作rabbitmq鏡像,也非常的簡單,需要參照官網對應rabbitmq版本和對應的erlang的版本進行鏡像製作,由於rabbitmq自身有官方的鏡像,所以在這片文章中我直接只用rabbitmq官方鏡像。rabbitmq官方鏡像有帶manager-plugin的和不帶plugin的。我們使用帶manager-plugin的。除此之外,我們依靠官方的一個auto-cluster插件去完成rabbitmq的集羣自動初始化。所以還需要在官方鏡像的基礎上安裝auto-cluster插件。


FROM 3.7.26-management-alpine

ADD https://github.com/rabbitmq/rabbitmq-autocluster/releases/download/0.10.0/autocluster-0.10.0.ez /opt/rabbitmq/plugins/
ADD https://github.com/rabbitmq/rabbitmq-autocluster/releases/download/0.10.0/rabbitmq_aws-0.10.0.ez /opt/rabbitmq/plugins/

RUN rabbitmq-plugins enable --offline rabbitmq_management && rabbitmq-plugins enable --offline autocluster

編譯製作鏡像完成後,開始寫k8s相關的yaml文件,並部署rabbitmq集羣

部署rabbitmq集羣

auto-cluster插件也是erlang開發的,同時它需要去k8s中查詢endpoint,所以需要有對應的查詢k8s的endpoint的權限,第一步是創建RBAC。

創建RBAC

apiVersion: v1
kind: ServiceAccount
metadata:
  name: rabbitmq-autocluster
  namespace: default

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: rabbitmq-autocluster
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: rabbitmq-autocluster
  namespace: default

創建headless service

apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/name: rabbitmq
    app.kubernetes.io/instance: rabbitmq-demo
    app.kubernetes.io/version: 3.7.26
  name: rabbitmq-demo
  namespace: default
spec:
  clusterIP: None
  ports:
  - name: amqp
    port: 5672
    protocol: TCP
    targetPort: 5672
  selector:
    app.kubernetes.io/instance: rabbitmq-demo
    app.kubernetes.io/version: 3.7.26
  sessionAffinity: None
  type: ClusterIP

創建secret保存adminuser,pass和erlang cookie

apiVersion: v1
kind: Secret
metadata:
  labels:
    app.kubernetes.io/name: rabbitmq
    app.kubernetes.io/instance: rabbitmq-demo
    app.kubernetes.io/version: 1.1.1
  name: rabbitmq-config
  namespace: default
data:
  rabbitmqDefaultPass: base64 password
  rabbitmqDefaultUser: base64 user
  rabbitmqErlangCookie: base64 cookie

自行更改對應的user,pass,cookie

創建statefulset

apiVersion: apps/v1
kind: StatefulSet
metadata:
  labels:
    app.kubernetes.io/name: rabbitmq
    app.kubernetes.io/instance: rabbitmq-demo
    app.kubernetes.io/version: 3.7.26
  name: rabbitmq-demo
  namespace: default
spec:
  replicas: 3
  selector:
    matchLabels:
      app.kubernetes.io/instance: rabbitmq-demo
      app.kubernetes.io/version: 3.7.26
  serviceName: rabbitmq-demo
  template:
    metadata:
      labels:
        app.kubernetes.io/instance: rabbitmq-demo
        app.kubernetes.io/version: 3.7.26
    spec:
      containers:
      - env:
        - name: RABBITMQ_DEFAULT_USER
          valueFrom:
            secretKeyRef:
              key: rabbitmqDefaultUser
              name: rabbitmq-config
        - name: RABBITMQ_DEFAULT_PASS
          valueFrom:
            secretKeyRef:
              key: rabbitmqDefaultPass
              name: rabbitmq-config
        - name: RABBITMQ_ERLANG_COOKIE
          valueFrom:
            secretKeyRef:
              key: rabbitmqErlangCookie
              name: rabbitmq-config
        - name: MY_POD_NAME
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.name
        - name: K8S_SERVICE_NAME
          value: rabbitmq-oam-mq-mq-1
        - name: RABBITMQ_USE_LONGNAME
          value: "true"
        - name: RABBITMQ_NODENAME
          value: rabbit@$(MY_POD_NAME).$(K8S_SERVICE_NAME)
        - name: RABBITMQ_NODE_TYPE
          value: disc
        - name: AUTOCLUSTER_TYPE
          value: k8s
        - name: AUTOCLUSTER_DELAY
          value: "10"
        - name: AUTOCLUSTER_CLEANUP
          value: "true"
        - name: CLEANUP_WARN_ONLY
          value: "false"
        - name: K8S_ADDRESS_TYPE
          value: hostname
        - name: K8S_HOSTNAME_SUFFIX
          value: .$(K8S_SERVICE_NAME)
        image: 製作的rabbitmq鏡像
        imagePullPolicy: IfNotPresent
        name: rabbitmq
        resources:
          limits:
            cpu: 512m
            memory: 1G
          requests:
            cpu: 521m
            memory: 1G
        securityContext:
          privileged: true
        volumeMounts:
        - mountPath: /var/lib/rabbitmq
          name: data
      serviceAccount: rabbitmq-autocluster
      volumes:
      - emptyDir: {}
        name: data  

關於auto-cluster插件依賴的環境變量的配置請參考rabbitmq-autocluster,有詳細的介紹和說明,可以根據自己的實際情況進行設置。

需要注意的點

  • AUTOCLUSTER_CLEANUP 這個環境變量是用來設置自動清除不健康的節點,需要配合CLEANUP_WARN_ONLY=false,同時也依賴CLEANUP_INTERVAL這個參數,默認是60s,每隔一分鐘進行一次檢測,當檢測到不健康節點的時候,就會吧節點從集羣中刪除,對應的節點上的數據也相應丟失,如果對應的queue沒設置成mirror queue是非常危險的。所以一般會AUTOCLUSTER_CLEANUP =false。如果AUTOCLUSTER_CLEANUP設置成true,當不健康節點節點從集羣中剔除,後面故障節點又重新起來後,由於故障節點中存儲的的信息中,包含該節點屬於之前的集羣,所以節點在起來後會嘗試加入之前的集羣,但是之前的集羣已經吧它剔除, 所以導致故障節點一直起不來,並且報錯: 大致意思是,節點yyy嘗試加入集羣xxx,但是集羣xxx不認爲節點yyy是xxx的節點。 這個時候,需要吧對應的故障節點的數據目錄下的mnesia數據目錄(mnesia數據目錄是erlang自帶的mnesia數據庫的數據存儲目錄)。然後重啓節點,讓節點重新加入集羣。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章