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é.
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 ".
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
etstderr
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"]
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
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"]
où 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
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:
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:)
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.
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]
où /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
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
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"
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.
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
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