Docker 部署 RabbitMQ:队列还在,消息没了
背景与目标
RabbitMQ 是最常用的消息中间件之一,用来做异步任务、解耦服务、削峰填谷。Windows 上原生安装要配 Erlang 环境,版本对不上就起不来,容器化省掉了这层麻烦。
但它的容器化有个别处没有的特点:RabbitMQ 是 Erlang 节点,节点名长这样——rabbit@rabbitmq,后半段就是容器的 hostname。数据目录里记着这个身份,Erlang cookie 也绑在同一个目录。所以会出现两类完全不同的"数据丢失":
节点层:卷挂错、hostname 变了,容器重建后认不出自己的旧数据,队列和用户直接"消失";
消息层:节点好好的,队列也在,但消息没落盘,重启后只剩空队列。
本文给你一份把两层都配好的 compose,并把这两层各自的坑拆开讲。
提示:宿主 Windows (Docker Desktop),镜像走华为云。管理界面由
-management镜像提供,基础镜像里没有。
步骤
第 0 步:确认 Docker Desktop 已就绪
docker version
docker compose version输出版本号即 OK。
第 1 步:准备目录
mkdir rabbitmq && cd rabbitmq第 2 步:写 docker-compose.yaml
新建 docker-compose.yaml,整段复制:
services:
rabbitmq:
image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/rabbitmq:4-management
container_name: rabbitmq
hostname: rabbitmq
environment:
RABBITMQ_DEFAULT_USER: "admin"
RABBITMQ_DEFAULT_PASS: "YourStrong!Passw0rd"
RABBITMQ_DEFAULT_VHOST: "/"
TZ: "Asia/Shanghai"
ports:
- "5672:5672"
- "15672:15672"
volumes:
- ./rabbitmq-data:/var/lib/rabbitmq
restart: unless-stopped要点:
hostname: rabbitmq不能省。节点名由此决定,重建容器时 hostname 一旦变化,旧数据就"不属于"新节点。卷挂的是
/var/lib/rabbitmq整个目录,不是下面的mnesia子目录。.erlang.cookie和mnesia/都在这一层。RABBITMQ_DEFAULT_USER/PASS:首次初始化时创建的管理账号,避开受限的guest。端口:
5672是 AMQP 协议端口,程序连这个;15672是管理界面,浏览器开这个。单节点适合开发与个人使用;集群与高可用不在本文范围。
第 3 步:启动
docker compose up -d首次启动要初始化节点,稍等。看日志:
docker compose logs -f rabbitmq看到 Server startup complete 即就绪。
第 4 步:连接验证
先确认节点活着:
docker compose exec rabbitmq rabbitmq-diagnostics -q ping返回 Ping succeeded 即 broker 正常。
再用浏览器打开管理界面:
http://localhost:15672用 admin / YourStrong!Passw0rd 登录,然后走一遍收发闭环:
Queues → Add a new queue,Name 填
demo,Durability 选Durable;进
demo,Publish message 随便填个 payload 发一条;在队列页 Get messages,能取到刚才那条。
能登录、能建队列、能发能收,说明 5672 与 15672 都通了。
验证


踩坑与解决
1. 卷挂到了 mnesia 子目录:重建后用户和队列全没
问题:容器重建后,之前建的队列、用户、权限都没了。
复现:volumes 写成
./rabbitmq-data:/var/lib/rabbitmq/mnesia,docker compose down再up,管理界面回到初始状态。根因:Erlang cookie(
.erlang.cookie)在/var/lib/rabbitmq这一层,mnesia/只放元数据。只挂子目录时 cookie 留在容器可写层,随容器销毁重新生成,新 cookie 与旧数据记录的节点身份对不上。解决:挂父目录
/var/lib/rabbitmq(本文写法)。已经挂错的,改成父目录后docker compose down -v重建,接受一次数据清空。验证:重建后管理界面里的 queues / users 仍在。
2. hostname 变了,节点起不来或数据"回退"
问题:不写
hostname时,删容器重建后 RabbitMQ 启动报节点相关错误,或数据像被重置。复现:去掉
hostname: rabbitmq,执行docker compose down && docker compose up -d,日志出现unable to perform an operation on node之类的报错。根因:节点名是
rabbit@<hostname>。不指定 hostname 时 Docker 用容器 ID,每次重建都变;数据目录里的旧节点名与新节点名不匹配。解决:固定
hostname: rabbitmq(本文已写),且不要随意改。真要改名,单机场景直接删卷重建最省事;集群场景才考虑rabbitmqctl rename_cluster_node。验证:
docker compose exec rabbitmq hostname始终输出rabbitmq,重建后不变。
3. 管理界面 15672 打不开:镜像不带插件
问题:容器起来了,
http://localhost:15672却连不上。复现:镜像用的是
rabbitmq:4(不带-management),15672 端口无响应。根因:management 是插件,基础镜像默认不启用,也不会监听 15672。
解决:换成
rabbitmq:4-management(本文);或进容器手动启用:docker compose exec rabbitmq rabbitmq-plugins enable rabbitmq_management由于挂了
/var/lib/rabbitmq,插件启用状态会随数据目录保留。验证:浏览器能打开登录页。
4. guest 登录被拒:它只允许本机连接
问题:想用默认的
guest/guest登录管理界面,提示登录失败。复现:删掉
RABBITMQ_DEFAULT_*后从宿主机浏览器登录,日志/客户端报user 'guest' can only connect via localhost。根因:
guest是受限账号,只允许回环地址连接。容器里的"localhost"不是你的宿主机,所以从浏览器、其他容器、其他机器都连不上。解决:显式设
RABBITMQ_DEFAULT_USER/RABBITMQ_DEFAULT_PASS(本文),业务再用独立账号或 vhost 隔离;不要放开guest的 loopback 限制。验证:用
admin能从宿主机登录,guest依旧被拒。
5. 重启后队列还在,消息没了
问题:管理界面里队列
demo还在,但里面的消息空了。复现:发几条消息,
docker compose down && docker compose up -d,消息数量归零。根因:Docker 卷只保住 broker 的元数据(队列定义、绑定、用户)。消息是否落盘,取决于三件事同时成立:队列声明为
durable、消息投递时设delivery_mode=2(persistent)、以及等你收到 publisher confirm 才认为发送成功。缺任何一件,重启都可能丢。解决:生产消息时用持久化队列 + 持久化投递 + 开启 publisher confirm;只有明确可丢的消息(日志、指标)才用非持久化换吞吐。
验证:发 10 条持久化消息,
down再up,队列里仍是 10 条。
通用坑(与 SQL Server / MySQL / Redis / MongoDB / PostgreSQL / MinIO 篇相同,不再重复展开)
端口被占:5672 或 15672 已被别的程序占用,报
port is already allocated。改外部端口,如5673:5672、15673:15672,客户端连接串和浏览器地址同步改。数据丢了:没挂卷,容器销毁即丢失。本教程已挂
./rabbitmq-data:/var/lib/rabbitmq。容器秒退:先看
docker compose logs rabbitmq,再对照上面第 1、2 条。
小结与参考
用 Docker 部署 RabbitMQ 4,两个端口分工明确:
5672给程序,15672给管理界面。节点身份靠两样固定:卷挂
/var/lib/rabbitmq整个目录、hostname写死不改。本篇核心矛盾:持久化分两层。卷 + 稳定 hostname 保住"节点",durable 队列 + persistent 消息 + publisher confirm 才保住"消息";只做一半,就会出现"队列在、消息没"。
不要用
guest做跨主机连接,首次就设RABBITMQ_DEFAULT_USER/PASS。管理界面需要
-management镜像或手动启用插件。
参考:
镜像:
swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/rabbitmq:4-managementRabbitMQ 官方文档:https://www.rabbitmq.com/docs

