Странный докер ошибка сельдерея

#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.