用 Docker 部署 RabbitMQ:从入门到实战全细节
这是写给未来自己的 RabbitMQ + Docker 全流程备忘:一次搞明白端口、账号、虚拟主机、持久化、集群和常见坑,以后再搭环境直接照着抄就行。
一、RabbitMQ 是什么,为什么要自己部署?
一句话版本:
- RabbitMQ 是一个实现了 AMQP 协议的消息中间件,常用于解耦服务、削峰填谷、异步处理任务等场景。
典型用法:
- Web 请求里只负责把任务写入队列,真实耗时逻辑交给后台消费者慢慢处理;
- 多个微服务之间,用消息队列传递事件(订单创建、支付成功、库存变更……);
- 延迟任务、重试队列、死信队列等等。
选择自己用 Docker 部署而不是托管服务的理由:
- 成本更可控:学习 / 内网环境不需要云上托管 MQ;
- 方便调试:本地就能起一套完整的 RabbitMQ 环境;
- 可迁移性强:Docker 化后,迁机器基本是复制配置 + 数据卷。
本文默认你已经对 “消息队列是什么” 有一点点概念,重点放在:
- 如何用 Docker 跑起 RabbitMQ,并打开可视化管理界面;
- 如何设置账号、密码、虚拟主机、权限;
- 如何做好数据持久化,避免重建容器时配置丢失;
- 如何用
docker-compose管理 RabbitMQ; - (选读)如何简单拉一个 多节点集群;
- 部署中高频踩坑与排查思路。
二、镜像选择与基础概念
RabbitMQ 官方镜像在 Docker Hub 上维护,推荐的几个标签:
rabbitmq:3-management- 带 Web 管理控制台,是开发 / 调试最常用的版本。
rabbitmq:3- 纯核心服务,不带 Web UI,适合资源有限或生产环境配监控系统。
rabbitmq:3-management-alpine- 基于 Alpine 的轻量版,体积更小。
为了方便,我们后面都用:
rabbitmq:3-management。
默认端口一览
RabbitMQ 镜像启动后,常见端口:
- 5672:AMQP 协议端口(应用连 MQ 用的端口);
- 15672:Web 管理控制台端口;
- (可选)5671:AMQP over TLS;
- (可选)15671:管理界面 HTTPS;
- (可选)25672:集群节点间通信端口。
后文的端口映射都围绕这些展开。
默认账号密码
RabbitMQ 默认会创建一个:
- 用户名:
guest - 密码:
guest
重要限制:
- 默认
guest/guest只能本机访问(localhost),如果你从远程 IP 访问,会被拒绝。
这也是为什么生产环境一定要创建自己的账号,并关掉或限制 guest 的原因。
三、拉取镜像并做第一次试跑
先拉镜像(确保 Docker 已安装并能正常工作):
docker pull rabbitmq:3-management确认镜像:
docker images | grep rabbitmq1. 最小运行示例(仅用于本地试用)
先用一个最简单的命令把 RabbitMQ 跑起来:
docker run --name my-rabbitmq \ -p 5672:5672 \ -p 15672:15672 \ -d rabbitmq:3-management参数含义:
--name my-rabbitmq:容器名称,后续方便用docker logs my-rabbitmq来看日志等;-p 5672:5672:暴露核心的 AMQP 服务端口;-p 15672:15672:暴露 Web 管理控制台;-d:后台运行;rabbitmq:3-management:使用带管理控制台的官方镜像。
启动后查看容器状态:
docker ps2. 打开 Web 管理控制台
浏览器访问:
http://127.0.0.1:15672默认账号:
- 用户名:
guest - 密码:
guest
能够登录就说明 RabbitMQ 已经跑起来了。
不过,目前这个环境还存在几个问题:
- 没有数据卷,容器删了配置就没了(包括用户、虚拟主机、队列持久化等);
- 仍然使用默认
guest/guest,并且理论上只允许本机登录; - 没有任何自定义配置(如集群、TLS、限流等)。
接下来一步步补齐。
四、数据持久化:挂载卷与配置目录
RabbitMQ 的 Docker 镜像中,主要有两个值得挂载的目录:
/var/lib/rabbitmq:数据目录(队列、消息、元数据等);/etc/rabbitmq:配置文件目录(rabbitmq.conf/advanced.config等)。
实践中,至少挂在 /var/lib/rabbitmq,否则重建容器时数据容易消失。
如果你有自定义配置(比如特定策略、TLS 设置等),再挂 /etc/rabbitmq。
1. 创建宿主机目录
以 Linux / macOS 为例:
mkdir -p ~/docker-data/rabbitmq/datamkdir -p ~/docker-data/rabbitmq/confWindows(PowerShell)类似:
mkdir C:\docker-data\rabbitmq\datamkdir C:\docker-data\rabbitmq\conf2. 用数据卷重新运行容器
先停掉之前的试用容器:
docker stop my-rabbitmqdocker rm my-rabbitmq再用带卷的命令重新启动:
docker run --name my-rabbitmq \ -p 5672:5672 \ -p 15672:15672 \ -v ~/docker-data/rabbitmq/data:/var/lib/rabbitmq \ -v ~/docker-data/rabbitmq/conf:/etc/rabbitmq \ -d rabbitmq:3-management现在,RabbitMQ 的数据和配置文件都落在宿主机,对应目录中。
后面添加的用户、虚拟主机、队列等信息都会持久化保存。
注意:刚启动时
/etc/rabbitmq可能是空的,但只要我们不挂载配置文件,RabbitMQ 会用默认配置启动。这时挂载conf目录主要是为将来扩展准备。
五、创建自己的用户与虚拟主机
现实中你几乎不应该用 guest/guest(特别是在暴露到网络时)。
推荐做法:
- 新建一个自己的管理员用户;
- 新建一个业务用虚拟主机(vhost);
- 赋予该用户对 vhost 的权限;
- 根据需要关闭或限制
guest用户。
1. 通过 Web UI 创建
进入 http://127.0.0.1:15672,默认 guest/guest 登录。
创建新用户:
- 进入
Admin标签页; Add a user:- Username:比如
app_user - Password:自行设定一个复杂点的密码
- Tags:选
administrator(也可以按需控制权限) - 点击
Add user。
- Username:比如
创建虚拟主机:
- 仍然在
Admin标签页; Virtual Hosts→Add a new virtual host;- Name:比如
/app或app_vhost; - 点击
Add virtual host。
给用户授权:
- 在
Admin→Users找到app_user; - 点击用户名进入详情页;
- 在
Permissions部分选择刚刚创建的 vhost(比如/app); - 配置
Configure / Write / Read权限(简单起见可以写.*); - 点击
Set permission。
之后,客户端只需要使用:
- user:
app_user - pass:你设置的密码
- vhost:
/app(或app_vhost)
即可连接到 RabbitMQ,并在这个 vhost 中创建交换机和队列。
2. 通过命令行创建(可脚本化)
如果你想把这些写进自动化脚本,可以用 rabbitmqctl / rabbitmq-plugins 等命令。
先进入容器:
docker exec -it my-rabbitmq bash容器内部执行:
# 创建用户rabbitmqctl add_user app_user 'Your_Strong_Password'
# 给用户加管理员标签(可选)rabbitmqctl set_user_tags app_user administrator
# 创建虚拟主机rabbitmqctl add_vhost /app
# 为用户在 /app vhost 上设置权限rabbitmqctl set_permissions -p /app app_user ".*" ".*" ".*"
# (按需)禁用 guest 用户的远程访问,或者直接删掉 guest# 禁用 guest 最常见做法是只允许本地访问,这通常通过配置文件完成退出容器:
exit这些命令产生的用户 / vhost 配置同样会写入 /var/lib/rabbitmq,即已经被我们持久化。
六、用 docker-compose 管理 RabbitMQ
当你不想每次都敲上面那串 docker run 命令时,就是 docker-compose 出场的时候。
在一个目录(比如 deploy/rabbitmq)下创建 docker-compose.yml:
version: "3.9"
services: rabbitmq: image: rabbitmq:3-management container_name: my-rabbitmq restart: always ports: - "5672:5672" # AMQP - "15672:15672" # Web 管理界面 environment: RABBITMQ_DEFAULT_USER: app_user RABBITMQ_DEFAULT_PASS: Your_Strong_Password RABBITMQ_DEFAULT_VHOST: /app volumes: - ./data:/var/lib/rabbitmq - ./conf:/etc/rabbitmq这里做的事情:
- 通过环境变量设置了一个默认用户和虚拟主机:
- 容器第一次启动时,会自动创建
app_user//app; - 后续再重启不会重复创建(数据已在
./data里)。
- 容器第一次启动时,会自动创建
- 用
./data、./conf做挂载点,让数据和配置都持久化在当前目录。
在该目录下运行:
docker compose up -d查看状态:
docker compose ps关闭服务:
docker compose down只要不加 -v,./data 里的内容会一直保留。
小建议:不要把真实密码硬编码在仓库里的 compose 文件中,可以用
.env或部署系统的 Secret 管理。
使用 .env 管理账号密码
在 docker-compose.yml 同目录下创建 .env:
RABBITMQ_USER=app_userRABBITMQ_PASS=Your_Strong_PasswordRABBITMQ_VHOST=/app然后在 docker-compose.yml 中这么写:
environment: RABBITMQ_DEFAULT_USER: ${RABBITMQ_USER} RABBITMQ_DEFAULT_PASS: ${RABBITMQ_PASS} RABBITMQ_DEFAULT_VHOST: ${RABBITMQ_VHOST}这样,你可以在不同环境用不同 .env 文件,而 compose 文件本身保持不变。
七、应用如何连接 Docker 中的 RabbitMQ
无论你用什么语言,本质上连接参数都差不多:
- 主机:
127.0.0.1(本地)或服务器 IP / 域名; - 端口:
5672(默认 AMQP 端口); - 用户名 / 密码:
RABBITMQ_DEFAULT_USER/RABBITMQ_DEFAULT_PASS; - 虚拟主机:
RABBITMQ_DEFAULT_VHOST。
以 Node.js + amqplib 为例:
npm install amqplibimport amqp from "amqplib";
const host = "127.0.0.1";const port = 5672;const user = "app_user";const pass = "Your_Strong_Password";const vhost = "/app";
const url = `amqp://${encodeURIComponent(user)}:${encodeURIComponent( pass)}@${host}:${port}${vhost}`;
async function main() { const conn = await amqp.connect(url); const channel = await conn.createChannel();
const queue = "demo_queue";
await channel.assertQueue(queue, { durable: true, });
await channel.sendToQueue(queue, Buffer.from("hello from docker-rabbitmq"), { persistent: true, });
console.log("消息已发送");
await channel.close(); await conn.close();}
main().catch(console.error);通过这个 demo,你可以检查:
- 队列是否创建成功(在 Web 控制台 Queues 标签页能看到);
- 消息是否成功发送、持久化。
八、消息持久化与可靠性:队列、消息、确认机制
RabbitMQ 的 “持久化” 不是一开镜像就有,需要满足几个条件:
- 队列本身要设置为
durable: true; - 消息发送时需要设置
deliveryMode=2(大部分语言里就是persistent: true); - 节点的数据目录
/var/lib/rabbitmq要挂载到宿主机; - 最好启用
publisher confirms,确保消息确实被 Broker 接收。
否则,Broker 重启或容器销毁时,消息和队列可能会丢。
1. 队列持久化
上面 Node.js 示例中的:
await channel.assertQueue(queue, { durable: true,});中的 durable: true 就是设置队列为持久化队列。
2. 消息持久化
发送消息时:
channel.sendToQueue(queue, Buffer.from("..."), { persistent: true,});这里的 persistent: true 即把 delivery_mode 设置为 2。
3. Publisher Confirms(发布确认)
为了确保消息真正被 Broker 接收(而不是在网络途中丢失),推荐:
- 使用
confirm channel,即在 Node.js 中createConfirmChannel; - 每发送一批消息都等 RabbitMQ 返回 ack。
简单示例:
const confirmChannel = await conn.createConfirmChannel();
confirmChannel.sendToQueue( queue, Buffer.from("message with confirm"), { persistent: true }, (err, ok) => { if (err) { console.error("消息未被确认", err); } else { console.log("消息已被 Broker 确认"); } });这是深入生产环境时必备的可靠性手段。
九、(进阶)简单 RabbitMQ 集群部署示例
RabbitMQ 支持通过 Erlang 分布式机制组建多节点集群。
这里给一个教学向的 Docker Compose 集群例子,帮助理解结构,不一定直接用于生产。
提示:RabbitMQ 集群配置本身比较讲究主机名解析、cookie、磁盘节点 / 内存节点等,生产环境建议参考官方文档或专门的部署教程,这里只做一个入门示例。
1. 基本思路
- 准备两个节点
rabbit1和rabbit2,加入同一个集群; - 用同一份
ERLANG_COOKIE,保证它们能互相通信; - 把
rabbit2加入到以rabbit1为核心的集群。
2. 示例 docker-compose.yml(精简版)
在一个单独的目录(如 deploy/rabbitmq-cluster)创建:
version: "3.9"
services: rabbit1: image: rabbitmq:3-management hostname: rabbit1 container_name: rabbit1 environment: RABBITMQ_ERLANG_COOKIE: "MY_SECRET_COOKIE" RABBITMQ_DEFAULT_USER: app_user RABBITMQ_DEFAULT_PASS: Your_Strong_Password RABBITMQ_DEFAULT_VHOST: /app ports: - "5672:5672" - "15672:15672" volumes: - ./data/rabbit1:/var/lib/rabbitmq
rabbit2: image: rabbitmq:3-management hostname: rabbit2 container_name: rabbit2 environment: RABBITMQ_ERLANG_COOKIE: "MY_SECRET_COOKIE" depends_on: - rabbit1 volumes: - ./data/rabbit2:/var/lib/rabbitmq启动集群:
docker compose up -d3. 手动把 rabbit2 加入 rabbit1
进入 rabbit2 容器:
docker exec -it rabbit2 bash执行如下命令(注意有停服务 / 加入集群 / 启服务的顺序):
rabbitmqctl stop_apprabbitmqctl join_cluster rabbit@rabbit1rabbitmqctl start_app回到 rabbit1 的 Web 管理界面 http://127.0.0.1:15672,登录后在 Overview 页面就能看到集群节点列表中出现 rabbit1 与 rabbit2。
再次强调:生产环境需要考虑磁盘节点(disc)与内存节点(ram)、镜像队列策略(HA)、跨机房网络延迟等,这里只是一个把多节点拉起来的起步版本。
十、与反向代理 / 安全策略的关系
RabbitMQ 默认不是 HTTP 服务,但它有一个 Web 管理端口(15672),你可能会想把它:
- 通过 Nginx 做一层反向代理;
- 绑定域名并加上 HTTPS;
- 再加上 Basic Auth 或 IP 白名单保护。
一个典型的 Nginx 片段可能是这样:
server { listen 80; server_name rabbitmq-admin.your-domain.com;
location / { proxy_pass http://127.0.0.1:15672; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; }}实战中,还会继续叠加:
- 把
listen 80换成listen 443 ssl字段,并配置证书; - 通过
allow/deny控制可访问 IP; - 或在前面加一个认证层(比如 Basic Auth)。
对于 5672(AMQP 端口),一般不会走反向代理,而是直接在内网暴露(局域网或安全组控制)。
十一、常见坑与排查思路
这一节专门列一些部署 RabbitMQ 时常见的问题和排查方法。
1. 容器一直重启 / 退出
首先看日志:
docker logs my-rabbitmq常见错误包括:
- 权限问题(对
/var/lib/rabbitmq或/etc/rabbitmq目录无写入权限); - 配置文件语法错误(尤其是自己写了
rabbitmq.conf或advanced.config); - ERLANG_COOKIE 不一致(在做集群时)。
排查建议:
- 先去掉自定义配置和卷,只用最小命令确认基础镜像没问题;
- 再一步步加上卷和配置;
- 没必要一上来就搞集群,把单节点跑稳再说。
2. 端口被占用
如果启动时报 bind (..) failed: port is already allocated,说明 5672 或 15672 已经被占用。
解决:
- 换宿主机端口映射,比如:
ports: - "5673:5672" - "15673:15672"连接时就用 5673 / 15673。
3. 客户端连接被拒绝 / 授权失败
常见错误消息:
ACCESS_REFUSED - Login was refused using authentication mechanism PLAIN. For details see the broker logfile.ACCESS_REFUSED - vhost '/app' refused.
检查清单:
- 用户名、密码是否正确;
- 指定的 vhost 是否存在;
- 是否给该用户在 vhost 上授权了
Configure/Read/Write权限; - 是否使用
guest/guest在远程访问(默认不允许)。
4. 消费者和队列的关系混乱
有时候你会发现:
- 队列里看起来有消息,但消费者收不到;
- 或者消费者连接的 vhost / queue 与你在 Web 上看的不一样。
排查要点:
- 确认 vhost:RabbitMQ 多个 vhost 相互隔离,很容易“连错房间”;
- 确认队列名:保证生产者和消费者使用的队列名完全一致;
- 确认 exchange 与 binding:尤其是在用 topic / direct / fanout 交换机时。
5. 性能问题与监控
RabbitMQ 的性能受多因素影响:
- 磁盘 IO(消息持久化时尤其明显);
- 网络延迟和带宽;
- 消费者 ack 策略(是否开启手动 ack、防止消息在未确认时大量堆积);
- prefetch(
basic.qos)设置是否合理。
排查时可以:
- 打开 Web 控制台的
Overview/Queues观察 rate; - 设置合理的 prefetch 值(比如每个消费者一次处理 50 条);
- 避免在一个 queue 上堆积海量未消费完的消息。
十二、升级、备份与回滚策略
部署好以后,不可避免要面对版本升级和灾难恢复,这里简单给一套操作习惯。
1. 升级镜像版本
前提:你已经用 docker-compose 部署,并挂载了数据卷。
步骤:
-
修改
docker-compose.yml中的镜像标签,例如从rabbitmq:3.11-management升到rabbitmq:3.13-management; -
拉取新镜像:
Terminal window docker compose pull -
重启服务:
Terminal window docker compose up -d -
观察日志和 Web 控制台,确认队列 / 用户 / 虚拟主机等都正常。
如果发现严重问题:
- 把镜像标签改回旧版本;
- 再次
docker compose up -d,数据仍然在卷里。
2. 数据备份
最简单粗暴的方式:
-
停掉服务(确保数据一致性):
Terminal window docker compose down -
打包
./data目录(对应/var/lib/rabbitmq):Terminal window tar czf rabbitmq-data-backup-$(date +%Y%m%d).tar.gz ./data -
把压缩包丢到异地存储(对象存储、另一台机器等)。
更细粒度的备份:
- 使用
rabbitmq-dump-queue等工具导出关键队列数据; - 使用集群 + 镜像队列来提升高可用性。
十三、从零到可用:RabbitMQ + Docker 部署清单
最后,把本文所有关键步骤压缩成一份 checklist,方便以后快速回顾:
- 拉镜像:
docker pull rabbitmq:3-management; - 最小试跑(验证环境):
docker run --name my-rabbitmq -p 5672:5672 -p 15672:15672 -d rabbitmq:3-management; - 确认 Web 控制台可访问:浏览器打开
http://127.0.0.1:15672,默认guest/guest登录; - 准备数据卷目录:
~/docker-data/rabbitmq/data、~/docker-data/rabbitmq/conf; - 用卷重建容器,挂载
/var/lib/rabbitmq(必选)和/etc/rabbitmq(可选); - 为生产 / 项目创建自己的用户与虚拟主机,并授权;
- 写一个
docker-compose.yml,把镜像、端口、环境变量、卷和restart: always都写进去; - 在应用中正确配置连接参数(host/port/user/pass/vhost),并使用持久化队列和消息;
- (进阶)需要高可用时,准备多节点集群并配置镜像队列策略;
- 定期备份数据卷,升级时小步慢跑,保留回滚路径。
做到这里,你就有了一套 可复用、可迁移、可调试 的 RabbitMQ Docker 部署方案。
下一次再遇到 “要不要搭一个 MQ 环境” 的需求,只需要改一改 compose 里的账号、端口和目录,就能迅速复制一整套环境出来,而不必再从零翻文档、踩坑。
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或赞助支持!