RabbitMQ (bundled subchart)
For demo and development installs, the chart can bring up its own RabbitMQ. For production, use the RabbitMQ Cluster Operator.
The subchart is CloudPirates rabbitmq,
which runs the official docker.io/rabbitmq image.
Enabling it
rabbitmq:
enabled: true
auth:
username: "waldur"
password: "waldur"
The chart’s default values already declare the plugins and ports Waldur needs.
Plugins and ports
Waldur needs four ports on the broker Service:
| port | purpose | required by |
|---|---|---|
| 5672 | AMQP | Celery broker URL |
| 15672 | management API | RABBITMQ["MANAGEMENT_PORT"] |
| 61613 | STOMP | RABBITMQ["STOMP_PORT"], set when waldur.rabbitmqEvents.stompEnabled |
| 15674 | web-STOMP | backend of templates/ingress-rmq-ws.yaml |
5672 and 15672 are always present. The other two come from the plugins, and this
chart does not derive Service ports from plugin names — so extraPorts has
to declare them explicitly alongside additionalPlugins:
rabbitmq:
additionalPlugins:
- rabbitmq_stomp
- rabbitmq_web_stomp
- rabbitmq_auth_backend_ldap
extraPorts:
- name: stomp
port: 61613
containerPort: 61613
targetPort: 61613
- name: stomp-websocket
port: 15674
containerPort: 15674
targetPort: 15674
Drop an entry from either list and the STOMP event stream stops working without
helm install failing.
Credentials
rabbitmq.auth.username and rabbitmq.auth.password are copied into the
waldur-secret Secret by templates/secrets.yaml, and the application reads them
from there. When pointing at a broker deployed outside the chart, set
rabbitmq.enabled: false plus rabbitmq.host and rabbitmq.secret.* instead.
IPv6-only and dual-stack clusters
The bundled broker works on an IPv6-only cluster out of the box; the chart’s default values carry the wiring and no operator configuration is needed. Two separate parts of RabbitMQ default to IPv4 and both are redirected:
| part | what defaults to IPv4 | how the chart fixes it |
|---|---|---|
| Erlang name resolution | epmd resolves the node’s own hostname through inet, which asks for A records only |
an inetrc with {inet6, true} plus -proto_dist inet6_tcp, applied from a rabbitmq-env.conf that tests /proc/net/if_inet6 at container start |
| Cowboy HTTP listeners | the management API (15672) and web-STOMP (15674) bind 0.0.0.0 |
management.tcp.ip = :: and web_stomp.tcp.ip = :: in rabbitmq.config.extraConfiguration |
Without the first, the broker aborts at boot even though the AAAA record resolves:
{epmd_error,"<pod>.<svc>.<ns>.svc.cluster.local",nxdomain}
The CLI half of it (CTL_ERL_ARGS) is not optional. Both the liveness and the
readiness probe run rabbitmq-diagnostics -q check_running, so without it the
broker boots but the pod never becomes ready and every rabbitmqctl call hangs
until it times out.
Without the second, the broker runs and AMQP works, but the management API and
the realtime web-STOMP stream behind templates/ingress-rmq-ws.yaml are
unreachable. Note that rabbitmq-diagnostics listeners reports these two as
[::] whether or not they are — /proc/net/tcp and /proc/net/tcp6 inside the
pod are the only reliable check:
kubectl exec <broker-pod> -- bash -c \
'tail -n +2 /proc/net/tcp | awk "\$4==\"0A\"{print \$2}"'
Binding [::] is correct on IPv4-only, IPv6-only and dual-stack clusters alike:
with the Linux default net.ipv6.bindv6only=0 the same socket also accepts IPv4
connections as v4-mapped. A host whose kernel has IPv6 compiled out or disabled
at boot is the one case that needs an override — empty
rabbitmq.config.extraConfiguration; the Erlang half already no-ops there.
Installing RabbitMQ separately
helm install rmq oci://registry-1.docker.io/cloudpirates/rabbitmq \
--version 0.21.19 -f rmq-values.yaml
That produces a Service named rmq-rabbitmq, the default of rabbitmq.host.
Clustering
More than one replica requires peer discovery. This chart does not cluster on its own — the Kubernetes peer discovery plugin has to be switched on explicitly:
replicaCount: 3
peerDiscoveryK8sPlugin:
enabled: true
rmq-values.yaml sets both. Leave the plugin off and replicaCount: 3 gives you
three independent brokers sharing one Service. Nothing fails: helm install
succeeds and all three pods report Ready. But every client connection is
load-balanced onto an arbitrary node, and the nodes share no state, so:
- a queue declared on one node does not exist on the others;
celery inspect ping— the worker’s startup, liveness and readiness probe — usually lands on a node without the worker’s pidbox queue and returnsError: No nodes replied within time constraint, so the worker fails its probes and is killed and restarted while loggingcelery@… ready.;- published tasks strand on whichever node the publisher happened to reach,
leaving durable queues with messages and
consumers=0; - Celery’s native delayed delivery fails to bind (
Exchange.bind: (404) NOT_FOUND - no exchange 'tasks-durable' in vhost '/'), because thecelery_delayed_*queues and the task exchanges land on different nodes.
Verify clustering after install — every pod must list all nodes, not just itself:
for i in 0 1 2; do
kubectl exec rmq-rabbitmq-$i -c rabbitmq -- rabbitmqctl cluster_status
done
The bundled subchart defaults to replicaCount: 1, where none of this applies;
the same rule holds if you raise it.
Migrating from the Bitnami subchart
An existing Bitnami volume cannot be reused, even though the PVC name is the
same. Bitnami stored mnesia at /bitnami/rabbitmq/mnesia; the official image
uses /var/lib/rabbitmq. Reattaching the old claim gives RabbitMQ an empty
mnesia directory — it starts clean, with no queues, users or vhosts.
For a dev/test broker that is usually fine: delete the old PVC and let the new one initialise. For anything with durable state, drain the queues first or export definitions from the management API and re-import them after the switch.
Values that changed shape: extraPlugins (a space-separated string) became
additionalPlugins (a list); extraContainerPorts and service.extraPorts
merged into a single extraPorts list; clustering.forceBoot has no equivalent.