奇怪的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部分。