Comment exécuter un travail cron à l'intérieur d'un conteneur docker?

j'essaie de lancer une cronjob dans un conteneur docker qui invoque un script shell.

hier, j'ai cherché partout sur le web et le débordement de pile, mais je n'ai pas vraiment pu trouver une solution qui fonctionne.

Comment puis-je faire cela?

EDIT:

j'ai créé un (commenté) dépôt github avec un conteneur cron docker de travail qui invoque un script shell à un intervalle donné.

112
demandé sur C Heyer 2016-05-26 13:32:53

13 réponses

vous pouvez copier votre crontab dans une image, afin que le conteneur lancé à partir de ladite image pour exécuter le travail.

voir " exécuter un travail cron avec Docker " de Julien Boulay dans son Ekito/docker-cron :

créons un nouveau fichier appelé crontab " pour décrire notre travail.

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

le fichier DockerFile suivant décrit toutes les étapes pour construire votre image""

FROM ubuntu:latest
MAINTAINER docker@ekito.fr

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

(voir Gaafar 's commentaire et Comment faire apt-get installer moins bruyant? :

apt-get -y install -qq --force-yes cron peut fonctionner aussi)


ou, assurez-vous que votre travail lui-même rediriger directement à stdout / stderr au lieu d'un fichier journal, comme décrit dans hugoShaka 's réponse :

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

remplacer la dernière ligne du fichier Dockerfile par

CMD ["cron", "-f"]

voir aussi (environ cron -f , qui est de dire cron "premier plan") " docker ubuntu cron -f ne fonctionne pas


Build and run it:

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

patientez, attendez 2 minutes et votre ligne de commande devrait afficher:

Hello world
Hello world

Eric ajoute dans les commentaires :

notez que tail peut ne pas afficher le bon fichier s'il est créé pendant la construction de l'image.

Si c'est le cas, vous devez créer ou toucher le fichier conteneur runtime afin de queue pour ramasser le fichier correct.

voir " sortie de tail -f à la fin d'un docker CMD ne montre pas ".

169
répondu VonC 2018-07-07 15:58:30

la solution adoptée peut être dangereuse dans un environnement de production.

dans docker vous ne devez exécuter qu'un processus par conteneur parce que si vous ne le faites pas, le processus qui a bifurqué et est allé en arrière-plan n'est pas surveillé par docker et peut s'arrêter sans que vous le sachiez.

quand vous utilisez CMD cron && tail -f /var/log/cron.log le processus cron bifurque fondamentalement pour exécuter cron en arrière-plan, le processus principal sort et laisse vous exécutez tailf au premier plan. Le processus cron pourrait s'arrêter ou échouer, vous ne le remarquerez pas, votre container fonctionnera toujours silencieusement et votre outil d'orchestration ne le redémarrera pas.

vous pouvez éviter une telle chose en redirigeant directement la sortie des commandes cron dans votre docker stdout et stderr qui se trouvent respectivement dans /proc/1/fd/1 et /proc/1/fd/2 .

en utilisant les commandes de base bash vous pouvez je veux faire quelque chose comme ça:

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

et votre CMD sera: CMD ["cron", "-f"]

51
répondu hugoShaka 2018-09-19 15:45:04

ce que @VonC a suggéré est sympa mais je préfère faire toute la configuration du travail cron en une seule ligne. Cela éviterait les problèmes de plateforme croisée comme l'emplacement de cronjob et vous n'avez pas besoin d'un fichier cron séparé.

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

après avoir lancé votre conteneur docker, vous pouvez vous assurer si le service cron fonctionne par:

# 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 vous préférez un point D'entrée à la place du CMD, vous pouvez remplacer le CMD ci-dessus par

ENTRYPOINT cron start && tail -f /var/log/cron.log
17
répondu Youness 2017-07-07 23:54:33

pour ceux qui veulent utiliser une image simple et légère:

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"]

cronjobs est le fichier qui contient vos cronjobs, sous cette forme:

* * * * * echo "hello stackoverflow" >> /test_file 2>&1
# remember to end this file with an empty new line
13
répondu Oscar Fanelli 2017-12-24 11:22:31

il y a une autre façon de le faire, est d'utiliser Tasker , un coureur de tâche qui a cron (un planificateur) le soutien.

pourquoi ? Parfois, pour exécuter un travail cron, vous devez mélanger votre image de base (python, java, nodejs, ruby) avec le crond. Cela signifie une autre image à maintenir. Tasker éviter cela en découplant le crond et votre conteneur. Vous pouvez simplement l'accent sur l'image que vous souhaitez exécuter vos commandes, et de configurer Tasker pour l'utiliser.

voici un fichier docker-compose.yml , qui va exécuter quelques tâches pour vous

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")'

il y a 3 tâches là-bas, Toutes vont courir à chaque minute ( every: minute ), et chacune d'entre elles va exécuter le code script , à l'intérieur de l'image définie dans la section image .

il suffit de lancer docker-compose up , et de le voir fonctionner. Voici le rapport de Tasker avec la documentation complète:

http://github.com/opsxcq/tasker

10
répondu OPSXCQ 2017-09-16 14:33:34

la réponse de VonC est assez complète. En outre, je voudrais ajouter une chose qui m'a aidé.Si vous voulez simplement exécuter un travail cron sans suivre un fichier, vous seriez tenté de simplement supprimer le && tail-f /var/log/cron.journal à partir de la commande cron. Cependant, cela provoquera la sortie du conteneur docker peu de temps après son exécution, car lorsque la commande cron sera terminée, docker pense que la dernière commande est sortie et donc le conteneur sera tué. Cela peut être évité en exécutant cron au premier plan via cron-f

je voudrais écrire ceci comme un commentaire, mais je n'ai pas encore assez de points:)

6
répondu vanugrah 2017-06-20 01:54:43

bien que cela vise à exécuter des travaux à côté d'un processus en cours d'exécution dans un conteneur via l'interface exec de Docker, cela peut vous intéresser.

j'ai écrit un démon qui observe les conteneurs et planifie les travaux, définis dans leurs métadonnées, sur eux. Exemple:

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

'Classic', une configuration en cron est également possible.

voici le docs , voici l'image dépôt .

4
répondu funky-future 2016-12-16 14:52:22

j'ai créé une image docker basée sur les autres réponses, qui peut être utilisé comme

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

/path/to/cron : chemin d'accès absolu au fichier crontab

ou l'utiliser comme base dans un Dockerfile

FROM gaafar/cron

# COPY crontab file in the cron directory
COPY crontab /etc/cron.d/crontab

# Add your commands here
4
répondu Gaafar 2017-07-09 11:18:49

lorsque vous déployez votre conteneur sur un autre hôte, notez qu'il ne démarre aucun processus automatiquement. Vous devez vous assurer que le service "cron" est en cours d'exécution à l'intérieur de votre conteneur. Dans notre cas, J'utilise Supervisord avec d'autres services pour lancer le service 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
répondu Sagar Ghuge 2016-12-16 07:08:49

définit la cronjob dans un conteneur dédié qui exécute la commande via docker exec à votre service.

c'est plus de cohésion et le script d'exécution aura accès aux variables d'environnement que vous avez définies pour votre service.

#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
répondu Jakob Eriksson 2018-02-04 17:40:00

Cron jobs sont stockés dans /var/spool/cron/crontabs (lieu Commun dans toutes les distros, je le Sais). BTW, vous pouvez créer un onglet cron dans bash en utilisant quelque chose comme ça:

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

cela créera un fichier temporaire avec la tâche cron, puis le programmera en utilisant crontab. Dernière ligne supprimer le fichier temporaire.

1
répondu Jesus Segnini 2016-05-26 10:41:54

lors de l'exécution sur certaines images tronquées qui restreignent l'accès root, j'ai dû ajouter mon utilisateur aux sudoers et exécuter en tant que 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

peut - être que ça aide quelqu'un

0
répondu Senica Gonzalez 2017-11-28 15:05:57

le moyen le plus robuste que j'ai trouvé jusqu'à présent est d'exécuter un conteneur cron indépendant - installer le client docker et lier monter la chaussette docker afin que vous puissiez parler au serveur docker sur l'hôte.

ensuite, il suffit d'utiliser envvars pour chaque tâche cron et un script entrypoint pour générer le/etc / crontab

Voici une image que j'ai créée en utilisant ce principe et en l'utilisant dans la production pour les 3-4 dernières années.

https://www.vip-consulter.solutions/post/mieux-docker-cron#contenu

-1
répondu Krasi Georgiev 2016-12-17 23:43:26