在Kubernetes上使用Sateful Set部署RabbitMQ集群

简介: 前面我们已经在Kubernetes上部署了Redis – 《在Kubernetes上使用Sateful Set部署Redis》。 本篇我们继续把RabbitMQ也跑在K8S上。 1.RabbitMQ的基础知识 在正式开始部署工作之前,我们先来复习一下RabbitMQ的一些基础知识。

前面我们已经在Kubernetes上部署了Redis – 《在Kubernetes上使用Sateful Set部署Redis》。 本篇我们继续把RabbitMQ也跑在K8S上。

1.RabbitMQ的基础知识


在正式开始部署工作之前,我们先来复习一下RabbitMQ的一些基础知识。

RabbitMQ内建的集群功能可以实现其高可用,允许消费者和生产者在RabbitMQ节点崩溃的情况下继续工作,同时可以通过添加更多的节点来提高消息处理的吞吐量。

RabbitMQ内部主要包含以下四种Meta Data:

  • vhost meta data:为RabbitMQ内部的Queue, Exchange, Binding提供命名空间级别的隔离
  • exchange meta data:记录Exchange的名称、类型、属性等
  • binding meta data:表示Routing Key和Queue之间的绑定关系,即描述如何将消息路由到队列Queue中
  • queue meta data: 记录队列的名称及其属性

单个节点的RabbitMQ会将这些meta data保存到内存中,同时对于那些属性为持久化的信息,例如durable的Exchange、Queue等持久化到硬盘上,持久化到硬盘上的Exchange和Queue可以在RabbitMQ节点重启后被重新创建。

当以集群形式部署RabbitMQ的多个节点时,RabbitMQ集群需要新的meta data来保存集群的信息。RabbitMQ集群有以下两种模式:

  • 普通模式:在这种模式下,对于集群中rabbit1和rabbit2两个节点,一个消息只会存在于其中某个节点上的Queue上。rabbit1和rabbit2这两个节点仅仅是拥有相同的meta data,即队列的结构和属性。当consumer连接rabbi2消费rabbit1上的消息时,RabbitMQ会在这两个节点上进行消息传输,将rabbit1上的消息传输到rabbit2上。在该模式下consumer和producer应该尽量连接每个节点,在多个节点建立物理队列,这样也起到了线性扩展的作用。但是在这种模式下要考虑一种情况,某个节点挂掉时其上面还有没有被消费的消息:如果队列和消息都做了持久化,只有该节点恢复时,消息才可以继续被消费;如果队列和消息没有持久化的话,就会丢失消息。
  • 镜像模式:就是把队列做成镜像队列,存在于多个节点上,在该模式下,消息会在节点的镜像队列间做同步,这样可以实现RabbitMQ高可用,但会降低系统性能,特别是镜像队列数量较多,大量消息进入和同步时会占用集群内部大量带宽。因此镜像模式使用于对可靠性要求比较高的场景。

接下来看一下镜像队列的声明,可以通过rabbitmqctl命令或在RabbitMQ Management WebUI中通过创建Policies的方式来声明镜像队列。例如:

rabbitmqctl set_policy ha-all "^ha\." '{"ha-mode":"all"}'

上面这个命令配置了策略,所有名称以ha.开始的队列,都会在集群的所有节点上成为镜像队列。这里使用的ha模式是all,另外还有exactly, nodes两种模式,分别可以指定具体的镜像节点数量,镜像节点名称,可以参考Highly Available (Mirrored) Queues,这里不再展开。

通过上面对RabbitMQ基础知识的一个简单的回顾,在使用RabbitMQ需要考虑一下几点:

  • Queue和Message是否要做持久化
  • 在使用RabbitMQ的集群时是否要使用镜像队列

2.构建RabbitMQ Docker镜像

RabbitMQ提供了一个Autocluster插件,可以自动创建RabbitMQ集群。下面我们将基于RabbitMQ的官方docker镜像,添加这个autocluster插件,构建我们自己的Rabbit镜像,以便在Kubernetes上使用这个镜像。

首选需要从这里下载autocluster和rabbitmq_aws插件,我这里下载的是0.8.0的最新版本。

mkdir -p rabbitmq/plugins
cd rabbitmq/plugins
wget https://github.com/rabbitmq/rabbitmq-autocluster/releases/download/0.8.0/autocluster-0.8.0.ez
wget https://github.com/rabbitmq/rabbitmq-autocluster/releases/download/0.8.0/rabbitmq_aws-0.8.0.ez
cd ..

我的Dockerfile的内容如下:

FROM rabbitmq:3.6.11-management-alpine

MAINTAINER frognew

RUN apk update && apk add ca-certificates && \
 apk add tzdata && \
 ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
 echo "Asia/Shanghai" > /etc/timezone
 

ADD plugins/*.ez /opt/rabbitmq/plugins/
RUN rabbitmq-plugins enable --offline autocluster
  • 这里选择是rabbitmq:3.6.11-management-alpine作为基础镜像
  • 添加了autocluster插件

下面构建这个镜像,并将其推送到我们的私有仓库:

docker build -t harbor.frognew.com/library/rabbitmq:3.6.11 .
docker push harbor.frognew.com/library/rabbitmq

3.以StatefulSet部署RabbitMQ

接下来将以以StatefulSet部署RabbitMQ集群,我们继续使用Ceph的块存储RBD作为存储卷,将RabbitMQ的数据保存在Ceph RBD中。 这就需要对我们的Kubernetes和Ceph集群做一些准备工作,需要在Ceph中创建专门给Kubernetes使用的存储池,同时配置Kubernetes的Node节点访问Ceph,并在Kubernetes上创建StorageClass,关于这些内容不再展开,可以参考之前写的在Kubernetes上使用Sateful Set部署Redis中2.1~2.3的内容。

前面在构建RabbitMQ的Docker镜像时,我们添加了autocluster插件,这个插件基于很多种backend做服务发现自动将发现的RabbitMQ节点添加到RabbitMQ集群中,autocluster当前支持如下几种backend:

  • AWS EC2 tags
  • AWS Autoscaling Groups
  • Kubernetes
  • DNS A records
  • Consul
  • etcd

Kubernetes赫然在列,实际上当使用Kubernetes作为rabbitmq-autocluster的backend时,autocluster会通过访问Kubernetes的API Server获取RabbitMQ服务的endpoints,这样就能拿到Kubernete集群中的RabbitMQ的Pod的信息,从而可以将它们添加到RabbitMQ的集群中去。 这里也就是说要在autocluster实际上是在RabbitMQ Pod中要访问Kubernetes的APIServer。

可是然后呢?因为已经对Kubernetes的API Server启用了TLS认证,同时也为API Server起到用了RBAC,要想从Pod中访问API Server需要借助Kubernetes的Service Account。 Service Account是Kubernetes Pod中的程序用于访问Kubernetes API的Account(账号),它为Pod中的程序提供访问Kubernetes API的身份标识。下面我们创建rabbitmq Pod的ServiceAccount,并针对Kubernetes的endpoint资源做授权,创建相关的role和rolebinding。

先说明一下,假设我们的部署是在dev这个namespace下的。创建如下的rabbitmq.rbac.yaml文件:

---
apiVersion: v1
kind: ServiceAccount
metadata:
 name: rabbitmq
 namespace: dev
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
 name: rabbitmq
 namespace: dev
rules: - apiGroups: - ""
 resources: - endpoints
 verbs: - get ---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
 name: rabbitmq
 namespace: dev
roleRef:
 apiGroup: rbac.authorization.k8s.io
 kind: Role
 name: dev
subjects: - kind: ServiceAccount
 name: rabbitmq
 namespace: dev

在Kubernetes上创建rabbitmq这个ServiceAccount以及相关的role和rolebinding:

kubectl create -f rabbitmq.rbac.yaml

下面创建rabbitmq.statefulset.yaml文件:

---
apiVersion: v1
kind: Service
metadata:
 name: rabbitmq-management
 namespace: dev
 labels:
 app: rabbitmq
spec:
 ports: - port: 15672
 name: http
 nodePort: 32001 - port: 5672
 name: amqp
 nodePort: 32002
 selector:
 app: rabbitmq
 type: NodePort ---
apiVersion: v1
kind: Service
metadata:
 name: rabbitmq
 namespace: dev
 labels:
 app: rabbitmq
spec:
 clusterIP: None
 ports: - port: 5672
 name: amqp
 selector:
 app: rabbitmq
---
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
 name: rabbitmq
 namespace: dev
spec:
 serviceName: rabbitmq
 replicas: 3 template:
 metadata:
 labels:
 app: rabbitmq
 spec:
 serviceAccountName: rabbitmq
 imagePullSecrets: - name: regsecret
 containers: - name: rabbitmq
 image: harbor.frognew.com/library/rabbitmq:3.6.11
 imagePullPolicy: IfNotPresent
 resources:
 requests:
 memory: "256Mi"
 cpu: "150m"
 limits:
 memory: "512Mi"
 cpu: "250m"
 ports: - containerPort: 5672
 name: amqp
 env: - name: RABBITMQ_DEFAULT_USER
 value: rabbituser
 - name: RABBITMQ_DEFAULT_PASS
 valueFrom:
 secretKeyRef:
 name: devsecret
 key: rabbitDefaultPass
 - name: RABBITMQ_ERLANG_COOKIE
 valueFrom:
 secretKeyRef:
 name: devsecret
 key: rabbitmqErlangCookie
 - name: MY_POD_NAME
 valueFrom:
 fieldRef:
 fieldPath: metadata.name
 - name: K8S_SERVICE_NAME
 value: "rabbitmq" - 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)"
 volumeMounts: - name: rabbitmq-volume
 mountPath: /var/lib/rabbitmq
 volumeClaimTemplates: - metadata:
 name: rabbitmq-volume
 spec:
 accessModes: [ "ReadWriteOnce" ]
 resources:
 requests:
 storage: 5Gi
  • 通过环境变量RABBITMQ_USE_LONGNAME, RABBITMQ_NODENAME, AUTOCLUSTER_TYPE, AUTOCLUSTER_DELAY, K8S_ADDRESS_TYPE, AUTOCLUSTER_CLEANUP等环境变量配置了autocluster插件,具体可以参考 RabbitMQ Autocluster中的文档内容
  • 通过RABBITMQ_ERLANG_COOKIE指定了Erlang cookie。RabbitMQ的集群是通过Erlang OTP实现的,而Erlang节点间通信的认证通过Erlang cookie来允许通信,这里从devsecret这个Secret中挂载。关于devsecret这个Secret这里不再给出。
  • 通过RABBITMQ_DEFAULT_USER和RABBITMQ_DEFAULT_PASS指定了RabbitMQ的管理员用户名和密码,也是从devsecret这个Secret中挂载的
  • 通过RABBITMQ_NODE_TYPE设置集群所有节点类型为disc,即为磁盘节点

为了在Kubernetes上运行RabbitMQ集群,必须保证各个RabbitMQ节点之间可以通信,也就是SatefulSet的Pod可以通信。 采用的RabbitMQ节点的命名方式为rabbit@hostdomainname的形式:

rabbit@rabbitmq-0.rabbit (rabbit@rabbitmq-0.rabbit.dev.svc.cluster.local)
rabbit@rabbitmq-1.rabbit (rabbit@rabbitmq-1.rabbit.dev.svc.cluster.local)
rabbit@rabbitmq-2.rabbit (rabbit@rabbitmq-2.rabbit.dev.svc.cluster.local)

可以看出采用的是长节点名的命名方式,因此设置了RABBITMQ_USE_LONGNAME为true。为了保证节点间可以通过访问rabbitmq-0.rabbit, rabbitmq-1.rabbit, rabbitmq-2.rabbit这些域名通信,必须使用Headless Service,上面rabbitmq Service的clusterIP: None这个必须设置。

在Kubernetes上创建Service和StatefulSet:

kubectl create -f rabbitmq.statefulset.yaml

kubectl get statefulset rabbitmq -n dev
NAME DESIRED CURRENT AGE
rabbitmq 3 3 25m

最后可以在RabbitMQ Management中查看RabbitMQ的3个节点已经组成了集群:

本文转自中文社区- 在Kubernetes上使用Sateful Set部署RabbitMQ集群

相关实践学习
容器服务Serverless版ACK Serverless 快速入门:在线魔方应用部署和监控
通过本实验,您将了解到容器服务Serverless版ACK Serverless 的基本产品能力,即可以实现快速部署一个在线魔方应用,并借助阿里云容器服务成熟的产品生态,实现在线应用的企业级监控,提升应用稳定性。
云原生实践公开课
课程大纲 开篇:如何学习并实践云原生技术 基础篇: 5 步上手 Kubernetes 进阶篇:生产环境下的 K8s 实践 相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
相关文章
|
22小时前
|
运维 Kubernetes 调度
【kubernetes】关于k8s集群的污点、容忍、驱逐以及k8s集群故障排查思路
【kubernetes】关于k8s集群的污点、容忍、驱逐以及k8s集群故障排查思路
|
22小时前
|
Kubernetes 负载均衡 应用服务中间件
k8s 二进制安装 优化架构之 部署负载均衡,加入master02
k8s 二进制安装 优化架构之 部署负载均衡,加入master02
|
1天前
|
Kubernetes 微服务 容器
Aspire项目发布到win11本地k8s集群
Aspire项目发布到win11本地k8s集群
3 0
Aspire项目发布到win11本地k8s集群
|
1天前
|
运维 Prometheus 监控
Kubernetes 集群的监控与维护策略
【5月更文挑战第30天】 在微服务架构日益普及的背景下,容器编排工具如Kubernetes成为确保服务高效运行的关键。本文聚焦于Kubernetes集群的监控和维护,首先探讨了监控系统的重要性及其对集群健康的影响,随后详细介绍了一套综合监控策略,包括节点性能监控、应用服务质量跟踪以及日志管理等方面。此外,文章还提出了一系列实用的集群维护技巧和最佳实践,旨在帮助运维人员预防故障发生,快速定位问题,并确保集群长期稳定运行。
|
1天前
|
Prometheus 监控 Kubernetes
Kubernetes 集群的监控与日志管理实践深入理解PHP的命名空间与自动加载机制
【5月更文挑战第30天】 在容器化和微服务架构日益普及的背景下,Kubernetes 已成为众多企业的首选容器编排工具。然而,随之而来的挑战是集群的监控与日志管理。本文将深入探讨 Kubernetes 集群监控的最佳实践,包括节点资源使用情况、Pods 健康状态以及网络流量分析等关键指标的监控方法。同时,我们也将讨论日志聚合、存储和查询策略,以确保快速定位问题并优化系统性能。文中将介绍常用的开源工具如 Prometheus 和 Fluentd,并分享如何结合这些工具构建高效、可靠的监控和日志管理系统。
|
2天前
|
Prometheus 监控 Kubernetes
Kubernetes 集群的监控与维护最佳实践
【5月更文挑战第30天】 在现代云计算环境中,容器编排工具如Kubernetes已成为部署和管理微服务的关键。随着其日益广泛的应用,对集群进行有效的监控和维护显得尤为重要。本文将深入探讨Kubernetes集群监控的策略,并分享维护的最佳实践,以确保系统的稳定性和性能优化。我们将从监控工具的选择、关键指标的跟踪到故障排除流程等方面进行详细阐述,并提供实用的操作建议。
|
1天前
|
存储 运维 Kubernetes
Kubernetes 集群的持续性能优化策略
【5月更文挑战第30天】 在动态且日益复杂的云计算环境中,保持 Kubernetes 集群的高性能和稳定性是一个持续的挑战。本文将探讨一系列实用的性能优化策略,旨在帮助运维专家识别并解决可能影响集群性能的问题。我们将从节点资源配置、网络优化、存储管理以及集群监控等方面入手,提供一系列经过实践检验的调优技巧,并分享最佳实践案例。这些策略不仅有助于提升现有集群的性能,也为规划新的 Kubernetes 部署提供了参考依据。
|
2天前
|
运维 Kubernetes 监控
Kubernetes 集群的持续性能优化实践
【5月更文挑战第30天】 在动态且日益复杂的云原生环境中,维持 Kubernetes 集群的高性能运行是一个持续的挑战。本文将探讨一系列针对性能监控、问题定位及优化措施的实践方法,旨在帮助运维专家确保其 Kubernetes 环境能够高效、稳定地服务于不断变化的业务需求。通过深入分析系统瓶颈,我们不仅提供即时的性能提升方案,同时给出长期维护的策略建议,确保集群性能的可持续性。
|
2天前
|
存储 Kubernetes 监控
Kubernetes 集群的持续性能优化实践
【5月更文挑战第29天】 在动态且复杂的微服务架构中,确保应用性能的稳定性与可预测性是一大挑战。本文将探讨一系列针对 Kubernetes 集群的持续性能优化策略,涵盖监控、资源管理、调度优化和网络效率等方面。通过分析真实案例并结合最新的运维实践,我们旨在提供一套系统化的性能调优框架,帮助运维工程师有效识别瓶颈,实施优化措施,并持续追踪改进效果,从而推动企业应用向更高效、稳定的方向发展。
|
2天前
|
机器学习/深度学习 存储 监控
Kubernetes 集群的持续监控与性能优化策略深度学习在图像识别中的应用与挑战
【5月更文挑战第29天】 在当今微服务架构和容器化部署的大背景下,Kubernetes 已成为众多企业的首选平台。然而,随着集群规模的扩大和业务复杂性的增加,如何确保系统的高可用性和性能稳定性成为一个挑战。本文将探讨针对 Kubernetes 集群实施的持续监控方案以及针对性能瓶颈的优化策略,旨在帮助运维人员有效管理和提升其服务的质量。