芹菜多里面码头工人容器

时间:2018-02-06 15:42:11

标签: python docker docker-compose celery

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

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

但我明白了......

$btn-focus-width: 0;

我的芹菜容器关闭了。怎么不让他靠近并从他那里得到他的原木?

UPD:Celery多创建后台进程。如何在前景中启动芹菜?

3 个答案:

答案 0 :(得分:5)

我做了这个任务。我用supervisord代替芹菜多。 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

答案 1 :(得分:1)

首先,我不明白使用multi& amp;泊坞窗。 在我看来,你希望每个工人都在一个单独的容器中。这样你就拥有了灵活性和微服务环境。

如果您仍希望在同一容器中拥有多个工作线程,我可以通过在命令末尾添加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

答案 2 :(得分:1)

根据您的应用程序需求和设计,您实际上可能希望将工作器分隔在不同的容器中以完成不同的任务。

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

编辑2019-12-05 :运行了一段时间后。这不是用于生产的好主意。 2个警告:

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

  2. 在启动和停止容器(但未将其删除)时,docker容器状态将保持不变。这意味着,如果您的芹菜工人确实依靠pidfile进行识别,而又出现了不正常的关机,则有可能会保留该pidfile,并且工人即使在遇到问题的情况下,也不会干净地重启docker stop; docker start。这是由于celery启动从先前的不正常关闭中检测到剩余的PIDfile的存在。为了防止出现多个实例,重新启动的工作程序会以“找到PIDfile,芹菜已经在运行吗?”的方式停止运行。必须使用docker rmdocker-compose down; docker-compose up删除整个容器。处理此问题的几种方法:

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

    b。。也许在--pidfilecelery multi命令中不包含celery worker参数会更好。

摘要建议:最好使用supervisord

现在,进入详细信息:

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

此外,芹菜工人可能会运行长时间运行的任务,并且需要响应gracefully shutdown的docker shutdown(SIGTERM)信号,即在关闭或重新启动之前完成长时间运行的任务。

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

中进行声明

此外,由于celery multi在后台运行,因此docker无法看到任何日志。您需要能够在前台显示日志,以使docker logs能够看到正在发生的事情。为此,我们将为celery多工作人员设置日志文件,并使用tail -f <logfile_pattern>在控制台前景中显示以无限期运行。

我们需要实现三个目标:

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

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

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

对于#3,我们将在启动期间在celery multi stop <number_of_workers_in_start_command>中运行celery multi start和其他参数参数。

这是我写的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"]

芹菜工人然后可以在docker容器中运行,也可以正常停止。