You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker运行RabbitMQ时Celery报Connection refused连接拒绝错误

问题现象

测试将长耗时任务投递至Celery worker处理队列的API,使用Docker容器部署的RabbitMQ作为消息队列,发送消息时抛出报错:
Error: [Errno 111] Connection refused

复现步骤
  • 启动RabbitMQ容器:docker run -d -p 5672:5672 rabbitmq
  • 启动Celery服务:celery -A celery worker --loglevel=INFO
  • 构建FastAPI镜像:docker build -t fastapi .
  • 运行FastAPI容器:docker run -it -p 8000:8000 fastapi
相关配置文件内容

Dockerfile

FROM python:3.9

WORKDIR /

COPY . .

RUN pip install --no-cache-dir --upgrade -r ./requirements.txt

EXPOSE 8000

CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]

requirements.txt

anyio==3.6.1
asgiref==3.5.2
celery==5.2.7
click==8.1.3
colorama==0.4.4
fastapi==0.78.0
h11==0.13.0
httptools==0.4.0
idna==3.3
pydantic==1.9.1
python-dotenv==0.20.0
PyYAML==6.0
sniffio==1.2.0
starlette==0.19.1
typing_extensions==4.2.0
uvicorn==0.17.6
watchgod==0.8.2
websockets==10.3

app.py

from fastapi import FastAPI
import tasks

@app.get("/{num}")
async def root(num):
  tasks.update_db.delay(num)
  return {"success": True}

tasks.py

from celery import Celery
import time

celery = Celery('tasks', broker='amqp://')

@celery.task(name='update_db')
def update_db(num: int) -> None:
  time.sleep(30)
  return
故障原因

连接拒绝的核心诱因是Docker默认网络隔离规则,叠加两处配置错误:

  1. tasks.py中配置的broker地址为amqp://,该地址默认解析为localhost:5672。FastAPI运行在独立Docker容器中,容器内的localhost指向容器自身的网络命名空间,既不代表宿主机,也不代表RabbitMQ所在容器,自然无法访问到RabbitMQ的5672端口。
  2. Celery启动命令参数错误:celery -A celery worker指定的应用入口为celery模块,但实际代码中Celery实例定义在tasks.py中,worker根本加载不到正确的broker配置和任务定义,就算网络通也无法正常消费任务。
  3. 官方默认RabbitMQ镜像启动后需要10-30秒完成插件加载、端口绑定初始化流程,刚执行完run命令立刻发起连接,也会因为端口还没开始监听触发连接拒绝。
排查解决步骤

按以下顺序操作即可修复问题:

  • 先创建Docker自定义桥接网络,避免默认网络的DNS解析、访问限制问题:
    docker network create celery-net
  • 启动RabbitMQ容器时指定固定容器名、加入自定义网络,启动后等待初始化完成:
    docker run -d --name rabbitmq --network celery-net -p 5672:5672 rabbitmq
    执行完命令后等待20-30秒,执行docker logs rabbitmq查看到Server startup complete字样的日志,说明RabbitMQ已经完成初始化,5672端口正常监听。
  • 修改tasks.py中的Celery broker配置,用RabbitMQ的容器名作为连接地址(同一自定义网络下Docker内置DNS会自动把容器名解析到对应容器IP):
from celery import Celery
import time

# 默认RabbitMQ的账号密码是guest/guest,地址直接写容器名rabbitmq
celery = Celery('tasks', broker='amqp://guest:guest@rabbitmq:5672//')

@celery.task(name='update_db')
def update_db(num: int) -> None:
  time.sleep(30)
  return
  • 修正Celery启动参数,指定正确的应用实例路径:如果Celery worker跑在宿主机上,需要单独把broker地址改成amqp://guest:guest@127.0.0.1:5672//(宿主机可以直接访问映射到本地的5672端口),启动命令改为celery -A tasks.celery worker --loglevel=INFO;如果Celery也容器化部署,直接把Celery容器加入celery-net网络,用上面的容器名broker配置即可。
  • 重新构建FastAPI镜像后,启动容器时加入自定义网络:
    docker run -it --network celery-net -p 8000:8000 fastapi

避坑提示:不要在FastAPI容器内用localhost/127.0.0.1尝试连接RabbitMQ,容器网络隔离下这个地址永远指向FastAPI容器自身,不可能连通。如果不想用自定义网络,需要通过宿主机中转连接,Windows/Mac环境可以用host.docker.internal作为宿主机访问地址,Linux环境启动容器时额外加--add-host=host.docker.internal:host-gateway参数,再把broker地址对应修改即可,该方案稳定性弱于自定义网络方案,优先选前者。

内容的提问来源于stack exchange,提问作者JSON_Derulo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 00:12:29