使用 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 版本兼容,才能顺利完成安装。

相关推荐
ChinaRainbowSea37 分钟前
1. 初始 RabbitMQ 消息队列
java·中间件·rabbitmq·java-rabbitmq
爱的叹息1 小时前
主流数据库的存储引擎/存储机制的详细对比分析,涵盖关系型数据库、NoSQL数据库和分布式数据库
数据库·分布式·nosql
千层冷面2 小时前
RabbitMQ 发送者确认机制详解
分布式·rabbitmq·ruby
ChinaRainbowSea2 小时前
3. RabbitMQ 的(Hello World) 和 RabbitMQ 的(Work Queues)工作队列
java·分布式·后端·rabbitmq·ruby·java-rabbitmq
敖正炀2 小时前
基于RocketMQ的可靠消息最终一致性分布式事务解决方案
分布式
一條狗4 小时前
随笔 20250402 分布式 ID 生成器 Snowflake 里面的坑
分布式
小马爱打代码4 小时前
Kubernetes 中部署 Ceph,构建高可用分布式存储服务
分布式·ceph·kubernetes
码熔burning4 小时前
【Spring Cloud Alibaba】:Nacos 入门讲解
分布式·spring cloud·微服务
hycccccch12 小时前
Canal+RabbitMQ实现MySQL数据增量同步
java·数据库·后端·rabbitmq
低头不见17 小时前
一个服务器算分布式吗,分布式需要几个服务器
运维·服务器·分布式