排查集群 Operator 故障
请使用此信息排查 RabbitMQ Kubernetes 集群 Operator 的常见问题。
注意,以下信息可能对“自助式”(DIY)RabbitMQ on Kubernetes 部署有所帮助,但此类环境并非其主要关注点。
常见场景与错误
某些错误有专门的章节
RabbitMQ 集群部署失败
创建 RabbitMQ 实例后,几分钟内仍不可用且 RabbitMQ Pod 未运行。
导致此类故障的常见原因包括:
- 集群中 CPU 或内存不足
imagePullSecrets配置不正确。这会导致无法从 Docker 镜像仓库拉取镜像。storageClassName配置不正确。
解决此问题的潜在方案:
- 运行
kubectl describe pod POD-NAME查看是否有任何警告(例如0/1 nodes are available: 1 Insufficient memory.) - 更正
imagePullSecrets和storageClassName配置。请参阅 imagePullSecrets、持久化 以及 更新 RabbitMQ 实例。 - 如果更新上述配置后问题仍然存在,请按照 检查实例状态 中的过程查看 RabbitMQ 集群资源的状态。
如果部署到资源受限的集群(例如 kind 或 minikube 等本地环境),您可能需要调整集群的 CPU 和/或内存限制。请查看 资源限制示例 以了解如何操作。
Pod 未被创建
例如出现以下错误:
pods POD-NAME is forbidden: unable to validate against any pod security policy: []
作为 Kubernetes Operator 部署的底层 ReplicaSet 事件,或者作为 RabbitmqCluster 的底层 StatefulSet 事件。
如果 Kubernetes 集群启用了 Pod 安全策略准入控制,但您尚未创建必要的 PodSecurityPolicy 和相应的基于角色的访问控制 (RBAC) 资源,则会发生这种情况。
潜在解决方案是按照 Pod 安全策略 中的步骤创建 PodSecurityPolicy 和 RBAC 资源。
Pod 在启动时重启
RabbitMQ 容器可能在 Pod 启动时失败,并记录类似以下消息:
epmd error for host rabbitmq-server-1.rabbitmq-nodes.mynamespace: nxdomain (non-existing domain)
或
Error during startup: {error,no_epmd_port}
Pod 重启并最终变为 Ready 状态。
由于 RabbitMQ 节点在 启动时解析自身及其对等节点的 hostname,因此可能需要将 CoreDNS 缓存超时时间 从默认的 30 秒降低到 5-10 秒范围内。
Pod 处于 CrashLoopBackOff 状态
由于 Kubernetes 会重启失败的 Pod,如果 RabbitMQ 节点无法启动,它很可能会进入 CrashLoopBackOff 状态——即尝试启动、失败并再次重启。在这种情况下,如果需要访问 Pod 或其数据,调试或修复问题可能会很困难。
调试此类情况的方法之一是创建一个不属于 StatefulSet 但挂载了相同持久化卷的新 Pod。以下是挂载 RabbitMQ 节点持久化卷的 Pod 定义示例:
apiVersion: v1
kind: Pod
metadata:
name: debug-rabbitmq
spec:
volumes:
- name: persistence
persistentVolumeClaim:
claimName: persistence-RMQ_NAME-server-2
containers:
- name: debug-rabbitmq
image: ... # you can use any image here, but for some tasks you should use the same image you use in the statefulset
command: ["/bin/sleep", "36000"]
volumeMounts:
- mountPath: /var/lib/rabbitmq/mnesia/
name: persistence
完成后,退出 Pod 并将其删除。
重建节点
在某些情况下,必须将节点退役(永久从集群中移除)并替换为新节点。新节点随后将从其对等节点同步数据。
使用 Operator 更换节点的流程如下:
以下过程将完全删除一个 Pod(RabbitMQ 节点)及其磁盘。这意味着该节点上所有未复制的数据都将丢失。请确保您了解其后果。
在此示例中,我们假设要重建 server-2。如果要删除其他节点,请相应调整命令。
kubectl rabbitmq pause-reconciliation RMQ_NAME(如果您没有 kubectl-rabbitmq 插件/CLI,也可以添加标签)——这意味着 Operator 不会“修复”(覆盖)对底层对象的任何手动更改。kubectl delete statefulset --cascade=orphan RMQ_NAME-server——删除 StatefulSet,使其不会“修复”Pod(在我们删除丢失的 Pod 后重新创建它)。kubectl delete pod RMQ_NAME-server-2(您可以在此处删除任何您想要的 Pod)。kubectl delete pvc persistence-RMQ_NAME-server-2(如果persistentVolumeReclaimPolicy设置为Delete,这将删除 PV 以及该节点上的所有数据)。kubectl delete pv PV_NAME(仅在persistentVolumeReclaimPolicy设置为Retain时需要;这将删除 PV 及该节点上的所有数据)。rabbitmqctl forget_cluster_node rabbit@RMQ_NAME-server-2.RMQ_NAME-nodes.NAMESPACE(从任何运行中的节点执行)——从集群中移除已删除的节点。kubectl rabbitmq resume-reconciliation RMQ_NAME(或删除标签)——Operator 将重新创建 StatefulSet,StatefulSet 将重新创建丢失的 Pod;该节点应加入集群。
在节点重建前后检查法定人数(Quorum)状态,以确保集群保持健康。详情请参阅 法定人数状态监控。
- 将法定人数队列(Quorum Queues)和流(Streams)扩展到新节点:
rabbitmq-queues grow rabbit@RMQ_NAME-server-2.RMQ_NAME-nodes.NAMESPACE allrabbitmq-streams add_replica STREAM_NAME rabbit@RMQ_NAME-server-2.RMQ_NAME-nodes.NAMESPACE
在 RabbitMQ 4.1 和 4.2 中,server-0 是特殊的。如果您需要重建带有 -0 后缀的节点,则需要显式地使其加入现有集群(例如 rabbitmqctl join_cluster rabbit@RMQ_NAME-server-1)。否则,它将作为独立节点运行。
Pod 卡在终止状态
症状:“删除 RabbitmqCluster 实例后,某些 Pod 卡在终止状态。RabbitMQ 仍在受影响的 Pod 中运行。”
原因:“最可能的原因是 RabbitMQ 中残留了法定人数队列(Quorum Queue)。具有法定人数关键状态的 Pod 会受到 preStop 钩子的保护,防止被终止。”
在强制删除 Pod 之前,请检查集群的法定人数状态,以了解该 Pod 是否为法定人数关键(quorum critical)。有关如何检查和解释法定人数状态的详情,请参阅 法定人数状态监控。
解决此问题的潜在方案:
- 确保队列中没有消息,或者确认删除这些消息是可以接受的。
- 通过运行以下命令强制删除队列:
kubectl delete pod --force --grace-period=0 POD-NAME
此示例使用 Pod 名称:
kubectl delete pod --force rabbit-rollout-restart-server-1
# warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.
# pod 'rabbit-rollout-restart-server-1' force deleted
要查看实例状态,请运行:
kubectl -n NAMESPACE get all
其中 NAMESPACE 是实例所在的 Kubernetes 命名空间。
例如:
kubectl -n rmq-instance-1 get all
# NAME READY STATUS RESTARTS AGE
# pod/example-server-0 1/1 Running 0 2m27s
<br/>
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# service/example-nodes ClusterIP None None 4369/TCP 2m27s
# service/example ClusterIP 10.111.202.183 None 5672/TCP,15672/TCP,15692/TCP 2m28s
<br/>
# NAME READY AGE
# statefulset.apps/example-server 1/1 2m28s
集群 Operator 启动失败
部署 RabbitMQ Cluster Operator 后,它在启动期间失败且其 Pod 被重启。
导致此类故障的常见原因包括:
- Operator 无法连接到 Kubernetes API。
解决此问题的潜在方案:
- 检查 Operator 是否仍在崩溃。Pod 重启可以解决许多中间问题,因此重启只是一个症状,而非问题本身。
- 查看 Operator 日志 (
kubectl -n rabbitmq-system logs -l app.kubernetes.io/name=rabbitmq-cluster-operator) - 您可能会看到类似以下的错误:
无法获取 API Group-ResourcesGet https://ADDRESS:443/api: connect: connection refused
- 检查您的 Kubernetes 集群是否健康,特别是
kube-apiserver组件。 - 检查是否有任何网络安全策略阻止 Operator 访问 Kubernetes API 服务器。
RabbitMQ 集群状态条件
RabbitMQ 实例具有描述 RabbitMQ 集群当前状态的 status.conditions。要获取状态,请运行:
kubectl describe rmq RMQ_NAME
状态条件示例可能如下所示:
Name: test-rabbit
Namespace: rabbitmq-system
API Version: rabbitmq.com/v1beta1
Kind: RabbitmqCluster
...
Status:
Binding:
Name: sample-default-user
Conditions:
Last Transition Time: 2023-07-07T11:57:10Z
Reason: AllPodsAreReady
Status: True
Type: AllReplicasReady # true when all RabbitMQ pods are 'ready'
Last Transition Time: 2023-07-07T11:57:10Z
Reason: AtLeastOneEndpointAvailable
Status: True
Type: ClusterAvailable # true when at least one RabbitMQ pod is 'ready'
Last Transition Time: 2023-07-07T11:55:58Z
Reason: NoWarnings
Status: True
Type: NoWarnings
Last Transition Time: 2023-07-07T11:57:11Z
Message: Finish reconciling
Reason: Success
Status: True
Type: ReconcileSuccess
...
如果状态条件 ReconcileSuccess 为 false,则意味着上次协调(reconcile)发生错误,RabbitMQ 集群配置可能已过时。查看集群 Operator 日志有助于了解协调失败的原因。
获取 Operator 日志:
kubectl -n rabbitmq-system logs -l app.kubernetes.io/name=rabbitmq-cluster-operator