【问题标题】:Celery multi inside docker container码头集装箱内的芹菜多
【发布时间】:2018-02-06 15:42:11
【问题描述】:

我在 docker 容器中有带有芹菜的 python 应用程序。我想要几个不同队列的工人。 例如:

celery worker -c 3 -Q queue1
celery worker -c 7 -Q queue2,queue3

但我不会在 docker compose 中这样做。我发现了芹菜多。我试过用它。

version: '3.2'
services:
  app:
    image: "app"
    build:
      context: .
    networks:
      - net
    ports:
      - 5004:5000
    stdin_open: true
    tty: true
    environment:
      FLASK_APP: app/app.py
      FLASK_DEBUG: 1
    volumes:
      - .:/home/app
  app__celery:
    image: "app"
    build:
      context: .
    command: sh -c 'celery multi start 2 -l INFO -c:1 3 -c:2 7 -Q:1 queue1 -Q:2 queue2,queue3'

但我明白了……

app__celery_1  |    > celery1@1ab37081acb9: OK
app__celery_1  |    > celery2@1ab37081acb9: OK
app__celery_1 exited with code 0

我的装有芹菜的容器关闭了。如何不让他关闭并从他那里获取日志?

UPD:Celery 多创建后台进程。如何在前台启动 celery multi?

【问题讨论】:

    标签: python docker docker-compose celery


    【解决方案1】:

    我就是这样做的。我用supervisord代替了celery multi。 Supervisord 在前台启动,我的容器没有关闭。

    command: supervisord -c supervisord.conf
    

    我将所有队列添加到 supervisord.con

    [program:celery]
    command = celery worker -A app.celery.celery -l INFO -c 3 -Q q1
    directory = %(here)s
    startsecs = 5
    autostart = true
    autorestart = true
    stopwaitsecs = 300
    stderr_logfile = /dev/stderr
    stderr_logfile_maxbytes = 0
    stdout_logfile = /dev/stdout
    stdout_logfile_maxbytes = 0
    
    [program:beat]
    command = celery -A app.celery.celery beat -l INFO --pidfile=/tmp/beat.pid
    directory = %(here)s
    startsecs = 5
    autostart = true
    autorestart = true
    stopwaitsecs = 300
    stderr_logfile = /dev/stderr
    stderr_logfile_maxbytes = 0
    stdout_logfile = /dev/stdout
    stdout_logfile_maxbytes = 0
    
    [supervisord]
    loglevel = info
    nodaemon = true
    pidfile = /tmp/supervisord.pid
    logfile = /dev/null
    logfile_maxbytes = 0
    

    【讨论】:

      【解决方案2】:

      根据您的应用程序需求和设计,您实际上可能希望将不同容器中的工作人员分开以执行不同的任务。

      但是,如果资源使用率较低并且将多个工作器组合在一个容器中是有意义的,则可以通过入口点脚本来实现。

      Edit 2019-12-05:运行一段时间后。对于生产用途来说,这不是一个好主意。 2 个警告:

      1. 存在后台工作人员静默退出但未在前台捕获的风险。 tail -f 将继续运行,但 docker 不会知道后台工作人员已停止。根据您的 celery 调试级别设置,日志可能会显示一些指示,但是当您执行 docker ps 时,docker 不知道。为了可靠,工人需要在失败时重新启动,这给我们带来了使用supervisord的建议。

      2. 随着容器的启动和停止(但未删除),docker 容器状态将保持不变。这意味着,如果您的 celery worker 确实依赖 pidfile 进行识别,但存在不正常的关闭,则 pidfile 有可能被保留,并且 worker 不会干净地重新启动,即使使用docker stop; docker start。这是由于 celery 启动检测到之前不干净关闭的剩余 PIDfile 的存在。为了防止出现多个实例,重新启动的工作人员会通过“找到 PIDfile,celery 已经在运行?”来停止自己。必须使用docker rmdocker-compose down; docker-compose up 删除整个容器。几种处理方法:

        a.容器必须是 run 并带有 --rm 标志才能在容器停止后删除容器。

        b.也许在celery multicelery worker 命令中不包括--pidfile 参数会更好。

      总结建议:使用supervisord 可能会更好。

      现在,进入细节:

      Docker 容器需要一个前台任务才能运行,否则容器将退出。这将进一步解决。

      此外,celery worker 可能会运行长时间运行的任务,需要响应 docker 的关闭 (SIGTERM) 信号到gracefully shutdown,即在关闭或重启之前完成长时间运行的任务。

      要实现docker信号的传播和处理,最好在docker的exec form的dockerfile中声明entrypoint,你也可以在docker-compose file中这样做

      另外,由于 celery multi 在后台工作,docker 看不到任何日志。您需要能够在前台显示日志,让docker logs 能够看到正在发生的事情。我们将通过为 celery 多工作程序设置日志文件并在控制台前台显示 tail -f <logfile_pattern> 来无限期运行。

      我们需要实现三个目标:

      1. 使用前台任务运行 docker 容器
      2. 接收、trap 并处理 docker 关闭信号
      3. 优雅地关闭工作器

      对于#1,我们将运行tail -f &,然后运行wait作为前台任务。

      对于#2,这是通过设置trap 函数并捕获信号来实现的。要使用 trap 函数接收和处理信号,wait 必须是正在运行的前台任务,在 #1 中实现。

      对于#3,我们将在celery multi start的启动过程中运行celery multi stop <number_of_workers_in_start_command>和其他自变量参数。

      这是我写的gist,复制到这里:

      #!/bin/sh
      
      # safety switch, exit script if there's error. Full command of shortcut `set -e`
      set -o errexit
      # safety switch, uninitialized variables will stop script. Full command of shortcut `set -u`
      set -o nounset
      
      # tear down function
      teardown()
      {
          echo " Signal caught..."
          echo "Stopping celery multi gracefully..."
      
          # send shutdown signal to celery workser via `celery multi`
          # command must mirror some of `celery multi start` arguments
          celery -A config.celery_app multi stop 3 --pidfile=./celery-%n.pid --logfile=./celery-%n%I.log
      
          echo "Stopped celery multi..."
          echo "Stopping last waited process"
          kill -s TERM "$child" 2> /dev/null
          echo "Stopped last waited process. Exiting..."
          exit 1
      }
      
      # start 3 celery worker via `celery multi` with declared logfile for `tail -f`
      celery -A config.celery_app multi start 3 -l INFO -Q:1 queue1 -Q:2 queue1 -Q:3 queue3,celery -c:1-2 1 \
          --pidfile=./celery-%n.pid \
          --logfile=./celery-%n%I.log
      
      # start trapping signals (docker sends `SIGTERM` for shudown)
      trap teardown SIGINT SIGTERM
      
      # tail all the logs continuously to console for `docker logs` to see
      tail -f ./celery*.log &
      
      # capture process id of `tail` for tear down
      child=$!
      
      # waits for `tail -f` indefinitely and allows external signals,
      # including docker stop signals, to be captured by `trap`
      wait "$child"
      

      使用上面的代码作为入口点脚本文件的内容,并根据需要进行相应的修改。

      在dockerfile或docker-compose文件中以exec形式声明:

      ENTRYPOINT ["entrypoint_file"]
      

      celery worker 之后可以在 docker 容器中运行,也可以优雅地停止。

      【讨论】:

        【解决方案3】:

        首先,我不明白使用 multi & docker 的好处。 正如我所看到的,您希望每个工人都在一个单独的容器中。这样您就拥有了灵活性和微服务环境。

        如果您仍然希望在同一个容器中拥有多个工作人员,我可以建议通过在命令末尾添加 while true; do sleep 2; done 来保持容器打开的解决方法: celery multi start 2 -l INFO -c:1 3 -c:2 7 -Q:1 queue1 -Q:2 queue2,queue3 && while true; do sleep 2; done.

        或者,将其包装在一个简短的脚本中:

        #!/bin/bash
        celery multi start 2 -l INFO -c:1 3 -c:2 7 -Q:1 queue1 -Q:2 queue2,queue3
        while true; do sleep 2; done
        

        【讨论】:

        • 我想启动 celery 并将日志记录到一个容器中的所有队列中。不同的队列,调度工作人员等。您的回答将有助于启动容器。它没有关闭。但我没有得到日志。所以我选择了主管
        • 如果您使用 docker-compose 运行,您会在一个地方看到所有日志,这还不够吗?当您扩展到多台机器时,您也不会在主管中同时看到日志,对吧?
        • Celery multi work only 背景。 while true; do sleep 2; done 将允许容器工作。但是如果工人没有响应,那么容器不会下降并重新启动。在 supervisord 中重新启动工作人员不会 dockerway。但它有效)而且我还没有准备好使用多台机器
        • 您可以检查循环中的 celery 进程。
        猜你喜欢
        • 1970-01-01
        • 2019-01-05
        • 2018-01-20
        • 2020-06-14
        • 1970-01-01
        • 2019-07-26
        • 1970-01-01
        • 1970-01-01
        • 2021-05-14
        相关资源
        最近更新 更多