it-swarm.com.de

Wie führe ich einen Cron-Job in einem Docker-Container aus?

Ich versuche, einen Cronjob in einem Docker-Container auszuführen, der ein Shell-Skript aufruft.

Gestern habe ich im ganzen Web nach Stapelüberlauf gesucht, aber ich konnte keine wirklich funktionierende Lösung finden.
Wie kann ich das machen?

EDIT:

Ich habe ein (kommentiertes) github-Repository erstellt mit einem funktionierenden Docker-Cron-Container, der in einem bestimmten Intervall ein Shell-Skript aufruft.

138
C Heyer

Sie können Ihre Crontab in ein Image kopieren, damit der von diesem Image gestartete Container den Job ausführen kann.

Siehe " Einen Cron-Job mit Docker ausführen " von Julien Boulay in seinem Ekito/docker-cron :

Erstellen Sie eine neue Datei mit dem Namen "crontab", um unseren Job zu beschreiben.

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

Die folgende DockerFile beschreibt alle Schritte zum Erstellen Ihres Images

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

(Siehe Gaafar 's Kommentar und Wie mache ich, dass apt-get weniger laut installiert wird? :
apt-get -y install -qq --force-yes cron kann auch funktionieren)


ODER stellen Sie sicher, dass Ihr Job direkt an stdout/stderr anstatt an eine Protokolldatei weitergeleitet wird, wie in hugoShaka 's answer beschrieben.

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

Ersetzen Sie die letzte Dockerfile-Zeile durch

CMD ["cron", "-f"]

Siehe auch (über cron -f, dh cron "foreground") " docker ubuntu cron -f funktioniert nicht "


Bauen Sie es auf und führen Sie es aus:

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

Seien Sie geduldig, warten Sie 2 Minuten und die Befehlszeile sollte Folgendes anzeigen:

Hello world
Hello world

Eric ergänzt in den Kommentaren :

Beachten Sie, dass tail möglicherweise nicht die richtige Datei anzeigt, wenn diese während der Image-Erstellung erstellt wird.
Wenn dies der Fall ist, müssen Sie die Datei während der Laufzeit des Containers erstellen oder berühren, damit tail die richtige Datei aufnimmt.

Siehe " Ausgabe von tail -f am Ende eines Dockers CMD zeigt " nicht an.

207
VonC

Die eingesetzte Lösung kann in einer Produktionsumgebung gefährlich sein.

Im Docker sollten Sie nur einen Prozess pro Container ausführen. Andernfalls wird der Prozess, der sich verzogen hat und im Hintergrund gegangen ist, nicht vom Docker überwacht und kann anhalten, ohne dass Sie es wissen.

Wenn Sie CMD cron && tail -f /var/log/cron.log verwenden, ist der cron-Prozess im Wesentlichen eine Verzweigung, um cron im Hintergrund auszuführen. Der Hauptprozess wird beendet, und Sie können tailf im Vordergrund ausführen. Der Cron-Prozess könnte anhalten oder fehlschlagen, Sie werden es nicht bemerken, der Container wird weiterhin unbeaufsichtigt ausgeführt und Ihr Orchestrierungs-Tool startet ihn nicht neu.

Sie können dies vermeiden, indem Sie die Befehle des crons direkt in Ihr Docker stdout und stderr umleiten, die sich jeweils in /proc/1/fd/1 und /proc/1/fd/2 befinden.

Mit grundlegenden Bash-Befehlen möchten Sie vielleicht Folgendes tun: 

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

Und Ihre CMD wird sein: CMD ["cron", "-f"]

65
hugoShaka

Was @VonC vorgeschlagen hat, ist Nice, aber ich bevorzuge die Konfiguration aller Cron-Jobs in einer Zeile. Dadurch würden plattformübergreifende Probleme wie der Cronjob-Standort vermieden und Sie benötigen keine separate Cron-Datei.

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

Nachdem Sie Ihren Docker-Container ausgeführt haben, können Sie anhand der folgenden Schritte sicherstellen, dass der cron-Dienst funktioniert:

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

Wenn Sie lieber ENTRYPOINT anstelle von CMD haben, können Sie die oben stehende CMD durch ersetzen

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

Für diejenigen, die ein einfaches und leichtes Image verwenden möchten:

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

Wo cronjobs ist die Datei, die Ihre Cronjobs enthält, in dieser Form

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

Es gibt einen anderen Weg, dies zu tun, ist die Verwendung von Tasker , einem Task-Runner, der Cron (ein Scheduler) unterstützt.

Warum ? Um einen Cron-Job auszuführen, müssen Sie Ihr Basis-Image (Python, Java, Nodejs, Ruby) mit dem Crond mischen. Das bedeutet, dass ein anderes Bild beibehalten werden muss. Tasker vermeiden das, indem Sie die Crond und Ihren Container entkoppeln. Sie können sich nur auf das Bild konzentrieren, das Sie ausführen möchten, und die Verwendung von Tasker konfigurieren.

Hier eine docker-compose.yml-Datei, die einige Aufgaben für Sie ausführt

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

Es gibt drei Aufgaben, alle werden jede Minute ausgeführt (every: minute), und jede von ihnen führt den script-Code in dem in image definierten Bild aus.

Führen Sie einfach docker-compose up aus und sehen Sie, dass es funktioniert. Hier ist das Tasker-Repo mit der vollständigen Dokumentation:

http://github.com/opsxcq/tasker

11
OPSXCQ

VonCs Antwort ist ziemlich gründlich. Außerdem möchte ich noch etwas hinzufügen, das mir geholfen hat. Wenn Sie nur einen Cron-Job ausführen möchten, ohne eine Datei zu beenden, werden Sie versucht, den && tail -f /var/log/cron.log aus dem Cron-Befehl zu entfernen. Dies führt jedoch dazu, dass der Docker-Container kurz nach der Ausführung beendet wird. Andernfalls glaubt das Docker, dass der letzte Befehl beendet wurde. Dies kann vermieden werden, indem cron über cron -f im Vordergrund ausgeführt wird.

Ich würde dies als Kommentar schreiben, aber ich habe noch nicht genug Punkte :)

8
vanugrah

Ich habe ein Andockbild erstellt, das auf den anderen Antworten basiert, die gerne verwendet werden können

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

dabei ist /path/to/cron: absoluter Pfad zur Crontab-Datei

oder als Basis in einem Dockerfile verwenden

FROM gaafar/cron

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

# Add your commands here
4
Gaafar

Definieren Sie den Cronjob in einem dedizierten Container, der den Befehl über Docker Exec zu Ihrem Dienst ausführt.

Dies ist eine höhere Kohäsion und das laufende Skript hat Zugriff auf die Umgebungsvariablen, die Sie für Ihren Service definiert haben.

#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"
4
Jakob Eriksson

Dies soll zwar die Ausführung von Jobs neben einem laufenden Prozess in einem Container über die exec-Schnittstelle von Docker ermöglichen, dies kann jedoch für Sie von Interesse sein.

Ich habe einen Daemon geschrieben, der Container überwacht und Jobs, die in ihren Metadaten definiert sind, für sie plant. Beispiel:

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

Eine klassische, cronartige Konfiguration ist ebenfalls möglich.

Hier sind die docs , hier ist das Image Repository .

4
funky-future

Wenn Sie Ihren Container auf einem anderen Host bereitstellen, beachten Sie, dass keine Prozesse automatisch gestartet werden. Sie müssen sicherstellen, dass der cron-Dienst in Ihrem Container ausgeführt wird .. In unserem Fall verwende ich Supervisord zusammen mit anderen Diensten, um den cron-Dienst zu starten.

[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
3
Sagar Ghuge

Mein Problem war also dasselbe. Das Update bestand darin, den Befehlsabschnitt in docker-compose.yml zu ändern.

Von

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

zu

befehl: crontab/etc/crontab

befehl: tail -f/etc/crontab

Das Problem war das '&&' zwischen den Befehlen. Nach dem Löschen war alles in Ordnung.

0
Pedro

Cron-Jobs werden in/var/spool/cron/crontabs (allgemeiner Ort in allen Distros, die ich kenne) gespeichert. Übrigens, Sie können einen cron-Tab in bash erstellen, indem Sie Folgendes verwenden:

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

Dadurch wird eine temporäre Datei mit cron-Task erstellt und anschließend mit crontab programmiert. Letzte Zeile temporäre Datei entfernen.

0
Jesus Segnini

Bei einigen heruntergefahrenen Images, die den Root-Zugriff einschränken, musste ich meinen Benutzer den Sudoern hinzufügen und als 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

Vielleicht hilft das jemandem

0
Senica Gonzalez