Задачи Celery не выполняются в docker-compose
У меня есть docker-compose, в котором есть три компонента: app, celery и redis. Они реализованы в DjangoRest.
Я видел этот вопрос несколько раз на stackoverflow и попробовал все перечисленные решения. Однако задача celery не запускается.
Поведение, которое имеет celery, такое же, как и у приложения, то есть он запускает проект django, но не запускает задачу.
docker-compose.yml
version: "3.8"
services:
app:
build: .
volumes:
- .:/django
ports:
- 8000:8000
image: app:django
container_name: myapp
command: python manage.py runserver 0.0.0.0:8000
depends_on:
- redis
redis:
image: redis:alpine
container_name: redis
ports:
- 6379:6379
volumes:
- ./redis/data:/data
restart: always
environment:
- REDIS_PASSWORD=
healthcheck:
test: redis-cli ping
interval: 1s
timeout: 3s
retries: 30
celery:
image: celery:3.1
container_name: celery
restart: unless-stopped
build:
context: .
dockerfile: Dockerfile
command: celery -A myapp worker -l INFO -c 8
volumes:
- .:/django
depends_on:
- redis
- app
links:
- redis
DockerFile
FROM python:3.9
RUN useradd --create-home --shell /bin/bash django
USER django
ENV DockerHOME=/home/django
RUN mkdir -p $DockerHOME
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
ENV PIP_DISABLE_PIP_VERSION_CHECK 1
USER root
RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -
RUN sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list'
RUN apt-get -y update
RUN apt-get install -y google-chrome-stable
USER django
WORKDIR /home/django
COPY requirements.txt ./
# set path
ENV PATH=/home/django/.local/bin:$PATH
# Upgrade pip and install requirements.txt
RUN pip install --upgrade pip
RUN pip install -r requirements.txt
COPY . .
EXPOSE 8000
# entrypoint
ENTRYPOINT ["/bin/bash", "-e", "docker-entrypoint.sh"]
docker-entrypoint.sh
# run migration first
python manage.py migrate
# create test dev user and test superuser
echo 'import create_test_users' | python manage.py shell
# start the server
python manage.py runserver 0.0.0.0:8000
celery.py
from __future__ import absolute_import
import os
from celery import Celery
from django.conf import settings
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myapp.settings')
app = Celery('myapp', broker='redis://redis:6379')
app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
@app.task(bind=True)
def debug_task(self):
print('Request: {0!r}'.format(self.request))
settings.py
CELERY_BROKER_URL = os.getenv('REDIS_URL') # "redis://redis:6379"
CELERY_RESULT_BACKEND = os.getenv('REDIS_URL') # ""redis://redis:6379"
CELERY_ACCEPT_CONTENT = ['application/json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_TIMEZONE = 'Africa/Nairobi'
Ваш docker-entrypoint.sh
скрипт безоговорочно запускает сервер Django. Поскольку вы объявляете его как ENTRYPOINT
изображение, Compose command:
передается ему в качестве аргументов , но ваш скрипт игнорирует их.
Лучший способ исправить это - передать конкретную команду - "запустить сервер Django", "запустить Celery worker" - как Dockerfile CMD
или Compose command:
. Сценарий точки входа заканчивается командой оболочки exec "$@"
для выполнения этой команды.
#!/bin/sh
python manage.py migrate
echo 'import create_test_users' | python manage.py shell
# run the container CMD
exec "$@"
В вашем Dockerfile необходимо объявить значение по умолчанию CMD
.
ENTRYPOINT ["./docker-entrypoint.sh"]
CMD python manage.py runserver 0.0.0.0:8000
Теперь в настройках Compose, если вы не укажете command:
, будет использована команда по умолчанию CMD
, а если укажете, то она будет запущена вместо нее. В обоих случаях будет запущен ваш сценарий точки входа, но когда он дойдет до последней строки exec "$@"
, он выполнит предоставленную команду.
Это означает, что вы можете удалить переопределение command:
из вашего контейнера app
. (Вы должны оставить его для контейнера Celery.) Вы можете упростить эту настройку, удалив параметры image:
и container_name:
(Compose выберет разумные значения по умолчанию для обоих) и крепление volumes:
, которое скрывает содержимое изображения.