你为什么要把celery 工人和 Django 容器分开

5us2dqdw  于 2023-01-27  发布在  Go
关注(0)|答案(2)|浏览(167)

我正在用celery 构建一个django应用程序,我尝试过在没有容器的情况下编写一个docker-compose,在我的django Dockerfile中,一个运行celery 工人和django应用程序的入口点:

...
python manage.py migrate
celery -A api worker -l INFO --detach
python manage.py runserver 0.0.0.0:8000

celery 将使用这个顺序运行,但不使用djangorunserver。我在教程中看到他们将django容器与woker容器分开,反之亦然。我没有看到这种分开的解释。我还观察到两个python容器( Django ,worker)的音量是一样的,如果celery 和django的环境不一样,它怎么能添加任务呢?在我看来,django应该有两个应用程序(相同的体积)对于两个容器只有1个运行runserver,另一个运行celery worker。我不明白这种分离。

bcs8qyzn

bcs8qyzn1#

您应该将容器设置为在每个容器中只运行一个前台进程,而不运行后台进程。即使在这个简单的示例中,也有两个明显的优点:如果Celery worker失败,您可以重新启动一个独立的容器,但是它作为后台进程对Docker是不可见的;并且您可以分别读取Web服务器和后台工作线程的docker logs,而不会将它们纠缠在一起。在更大的范围内,您可以想象根据负载运行不同数量的Django和Celery容器。
要实现这一点,入口点脚本不能直接运行程序,而是要传递(可能被覆盖)容器命令作为参数,您可以使用特殊的shell构造来运行它

#!/bin/sh
./manage.py migrate
exec "$@"

在Dockerfile中,声明ENTRYPOINT和默认的CMD以运行Web服务器

ENTRYPOINT ["./entrypoint.sh"]  # probably unchanged, must be JSON array syntax
CMD ["./manage.py", "runserver", "0.0.0.0:8000"]

在Compose设置中,您可以在同一个映像上运行多个容器,但要覆盖Celery worker的command:

version: '3.8'
services:
  web:
    build: .
    ports: ['8000:8000']
    environment:
      REDIS_HOST: redis
  worker:
    build: .
    command: celery -A api worker -l INFO
    environment:
      REDIS_HOST: redis
  redis:
    image: redis

主应用程序通过Redis(或其他商店)中的队列与工作者通信,因此它们不需要在同一个容器中。

50pmv0ei

50pmv0ei2#

正如Celery文件所述:
Celery通过消息进行通信,通常使用代理在客户机和工作机之间进行调解。为了启动一个任务,客户机向队列添加一条消息,然后代理将该消息传递给工作机。
这意味着客户端(Django)和工作端(Celery)之间的通信是通过一个消息队列完成的。因此,工作端和客户端是否在不同的容器甚至不同的机器中并不重要。如果客户端可以访问消息队列(例如使用Redis或RabbitMQ),并且工作端可以从该队列中弹出任务,那么它总是可以工作的。
关于docker-compose部分,没有一个理想的标准来区分Celery和Django。你可以把它们放在同一个容器中,这取决于你和项目的要求。如果你使用两个容器,那么它们需要共享卷,因为源代码和执行任务所需的任何其他数据。

相关问题