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


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

Ayer he estado buscando por toda la web y stack overflow, pero realmente no pude encontrar una solución que funcione.
¿Cómo puedo hacer esto?

EDITAR:

He creado un repositorio de github (comentado) con un contenedor cron de docker que invoca un script de shell en un intervalo dado.

Author: C Heyer, 2016-05-26

13 answers

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

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

Vamos a crear un nuevo archivo llamado "crontab" 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 archivo DockerFile describe todos los pasos para construir su imagen

FROM ubuntu:latest
MAINTAINER [email protected]

RUN apt-get update && apt-get -y install cron

# Add crontab file in the cron directory
ADD crontab /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

(véase Gaafar comment and How do I make apt-get install less noisy?:
apt-get -y install -qq --force-yes cron puede funcionar también)


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

 * * * * * 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, que es decir cron" primer plano") " docker ubuntu cron -f no está funcionando "


Compilar y ejecutar it:

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 comandos debe mostrar:

Hello world
Hello world

Eric agrega en los comentarios:

Tenga en cuenta que tail puede no mostrar el archivo correcto si se crea durante la compilació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.

Véase " Salida de tail -f al final de un docker CMD no muestra ".

 169
Author: VonC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-07 15:58:30

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 se fue en segundo plano no es monitoreado por docker y puede detenerse sin que usted lo sepa.

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

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

Usando comandos bash básicos puede que quieras hacer algo como esto:

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

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

 51
Author: hugoShaka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-19 15:45:04

Lo que @VonC ha sugerido es bueno, pero prefiero hacer toda la configuración del trabajo cron en una línea. Esto evitaría problemas multiplataforma 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 mediante:

# 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, entonces puede sustituir el CMD anterior con

ENTRYPOINT cron start && tail -f /var/log/cron.log
 17
Author: Youness,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-07 23:54:33

Para aquellos que quieren usar una imagen simple y ligera:

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 tus cronjobs, en esta forma:

* * * * * echo "hello stackoverflow" >> /test_file 2>&1
# remember to end this file with an empty new line
 13
Author: Oscar Fanelli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-24 11:22:31

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

¿Por qué ? A veces para ejecutar un trabajo cron, tienes que mezclar, tu imagen base (python, java, nodejs, ruby) con el cron. Eso significa otra imagen para mantener. Tasker evita eso desacoplando el crond y tu contenedor. Solo puede centrarse en la imagen que desea ejecutar sus comandos, y configurar Tasker para usarlo.

Aquí un archivo docker-compose.yml, que ejecutará algunos tareas para ti

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 ellas se ejecutarán cada minuto (every: minute), y cada una de ellas ejecutará el código script, dentro de la imagen definida en la sección image.

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

Http://github.com/opsxcq/tasker

 10
Author: OPSXCQ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-16 14:33:34

La respuesta de VonC es bastante completa. Además me gustaría añadir 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.registro desde el comando cron. Sin embargo, esto hará que el contenedor de docker salga poco después de ejecutarse porque cuando se completa el comando cron, docker piensa que el último comando ha salido y, por lo tanto, mata al contenedor. Esto se puede evitar ejecutando cron en primer plano a través de cron-f

Escribiría esto como un comentario, pero todavía no tengo suficientes puntos:)

 6
Author: vanugrah,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-20 01:54:43

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', cron-como la configuración también es posible.

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

 4
Author: funky-future,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-16 14:52:22

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][1]

Donde /path/to/cron: ruta absoluta al archivo crontab

O usar 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
 4
Author: Gaafar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-09 11:18:49

Cuando implemente su contenedor en otro host, solo 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
 2
Author: Sagar Ghuge,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-16 07:08:49

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

Esta 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"
 2
Author: Jakob Eriksson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-04 17:40:00

Los trabajos 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.

 1
Author: Jesus Segnini,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-26 10:41:54

Cuando se ejecuta en 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 ayuda a alguien

 0
Author: Senica Gonzalez,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-28 15:05:57

La forma más robusta que he encontrado hasta ahora es ejecutar un contenedor cron independiente: instalar el cliente docker y bind montar el calcetín docker para que pueda hablar con el servidor docker en el host.

Entonces solo use env vars para cada trabajo cron y un script entrypoint 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ño.

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

 -1
Author: Krasi Georgiev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-17 23:43:26