library hub compose docker cron containers sh

docker - hub - ¿Cómo ejecutar un trabajo cron dentro de un contenedor acoplable?



docker-compose (15)

Estoy tratando de ejecutar un cronjob dentro de un contenedor docker que invoca un script de shell.

Ayer estuve buscando en toda la web y el desbordamiento de pila, pero realmente no pude encontrar una solución que funcione.
¿Cómo puedo hacer esto?

EDITAR:

He creado un repositorio github (comentado) con un contenedor cron de Docker que funciona que invoca un script de shell en un intervalo determinado.


Al ejecutar algunas imágenes recortadas que restringen el acceso de root, tuve que agregar mi usuario a los sudoers y ejecutar como sudo cron

FROM node:8.6.0 RUN apt-get update && apt-get install -y cron sudo COPY crontab /etc/cron.d/my-cron RUN chmod 0644 /etc/cron.d/my-cron RUN touch /var/log/cron.log # Allow node user to start cron daemon with sudo RUN echo ''node ALL=NOPASSWD: /usr/sbin/cron'' >>/etc/sudoers ENTRYPOINT sudo cron && tail -f /var/log/cron.log

Tal vez eso ayude a alguien


Aunque esto tiene como objetivo ejecutar trabajos junto a un proceso en ejecución en un contenedor a través de la interfaz exec de Docker, esto puede ser de su interés.

He escrito un demonio que observa contenedores y programa trabajos, definidos en sus metadatos, en ellos. Ejemplo:

version: ''2'' services: wordpress: image: wordpress mysql: image: mariadb volumes: - ./database_dumps:/dumps labels: deck-chores.dump.command: sh -c "mysqldump --all-databases > /dumps/dump-$$(date -Idate)" deck-chores.dump.interval: daily

''Clásico'', la configuración de tipo cron también es posible.

Aquí están los docs , aquí está el repositorio de imágenes .


Creé una imagen de Docker basada en las otras respuestas, que se puede usar como

docker run -v "/path/to/cron:/etc/cron.d/crontab" gaafar/cron

where /path/to/cron : ruta absoluta al archivo crontab, o puede usarlo como base en un Dockerfile:

FROM gaafar/cron # COPY crontab file in the cron directory COPY crontab /etc/cron.d/crontab # Add your commands here

Como referencia, la imagen está aquí .


Cuando implemente su contenedor en otro host, tenga en cuenta que no iniciará ningún proceso automáticamente. Debe asegurarse de que el servicio ''cron'' se esté ejecutando dentro de su contenedor. En nuestro caso, estoy usando Supervisord con otros servicios para iniciar el servicio cron.

[program:misc] command=/etc/init.d/cron restart user=root autostart=true autorestart=true stderr_logfile=/var/log/misc-cron.err.log stdout_logfile=/var/log/misc-cron.out.log priority=998


Defina el cronjob en un contenedor dedicado que ejecuta el comando a través de docker exec a su servicio.

Esto es una mayor cohesión y el script en ejecución tendrá acceso a las variables de entorno que haya definido para su servicio.

#docker-compose.yml version: "3.3" services: myservice: environment: MSG: i''m being cronjobbed, every minute! image: alpine container_name: myservice command: tail -f /dev/null cronjobber: image: docker:edge volumes: - /var/run/docker.sock:/var/run/docker.sock container_name: cronjobber command: > sh -c " echo ''* * * * * docker exec myservice printenv | grep MSG'' > /etc/crontabs/root && crond -f"


Entonces, mi problema era el mismo. La solución fue cambiar la sección de comandos en docker-compose.yml .

De

comando: crontab / etc / crontab && tail -f / etc / crontab

A

comando: crontab / etc / crontab

comando: tail -f / etc / crontab

El problema era el ''&&'' entre los comandos. Después de eliminar esto, todo estuvo bien.


Hay otra forma de hacerlo, es usar Tasker , un corredor de tareas que tiene soporte cron (un planificador).

Por qué ? A veces, para ejecutar un trabajo cron, debe mezclar su imagen base (python, java, nodejs, ruby) con el crond. Eso significa otra imagen para mantener. Tasker evita eso desacoplando el crond y tu contenedor. Puede enfocarse en la imagen que desea ejecutar sus comandos y configurar Tasker para usarla.

Aquí un archivo docker-compose.yml , que ejecutará algunas tareas por usted

version: "2" services: tasker: image: strm/tasker volumes: - "/var/run/docker.sock:/var/run/docker.sock" environment: configuration: | logging: level: ROOT: WARN org.springframework.web: WARN sh.strm: DEBUG schedule: - every: minute task: hello - every: minute task: helloFromPython - every: minute task: helloFromNode tasks: docker: - name: hello image: debian:jessie script: - echo Hello world from Tasker - name: helloFromPython image: python:3-slim script: - python -c ''print("Hello world from python")'' - name: helloFromNode image: node:8 script: - node -e ''console.log("Hello from node")''

Hay 3 tareas allí, todas se ejecutarán cada minuto ( every: minute ), y cada una de ellas ejecutará el código del script , dentro de la imagen definida en la sección de image .

Simplemente ejecute docker-compose up y vea que funciona. Aquí está el repositorio de Tasker con la documentación completa:

Tasker


Intente usar una gema mecánica para programar tareas. Siga los pasos provistos en este enlace.

http://fuzzyblog.io/blog/rails/2017/05/11/adding-cron-to-a-dockerized-rails-application-using-clockwork.html

Puede llamar a la tarea de rastrillo dentro del archivo lib / clock.rb como se muestra a continuación.

every(1.day, ''Import large data from csv files'', :at => ''5:00'') do |job| `rake ''portal:import_data_from_csv''` end

Cree un contenedor separado en el archivo docker-compose y ejecute el siguiente comando dentro del contenedor.

command: bundle exec clockwork lib/clock.rb


La forma más sólida que encontré hasta ahora es ejecutar un contenedor cron independiente: instale el cliente de Docker y monte el Docker Sock para que pueda hablar con el servidor de Docker en el host.

Luego, solo use env vars para cada trabajo cron y un script de punto de entrada para generar / etc / crontab

Aquí hay una imagen que creé usando este principio y usándola en producción durante los últimos 3-4 años.

https://www.vip-consult.solutions/post/better-docker-cron#content


La solución adoptada puede ser peligrosa en un entorno de producción .

En Docker, solo debe ejecutar un proceso por contenedor porque si no lo hace, el proceso que se bifurcó y pasó a segundo plano no se supervisa y puede detenerse sin que usted lo sepa.

Cuando usa CMD cron && tail -f /var/log/cron.log el proceso cron básicamente se bifurca para ejecutar cron en segundo plano, el proceso principal se cierra y le permite ejecutar tailf en primer plano. El proceso cron en segundo plano podría detenerse o fallar, no lo notará, su contenedor seguirá ejecutándose en silencio y su herramienta de orquestación no lo reiniciará.

Puede evitar tal cosa al redirigir directamente la salida de comandos del cron a su docker stdout y stderr que se encuentran respectivamente en /proc/1/fd/1 y /proc/1/fd/2 .

Usando redireccionamientos básicos de shell, puede hacer algo como esto:

* * * * * root echo hello > /proc/1/fd/1 2>/proc/1/fd/2

Y su CMD será: CMD ["cron", "-f"]


Lo que ha sugerido @VonC es bueno, pero prefiero hacer toda la configuración del trabajo cron en una sola línea. Esto evitaría problemas entre plataformas como la ubicación de cronjob y no necesita un archivo cron separado.

FROM ubuntu:latest # Install cron RUN apt-get -y install cron # Create the log file to be able to run tail RUN touch /var/log/cron.log # Setup cron job RUN (crontab -l ; echo "* * * * * echo "Hello world" >> /var/log/cron.log") | crontab # Run the command on container startup CMD cron && tail -f /var/log/cron.log

Después de ejecutar su contenedor docker, puede asegurarse de que el servicio cron esté funcionando:

# To check if the job is scheduled docker exec -ti <your-container-id> bash -c "crontab -l" # To check if the cron service is running docker exec -ti <your-container-id> bash -c "pgrep cron"

Si prefiere tener ENTRYPOINT en lugar de CMD, puede sustituir el CMD anterior con

ENTRYPOINT cron start && tail -f /var/log/cron.log


Los trabajos de Cron se almacenan en / var / spool / cron / crontabs (lugar común en todas las distribuciones que conozco). Por cierto, puedes crear una pestaña cron en bash usando algo así:

crontab -l > cronexample echo "00 09 * * 1-5 echo hello" >> cronexample crontab cronexample rm cronexample

Esto creará un archivo temporal con la tarea cron, luego lo programará usando crontab. Última línea eliminar archivo temporal.


Para aquellos que desean usar una imagen simple y liviana:

FROM alpine:3.6 # copy crontabs for root user COPY config/cronjobs /etc/crontabs/root # start crond with log level 8 in foreground, output to stderr CMD ["crond", "-f", "-d", "8"]

Donde cronjobs es el archivo que contiene sus cronjobs, de esta forma:

* * * * * echo "hello " >> /test_file 2>&1 # remember to end this file with an empty new line


Puede copiar su crontab en una imagen, para que el contenedor lanzado desde dicha imagen ejecute el trabajo.

Consulte " Ejecutar un trabajo cron con Docker " de Julien Boulay en su Ekito/docker-cron :

Creemos un nuevo archivo llamado " hello-cron " para describir nuestro trabajo.

* * * * * echo "Hello world" >> /var/log/cron.log 2>&1 # An empty line is required at the end of this file for a valid cron file.

El siguiente Dockerfile describe todos los pasos para construir su imagen.

FROM ubuntu:latest MAINTAINER [email protected] RUN apt-get update && apt-get -y install cron # Copy hello-cron file to the cron.d directory COPY hello-cron /etc/cron.d/hello-cron # Give execution rights on the cron job RUN chmod 0644 /etc/cron.d/hello-cron # Apply cron job RUN crontab /etc/cron.d/hello-cron # Create the log file to be able to run tail RUN touch /var/log/cron.log # Run the command on container startup CMD cron && tail -f /var/log/cron.log

(vea el comment Gaafar y ¿Cómo hago que apt-get install sea menos ruidoso?
apt-get -y install -qq --force-yes cron puede funcionar)

O, asegúrese de que su trabajo en sí mismo redirija directamente a stdout / stderr en lugar de un archivo de registro, como se describe en la answer hugoShaka :

* * * * * root echo hello > /proc/1/fd/1 2>/proc/1/fd/2

Reemplace la última línea de Dockerfile con

CMD ["cron", "-f"]

Ver también (acerca de cron -f , es decir cron "primer plano") " docker ubuntu cron -f no funciona "

Construir y ejecutarlo:

sudo docker build --rm -t ekito/cron-example . sudo docker run -t -i ekito/cron-example

Sea paciente, espere 2 minutos y su línea de comando debería mostrar:

Hello world Hello world

Eric agrega en los comentarios :

Tenga en cuenta que la tail puede no mostrar el archivo correcto si se crea durante la creación de la imagen.
Si ese es el caso, debe crear o tocar el archivo durante el tiempo de ejecución del contenedor para que tail pueda recoger el archivo correcto.

Consulte " No se muestra la salida de tail -f al final de una ventana acoplable CMD ".


respuesta es bastante exhaustiva. Además, me gustaría agregar una cosa que me ayudó. Si solo desea ejecutar un trabajo cron sin seguir un archivo, estaría tentado a eliminar el && tail -f /var/log/cron.log del comando cron.

Sin embargo, esto hará que el contenedor Docker salga poco después de ejecutarse porque cuando se completa el comando cron, Docker cree que el último comando ha salido y, por lo tanto, mata el contenedor. Esto se puede evitar ejecutando cron en primer plano a través de cron -f .