#python #docker #celery
#python #докер #сельдерей
Вопрос:
Я пытаюсь запустить celery внутри контейнера docker, и по какой-то причине он никогда не обновляется. Всякий раз, когда я добавляю новую функцию в tasks.py
или обновляю существующую функцию, она никогда не регистрируется в celery даже после перезапуска контейнера.
Вот мой 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 amp;amp; apt-get install -y
apt-utils
nginx
supervisor
python3-pip
amp;amp; 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)
а затем перестраивает приложение заново. Ничего не помогает. Любые идеи были бы очень признательны.
Комментарии:
1. вы перестраиваете с
--no-cache
?2. @user2915097 Я получаю
unknown flag: --no-cache
3. в docs.docker.com/engine/reference/commandline/build Я вижу
--no-cache Do not use cache when building the image
4. @user2915097 мои извинения, я тоже пробовал, это не помогло
5. После запуска экземпляра docker вы можете получить доступ к оболочке контейнера с помощью command
docker exec -it myapp /bin/bash
. Затем вы можете перейти к/app
и проверить,tasks.py
обновлен ли файл или нет. Имейте в виду, что вам может потребоваться выполнитьapt
установку редактора внутри контейнера.
Ответ №1:
Я думаю, что это может быть проблемой:
@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
Причина: просто проверьте исходный код decorator 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)
Единственный принятый им неназванный аргумент — это функция, которую нужно оформить. В противном случае он вызвал бы TypeError
и был бы проглочен supervisord
, поскольку вы не настроили loglevel
на debug
.
Комментарии:
1. Привет @Philip, спасибо за совет, но это тоже не помогает.
2. @Jonathan Ну, вы получили какой-то результат, настроив уровень журнала и файл журнала?
Ответ №2:
Я не смог воспроизвести вашу проблему в своей настройке. Я создал простое приложение Flask, как в документации по сельдерею.
Можете ли вы попробовать несколько команд, чтобы перепроверить свои настройки?
Откройте оболочку в контейнере myapp (она должна быть уже запущена):
docker exec -t -i myapp /bin/bash
И затем:
cd /app
celery -A tasks.celery status
celery -A tasks.celery inspect registered
Отображается ли новая задача?
Я думаю, что у вас могут быть другие экземпляры celery, подключенные к тому же серверу redis, поэтому у вас есть 21 экземпляр. Но я предполагаю.
Вы также можете попробовать с независимым контейнером redis.
docker run --name myredis -d redis
И запустите celery в режиме отладки, с:
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
Есть ли задача сейчас? Это должно быть указано просто под сообщением о запуске Celery.
Я не думаю, что у вас проблема с вашим изображением, но вы можете дважды проверить это, изучая:
docker exec myapp /bin/bash -c "cat /app/tasks.py"
Я не думаю, что это проблема, потому что вы копируете / app в изображение, и когда вы запускаете контейнер, вы снова сопоставляете / app, используя локальный каталог. Вы запускаете контейнер из того же каталога, из которого вы создали контейнер?
-v $(pwd)/app:/app переопределит /app в контейнере с текущим каталогом ./app. Вам действительно это нужно? Без части -v у вас те же результаты?
Я надеюсь, что это поможет выяснить, что не так.
Ответ №3:
Я сделал рабочее репозиторий вашего кода. Он живет здесь.
Что я изменил:
- Опечатка двоеточия (посмотрите на свой
multiply
def) - Не вызывает декораторов
- Общая очистка кода
- Использование одного URI redis
- Некоторая навигация по каталогам в моем тесте
Я не фокусировался на частях supervisord.