使用 Helm 部署 RabbitMQ 高可用集群(HA)

在这篇教程中,我们将介绍如何通过 Helm 在 Kubernetes 集群中部署 RabbitMQ 高可用集群(HA)。我们将从下载和配置 Helm Chart 包开始,接着会介绍一些常见错误的解决方案,以帮助你顺利完成部署。

步骤 1:搜索并下载 RabbitMQ HA Helm Chart

首先,添加一些常见的 Helm 仓库,如 Bitnami、Aliyun 和 Azure 等

python 复制代码
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo add stable http://mirror.azure.cn/kubernetes/charts
helm repo add aliyun https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts
helm repo add incubator https://charts.helm.sh/incubator
helm repo update

然后,我们需要在 Helm 仓库中搜索 RabbitMQ HA Chart。使用以下命令可以列出所有相关的 RabbitMQ Chart。

bash 复制代码
helm search repo rabbitmq

输出示例:

复制代码
NAME                                    CHART VERSION   APP VERSION     DESCRIPTION
aliyun/rabbitmq                         0.6.21          3.7.3           Open source message broker software that implem...
aliyun/rabbitmq-ha                      1.0.0           3.7.3           Highly available RabbitMQ cluster, the open sou...
bitnami/rabbitmq                        15.2.3          4.0.5           RabbitMQ is an open source general-purpose mess...
bitnami/rabbitmq-cluster-operator       4.4.2           2.12.0          The RabbitMQ Cluster Kubernetes Operator automa...
stable/rabbitmq                         0.6.21          3.7.3           Open source message broker software that implem...
stable/rabbitmq-ha                      1.0.0           3.7.3           Highly available RabbitMQ cluster, the open sou...

选择 stable/rabbitmq-ha,然后使用 helm pull 下载该 Chart 包。

bash 复制代码
helm pull stable/rabbitmq-ha

解压下载的 Chart 包:

bash 复制代码
tar -xvf rabbitmq-ha-1.0.0.tgz
cd rabbitmq-ha/

步骤 2:修改 values.yaml 配置文件

在 Chart 解压后,我们可以找到 values.yaml 文件,修改其中的配置以满足我们的需求。

以下是关键配置项的修改示例:

yaml 复制代码
rabbitmqUsername: rabbitmq
rabbitmqPassword: rabbitmq
image:
  repository: docker-0.unsee.tech/rabbitmq
  tag: 3.7-alpine
  pullPolicy: IfNotPresent
service:
  type: NodePort
persistentVolume:
  enabled: false  # 如果需要开启持久化存储,将此项改为 true
  accessModes:
    - ReadWriteMany
  size: 8Gi

在这里,我们更改了 RabbitMQ 的用户名和密码,还设置了 RabbitMQ 镜像的自定义地址。同时,我们配置了 NodePort 类型的服务,并禁用了持久化存储(你可以根据需求修改为启用)。

步骤 3:安装 RabbitMQ HA

完成配置后,使用 Helm 安装 RabbitMQ HA 集群。

bash 复制代码
helm install rabbitmq-ha ./rabbitmq-ha

安装完成后,可以通过以下命令查看服务和 Pod 状态。

查看服务状态:

bash 复制代码
kubectl get svc

输出示例:

复制代码
NAME                      TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                                         AGE
kubernetes                ClusterIP   10.96.0.1    <none>        443/TCP                                         3d21h
rabbitmq-ha-rabbitmq-ha   NodePort    10.96.3.50   <none>        15672:32241/TCP,5672:31214/TCP,4369:32046/TCP   2m53s

查看 Pod 状态:

bash 复制代码
kubectl get pod

输出示例:

复制代码
NAME                                              READY   STATUS             RESTARTS   AGE
nfs-subdir-external-provisioner-dc68ff47f-g8k6n   0/1     ImagePullBackOff   0          47m
rabbitmq-ha-rabbitmq-ha-0                         1/1     Running            0          3m7s
rabbitmq-ha-rabbitmq-ha-1                         1/1     Running            0          84s
rabbitmq-ha-rabbitmq-ha-2                         1/1     Running            0          60s

步骤 4:浏览器访问 RabbitMQ 管理界面

RabbitMQ 管理界面可以通过 NodePort 服务进行访问,使用以下 IP 地址和端口:

复制代码
http://192.168.80.130:32241/

登录账号密码为:

复制代码
用户名:rabbitmq
密码:rabbitmq

常见错误及解决办法

错误 1:API 版本不兼容

如果在安装过程中遇到以下错误:

复制代码
Error: INSTALLATION FAILED: unable to build kubernetes objects from release manifest: [resource mapping not found for name: "rabbitmq-ha-rabbitmq-ha" namespace: "" from "": no matches for kind "Role" in version "rbac.authorization.k8s.io/v1beta1"]

分析: 这是因为 Kubernetes 1.16 版本后,许多 API 版本被更新或废弃,rbac.authorization.k8s.io/v1beta1apps/v1beta1 已被废弃。

解决方法: 将 Helm Chart 中的 API 版本更新为适用于 Kubernetes 1.22 及以上版本的 API 版本,具体如下:

  • rbac.authorization.k8s.io/v1(替代 v1beta1
  • apps/v1(替代 v1beta1

你需要在 templates/ 目录下的资源定义文件中手动更新这些 API 版本。

错误 2:StatefulSet 的 selector 和 labels 不匹配

如果遇到以下错误:

复制代码
Error: INSTALLATION FAILED: StatefulSet.apps "rabbitmq-ha-rabbitmq-ha" is invalid: [spec.selector: Required value, spec.template.metadata.labels: Invalid value: map[string]string{"app":"rabbitmq-ha", "release":"rabbitmq-ha"}: `selector` does not match template `labels`]

分析: 错误表明,StatefulSetspec.selector 部分与 spec.template.metadata.labels 部分的内容不一致。

解决方法: 打开 statefulset.yaml 文件,确保 spec.selector.matchLabelsspec.template.metadata.labels 部分的标签一致。

例如,修改以下部分:

yaml 复制代码
selector:
  matchLabels:
    app: {{ template "rabbitmq-ha.name" . }}
    release: {{ .Release.Name }}

同时确保 template.metadata.labels 部分的标签一致:

yaml 复制代码
labels:
  app: {{ template "rabbitmq-ha.name" . }}
  release: {{ .Release.Name }}

完整的statefulset.yaml 示例:

python 复制代码
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: {{ template "rabbitmq-ha.fullname" . }}
  labels:
    app: {{ template "rabbitmq-ha.name" . }}
    chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
    release: {{ .Release.Name }}
    heritage: {{ .Release.Service }}
spec:
  serviceName: {{ template "rabbitmq-ha.fullname" . }}
  replicas: {{ .Values.replicaCount }}
  updateStrategy:
    type: {{ .Values.updateStrategy }}
  selector:
    matchLabels:
      app: {{ template "rabbitmq-ha.name" . }}
      release: {{ .Release.Name }}
  template:
    metadata:
      labels:
        app: {{ template "rabbitmq-ha.name" . }}
        release: {{ .Release.Name }}
      annotations:
        {{- if not .Values.customConfigMap }}
        checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
        {{- end }}
    spec:
      terminationGracePeriodSeconds: 10
      serviceAccountName: {{ template "rabbitmq-ha.serviceAccountName" . }}
      containers:
        - name: {{ .Chart.Name }}
          image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - name: epmd
              protocol: TCP
              containerPort: 4369
            - name: amqp
              protocol: TCP
              containerPort: 5672
            - name: http
              protocol: TCP
              containerPort: 15672
            {{- if .Values.rabbitmqSTOMPPlugin.enabled }}
            - name: stomp-tcp
              protocol: TCP
              containerPort: 61613
            - name: stomp-ssl
              protocol: TCP
              containerPort: 61614
            {{- end }}
            {{- if .Values.rabbitmqWebSTOMPPlugin.enabled }}
            - name: stomp-ws
              protocol: TCP
              containerPort: 15674
            {{- end }}
            {{- if .Values.rabbitmqMQTTPlugin.enabled }}
            - name: mqtt-tcp
              protocol: TCP
              containerPort: 1883
            - name: mqtt-ssl
              protocol: TCP
              containerPort: 8883
            {{- end }}
            {{- if .Values.rabbitmqWebMQTTPlugin.enabled }}
            - name: mqtt-ws
              protocol: TCP
              containerPort: 15675
            {{- end }}
          livenessProbe:
            exec:
              command:
                - rabbitmqctl
                - status
            initialDelaySeconds: 30
            timeoutSeconds: 5
          readinessProbe:
            exec:
              command:
                - rabbitmqctl
                - status
            initialDelaySeconds: 10
            timeoutSeconds: 5
          env:
            - name: MY_POD_IP
              valueFrom:
                fieldRef:
                  fieldPath: status.podIP
            - name: RABBITMQ_USE_LONGNAME
              value: "true"
            - name: RABBITMQ_NODENAME
              value: "rabbit@$(MY_POD_IP)"
            - name: K8S_SERVICE_NAME
              value: {{ template "rabbitmq-ha.fullname" . }}
            - name: RABBITMQ_ERLANG_COOKIE
              valueFrom:
                secretKeyRef:
                  name: {{ template "rabbitmq-ha.fullname" . }}
                  key: rabbitmq-erlang-cookie
            {{- if .Values.rabbitmqHipeCompile }}
            - name: RABBITMQ_HIPE_COMPILE
              value: {{ .Values.rabbitmqHipeCompile | quote }}
            {{- end }}
            - name: RABBITMQ_DEFAULT_USER
              value: {{ .Values.rabbitmqUsername | quote }}
            - name: RABBITMQ_DEFAULT_PASS
              valueFrom:
                secretKeyRef:
                  name: {{ template "rabbitmq-ha.fullname" . }}
                  key: rabbitmq-password
            - name: RABBITMQ_DEFAULT_VHOST
              value: {{ .Values.rabbitmqVhost | quote }}
          resources:
{{ toYaml .Values.resources | indent 12 }}
          volumeMounts:
            - name: data
              mountPath: /var/lib/rabbitmq
            - name: config
              mountPath: /etc/rabbitmq
      {{- if .Values.nodeSelector }}
      nodeSelector:
{{ toYaml .Values.nodeSelector | indent 8 }}
      {{- end }}
      {{- if .Values.tolerations }}
      tolerations:
{{ toYaml .Values.tolerations | indent 8 }}
      {{- end }}
      {{- if eq .Values.podAntiAffinity "hard" }}
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - topologyKey: "kubernetes.io/hostname"
              labelSelector:
                matchLabels:
                  app: {{ template "rabbitmq-ha.name" . }}
                  release: {{ .Release.Name }}
      {{- else if eq .Values.podAntiAffinity "soft" }}
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
            - weight: 1
              podAffinityTerm:
                topologyKey: kubernetes.io/hostname
                labelSelector:
                  matchLabels:
                    app: {{ template "rabbitmq-ha.name" . }}
                    release: {{ .Release.Name }}
      {{- end }}
      volumes:
        - name: config
          configMap:
            name: {{ template "rabbitmq-ha.fullname" . }}
{{- if .Values.persistentVolume.enabled }}
  volumeClaimTemplates:
    - metadata:
        name: data
        annotations:
        {{- range $key, $value := .Values.persistentVolume.annotations }}
          {{ $key }}: {{ $value }}
        {{- end }}
      spec:
        accessModes:
        {{- range .Values.persistentVolume.accessModes }}
          - {{ . | quote }}
        {{- end }}
        resources:
          requests:
            storage: {{ .Values.persistentVolume.size | quote }}
      {{- if .Values.persistentVolume.storageClass }}
      {{- if (eq "-" .Values.persistentVolume.storageClass) }}
        storageClassName: ""
      {{- else }}
        storageClassName: "{{ .Values.persistentVolume.storageClass }}"
      {{- end }}
      {{- end }}
{{- else }}
        - name: data
          emptyDir: {}
{{- end }}

结论

通过以上步骤,你成功地在 Kubernetes 集群上使用 Helm 部署了 RabbitMQ 高可用集群。你可以使用浏览器访问管理界面,并根据需要调整配置,处理常见的安装错误。在部署过程中,确保 Helm Chart 与 Kubernetes API 版本兼容,才能顺利完成安装。

相关推荐
茶杯梦轩1 天前
从零起步学习RabbitMQ || 第三章:RabbitMQ的生产者、Broker、消费者如何保证消息不丢失(可靠性)详解
分布式·后端·面试
回家路上绕了弯3 天前
深入解析Agent Subagent架构:原理、协同逻辑与实战落地指南
分布式·后端
用户8307196840823 天前
Spring Boot 集成 RabbitMQ :8 个最佳实践,杜绝消息丢失与队列阻塞
spring boot·后端·rabbitmq
用户8307196840825 天前
RabbitMQ vs RocketMQ 事务大对决:一个在“裸奔”,一个在“开挂”?
后端·rabbitmq·rocketmq
初次攀爬者6 天前
RabbitMQ的消息模式和高级特性
后端·消息队列·rabbitmq
初次攀爬者8 天前
ZooKeeper 实现分布式锁的两种方式
分布式·后端·zookeeper
让我上个超影吧9 天前
消息队列——RabbitMQ(高级)
java·rabbitmq
塔中妖9 天前
Windows 安装 RabbitMQ 详细教程(含 Erlang 环境配置)
windows·rabbitmq·erlang
断手当码农9 天前
Redis 实现分布式锁的三种方式
数据库·redis·分布式
初次攀爬者9 天前
Redis分布式锁实现的三种方式-基于setnx,lua脚本和Redisson
redis·分布式·后端