芹菜多在码头工人容器

dlu*_*biu 3 python celery docker docker-compose

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

celery worker -c 3 -Q queue1
celery worker -c 7 -Q queue2,queue3
Run Code Online (Sandbox Code Playgroud)

但我不在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'
Run Code Online (Sandbox Code Playgroud)

但是我明白了...

app__celery_1  |    > celery1@1ab37081acb9: OK
app__celery_1  |    > celery2@1ab37081acb9: OK
app__celery_1 exited with code 0
Run Code Online (Sandbox Code Playgroud)

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

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

VKe*_*Ken 8

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

但是,如果资源使用率低,并且在单个容器中组合多个工作人员是有意义的,则可以通过入口点脚本来完成。

编辑 2019-12-05:运行一段时间后。对于生产用途来说,这不是一个好主意。2个注意事项:

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

  2. 随着容器的启动和停止(但未删除),docker 容器状态将保持不变。这意味着,如果你的芹菜工人不依赖于一个pidfile进程文件进行识别,并且尚未有非正常关机,有一个机会,pidfile进程文件保持,而工人将不会正常启动甚至用docker stop; docker start。这是因为 celery 启动检测到上次不正常关闭的剩余 PID 文件的存在。为了防止多个实例,重新启动的 worker 会用“找到 PIDfile,celery 已经在运行?”来停止自己。必须使用docker rm, 或删除整个容器docker-compose down; docker-compose up。处理这种情况的几种方法:

    一种。一旦容器停止,容器必须run带有--rm标记以移除容器。

    也许--pidfilecelery multiorcelery worker命令中不包含参数会更好。

总结建议:使用supervisord.

现在,进入细节:

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

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

为了实现docker信号的传播和处理,最好entrypoint在docker的exec形式的dockerfile中声明,也可以在docker-composefile中进行

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

我们需要实现三个目标:

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

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

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

对于 #3,我们将celery multi stop <number_of_workers_in_start_command>celery multi start.

这是我写的要点,复制到这里:

#!/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"
Run Code Online (Sandbox Code Playgroud)

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

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

ENTRYPOINT ["entrypoint_file"]
Run Code Online (Sandbox Code Playgroud)

然后 celery 工作人员可以在 docker 容器中运行,也可以优雅地停止。


dlu*_*biu 5

我是这样做的。我用主管代替芹菜多。Supervisord在前台启动,并且我的容器未关闭。

command: supervisord -c supervisord.conf
Run Code Online (Sandbox Code Playgroud)

我将所有队列添加到supervisor.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
Run Code Online (Sandbox Code Playgroud)