奇怪的docker+芹菜臭虫

我想在一个docker集装箱内运行芹菜,而且由于某种原因它永远不会更新。 每当我在tasks.py添加一个新的函数,或者更新一个已经存在的函数,即使在我重新启动容器之后,它也不会向芹菜注册。

这是我的dockerfile

 # start with a base image FROM python:3.4-slim ENV REDIS_IP 1.1.1.111 ENV REDIS_PORT 6379 ENV REDIS_DB 0 # install dependencies RUN apt-get update && apt-get install -y \ apt-utils \ nginx \ supervisor \ python3-pip \ && rm -rf /var/lib/apt/lists/* RUN echo "America/New_York" > /etc/timezone; dpkg-reconfigure -f noninteractive tzdata # update working directories ADD ./app /app ADD ./config /config ADD requirements.txt / # install dependencies RUN pip install --upgrade pip RUN pip3 install -r requirements.txt # setup config RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf RUN rm /etc/nginx/sites-enabled/default RUN ln -s /config/nginx.conf /etc/nginx/sites-enabled/ RUN ln -s /config/supervisor.conf /etc/supervisor/conf.d/ EXPOSE 80 CMD ["supervisord", "-n"] 

然后我的supervisor.conf

 [program:app] command = uwsgi --ini /config/app.ini autostart=true autorestart=true [program:nginx] command = service nginx restart autostart=true autorestart=true [program:celery] directory = /app command = celery -A tasks.celery worker -P eventlet -c 1000 autostart=true autorestart=true 

我的tasks.py

 import os from celery import Celery from app import app as flask_app def make_celery(app): celery = Celery(app.import_name, backend='redis://{0}:{1}/{2}'.format(os.environ['REDIS_IP'],os.environ['REDIS_PORT'],os.environ['REDIS_DB']), broker='redis://{0}:{1}/{2}'.format(os.environ['REDIS_IP'],os.environ['REDIS_PORT'],os.environ['REDIS_DB'])) celery.conf.update( CELERY_ENABLE_UTC=True, CELERY_TIMEZONE='America/New_York' ) TaskBase = celery.Task class ContextTask(TaskBase): abstract = True def __call__(self, *args, **kwargs): with app.app_context(): return TaskBase.__call__(self, *args, **kwargs) celery.Task = ContextTask return celery celery = make_celery(flask_app) @celery.task() def add_together(a, b): return a+ b @celery.task() def multiply(a,b) return a*b 

出于某种原因:

  • 我有21名工人登记和multiply从未获得登记,
  • 当我对add_together进行更改时,即使在重新启动容器时也不会进行注册。

在这里输入图像说明

我开始我的容器:

 docker build --rm -t myapp . docker run -d -p 88:80 -v $(pwd)/app:/app --name=myapp myapp 

并重新启动:

 docker restart myapp 

我也试过了

 docker stop $(docker ps -a -q) docker rm $(docker ps -a -q) 

然后再重新构build应用程序。 没什么帮助。 任何想法将非常赞赏。

我认为这可能是问题:

 @celery.task() # <-- you shouldn't call this decorator directly def add_together(a, b): return a+ b 

尝试将其更改为:

 @celery.task def add_together(a, b): return a+ b 

原因:只需检查装饰器task的源代码 :

 def task(self, *args, **opts): """Creates new task class from any callable.""" # ... handling named options if len(args) == 1: if callable(args[0]): return inner_create_task_cls(**opts)(*args) raise TypeError('argument 1 to @task() must be a callable') if args: raise TypeError( '@task() takes exactly 1 argument ({0} given)'.format( sum([len(args), len(opts)]))) return inner_create_task_cls(**opts) 

它接受的唯一未命名的参数是要装饰的function。 否则会引发TypeError并被supervisord吞下,因为您没有configurationloglevel进行debug

我无法在我的设置上重现您的问题。 我在Celery文档中创build了一个简单的Flask应用程序。

你可以尝试几个命令来仔细检查你的设置?

打开一个shell到myapp容器(它必须已经在运行):

 docker exec -t -i myapp /bin/bash 

接着:

 cd /app celery -A tasks.celery status celery -A tasks.celery inspect registered 

新任务出现了吗?

我想你可能有其他芹菜实例连接到同一个redis服务器,这就是为什么你有21个实例。 但我猜测。

你也可以尝试一个独立的redis容器。

 docker run --name myredis -d redis 

并在debugging模式下执行芹菜,其中:

 docker run --rm -t -i -v $(pwd)/app:/app -e REDIS_IP=myredis -u nobody -w /app --link myredis myapp celery -A tasks.celery worker -P eventlet -c 1000 -l debug 

那里的任务呢? 它应该是刚刚列出的芹菜启动旗帜消息。

我不认为你的形象有问题,但你可以仔细检查,看看:

 docker exec myapp /bin/bash -c "cat /app/tasks.py" 

我不认为这是问题,因为您复制/应用程序到图像中,当您运行容器时,您使用本地目录再次映射/应用程序。 你是从你build造容器的目录运行容器吗?

-v $(pwd)/ app:/ app将覆盖当前目录./app的容器中的/ app。 你真的需要这个吗? 没有-v部分,你有相同的结果吗?

我希望能帮助弄清楚什么是错的。

我做了一个工作回购你的代码。 它住在这里 。

我改变的事情:

  • 冒号错字(看你的multiply def)
  • 不要调用装饰器
  • 通用代码清理
  • 使用单个redis URI
  • 在我的testing中的一些目录导航

我没有专注于supervisord部分。