rabbitmq
RabbitMQ是實現了高級消息隊列協議的開源消息代理軟件。RabbitMQ服務器是用Erlang語言編寫的,而聚類和故障轉移是構建在開放電信平臺框架上的。所有主要的編程語言均有與代理接口通訊的客戶端庫。同時rabbitmq的使用非常的廣泛,所以使用容器化的方式快速部署rabbitmq集羣非常的有必要。
關於rabbitmq服務組成
rabbitmq服務實質郵4大部分組成
- epmd服務,rabbitmq起來後會自動的啓動epmd服務,empd服務是erlang的一個小程序,專門用來做端口管理的。通常端口是4369
- rabbitmq amqp server,這個服務就是我們通常使用rabbitmq服務的時候,鏈接的5672端口的服務,使用來支持amqp服務的。通常端口是5672
- rabbitmq cluster server,主要是用來做cluster節點之間的心跳發現的,通常端口是25672
- 如果開啓來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數據庫的數據存儲目錄)。然後重啓節點,讓節點重新加入集羣。