Trabajador de apio corriendo + batido en el mismo contenedor

Trabajador de apio corriendo + batido en el mismo contenedor

La aplicación My Flas consta de cuatro contenedores: aplicación web, postgres, rabbitMQ y Celery. Como tengo tareas de apio que se ejecutan periódicamente, estoy usando celery beat. He configurado mi archivo docker-compose así:

version: '2'
services:
  rabbit:
    # ...      
  web:
    # ...
  rabbit:
    # ...
  celery:
    build:
        context: .
        dockerfile: Dockerfile.celery

Y mi Dockerfile.celery se ve así:

# ...code up here...
CMD ["celery", "-A", "app.tasks.celery", "worker", "-B", "-l", "INFO"]

Aunque leí en los documentos que no debería ir a producción con la opción -B, la agregué rápidamente de todos modos (y me olvidé de cambiarla) y rápidamente me di cuenta de que mis tareas programadas se ejecutaban en múltiples veces. Para aquellos interesados, si hace un ps aux | grep celery desde dentro de su contenedor de apio, verá varios procesos de apio + ritmo en ejecución (pero solo debe haber un proceso de ritmo y tantos procesos de trabajo). No estaba seguro de los documentos por qué no deberías ejecutar -B en producción, pero ahora lo sé.

Entonces cambié mi Dockerfile.celery a:

# ...code up here...
CMD ["celery", "-A", "app.tasks.celery", "worker", "-l", "INFO"]
CMD ["celery", "-A", "app.tasks.celery", "beat", "-l", "INFO"]

No, cuando inicio mi aplicación, los procesos de trabajo se inician pero Beat no. Cuando invierto esos comandos para que el ritmo se llame primero, luego se inicia el ritmo pero los procesos de trabajo no. Entonces mi pregunta es: ¿cómo ejecuto celery worker + beat juntos en mi contenedor? He revisado muchos artículos/documentos, pero aún no puedo resolver esto.

EDITADO

Cambié mi Dockerfile.celery a lo siguiente:

ENTRYPOINT [ "/bin/sh" ]
CMD [ "./docker.celery.sh" ]    

Y mi archivo docker.celery.sh se ve así:

#!/bin/sh -ex
celery -A app.tasks.celery beat -l debug &
celery -A app.tasks.celery worker -l info &

Sin embargo, recibo el error celery_1 exited with code 0

Editar #2

Agregué el siguiente comando de bloqueo al final de mi archivo docker.celery.sh y todo se solucionó:

tail -f /dev/null
Mostrar la mejor respuesta

puede crear otro contenedor solo para el tiempo y anular su comando de trabajo... cuando escale a sus trabajadores, los escalará solo a ellos y no al tiempo (programador) también

@MazelTov: buena sugerencia y para mi próximo proyecto consideraré colocarlos en contenedores separados. Por varias razones, necesitaba que ambos procesos se ejecutaran en el mismo contenedor.

docker ejecuta solo un CMD, por lo que solo se ejecuta el primer CMD, la solución alternativa es crear un script bash que ejecute tanto el trabajador como el beat y use el docker CMD para ejecutar este script

gracias por la respuesta pero, lamentablemente, no me funciona. Usando su sugerencia, encuentro el mismo problema: es decir, en mi Dockerfile.celery estoy ejecutando ENTRYPOINT [ "/ bin/sh" ] seguido de CMD [ "./docker.celery.sh" ]. El script de shell tiene dos comandos: celery -A app.tasks.celery beat -l debug seguido de celery -A app.tasks.celery worker -l info. Al igual que antes, el primer comando se ejecuta pero el segundo no. ¿Estoy haciendo algo mal?

¿La primera línea termina con &, lo que significa que se ejecuta en segundo plano y continúa con la siguiente línea (también la segunda línea debe terminar con & para el uso de mejores prácticas)

Agregué & al final de cada comando, pero al iniciar mi contenedor aparece el siguiente error celery_1 exited with code 0. He agregado mi script de shell a mi publicación original. ¿Cualquier otra sugerencia?

parece que el contenedor está ejecutando todos los servicios y que existe, intente agregar un cmd de bloqueo al final del script bash, algo como tailf algún archivo o algo así

sus sugerencias han sido útiles. ¡Todo funciona ahora! Queda un pequeño problema de limpieza, es decir: hice un tail -f blank.log donde el archivo blank.log solo contiene un comentario y nada más. Cuando se ejecuta el comando, mi consola se queja con tail: unrecognized file system type 0x794c7630 for ‘blank.log'. No es un gran problema ya que todo funciona, pero sería bueno corregir el error. ¿Alguna sugerencia?

FYI: arreglé el último error que estaba recibiendo con tail -f /dev/null.

Creo que este enfoque funciona, pero no lo recomendaría. está perdiendo la producción de celery beat y no sabrá lo que sucede dentro del contenedor porque arroja el cierre de sesión

@MazelTov tiene razón, la mejor práctica es agregar la salida de apio a algún archivo de registro (la mejor práctica para hacer que este archivo de registro persista en el host)

todo lo que se imprime en STDOUT en el contenedor docker es un registro :-), creo que es mejor con la opción -B al ejecutar el trabajador

La otra opción es usar algo como dumb-init.

@hugo Necesitaba hacer lo mismo que tú, y tu última edición me lo resolvió rápidamente. celery -A app.tasks.celery beat -l debug & celery -A app.tasks.celery worker -l info & tail -f /dev/null Tal vez debería agregarse como respuesta.

Puedes usar celery beatX para el ritmo. Está permitido (y recomendado) tener varias instancias de beatX. Usan candados para sincronizar.

No puedo decir si está listo para la producción, pero me funciona de maravilla (con la tecla -B)

Celery beatX se ve interesante. Sin embargo, actualmente parece que solo funciona con Redis y Memcached. Estoy usando RabbitMQ y preferiría no agregar más tecnología a mi pila. Pero es bueno saber sobre esto, así que gracias por la sugerencia.

Lo obtuve poniendo el punto de entrada como se explicó anteriormente, además agregué &> para tener la salida en un archivo de registro.

mi punto de entrada.sh

#!/bin/bash
python3 manage.py migrate

python3 manage.py migrate catalog --database=catalog

python manage.py collectstatic --clear --noinput --verbosity 0


# Start Celery Workers
celery worker --workdir /app --app dri -l info &> /log/celery.log  &

# Start Celery Beat
celery worker --workdir /app --app dri -l info --beat &> /log/celery_beat.log  &

python3 manage.py runserver 0.0.0.0:8000

Partiendo del mismo concepto que @shahaf ha resaltado resolví a partir de esta otra solución usando bash -c de esta manera:

command: bash -c "celery -A app.tasks.celery beat & celery -A app.tasks.celery worker --loglevel=debug"