Как запустить задание cron внутри контейнера docker?

Я пытаюсь запустить cronjob внутри контейнера docker, который вызывает сценарий оболочки.

вчера я искал по всему интернету и переполнению стека, но я не мог найти решение, которое работает.
Как я могу это сделать?

EDIT:

Я создал (комментарии) репозиторий github С рабочим контейнером cron docker, который вызывает сценарий оболочки с заданным интервалом.

13 ответов


вы можете скопировать crontab в изображение, чтобы контейнер, запущенный из указанного изображения, запускал задание.

в разделе "выполнить задание cron с Docker" из Жюльен Буле в своем Ekito/docker-cron:

давайте создадим новый файл под названием "crontab", чтобы описать нашу работу.

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

в следующем файле DockerFile описаны все шаги по созданию изображение

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

(см. Джафар ' s комментарий и как сделать apt-get установить менее шумные?:
apt-get -y install -qq --force-yes cron может работать тоже)


или убедитесь, что ваша работа перенаправляется непосредственно в stdout / stderr вместо файла журнала, как описано в hugoShaka ' s ответ:

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

заменить последнюю строку Dockerfile на

CMD ["cron", "-f"]

Смотрите также (о cron -f, что означает cron "передний план")"docker ubuntu cron -f не работает"


построить и запустить его:

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

будьте терпеливы, подождите 2 минуты, и ваша командная строка должна отображаться:

Hello world
Hello world

Эрик добавляет в комментариях:

отметим, что tail может не отображаться правильный файл, если он создан во время изображения строить.
Если это так, вам нужно создать или коснуться файла во время выполнения контейнера, чтобы tail взял правильный файл.

в разделе "выход tail -f в конце докера CMD не показывает".


принятое решение может быть опасным в производственной среде.

в docker вы должны выполнить только один процесс на контейнер, потому что если вы этого не сделаете, процесс, который раздвоился и пошел фон, не контролируется docker и может остановиться без вашего ведома.

при использовании CMD cron && tail -f /var/log/cron.log процесс cron в основном fork для выполнения cron в фоновом режиме основной процесс завершается и позволяет выполнить tailf на переднем плане. Демон cron процесс может остановиться или потерпеть неудачу вы не заметите, ваш контейнер будет по-прежнему работать молча, и ваш инструмент оркестровки не перезапустит его.

вы можете избежать такой вещи, перенаправляя непосредственно команды cron вывода в docker stdout и stderr которые расположены соответственно в /proc/1/fd/1 и /proc/1/fd/2.

используя основные команды bash, вы можете сделать что-то вроде этого :

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

и ваш CMD будет : CMD ["cron", "-f"]


то, что предложил @VonC, приятно, но я предпочитаю делать всю конфигурацию задания cron в одной строке. Это позволит избежать кросс-платформенных проблем, таких как местоположение cronjob, и вам не нужен отдельный файл cron.

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

после запуска контейнера docker вы можете убедиться, что служба cron работает по:

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

Если вы предпочитаете иметь ENTRYPOINT вместо CMD, то вы можете заменить CMD выше с

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

для тех, кто хочет использовать простой и легкий образ:

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 это файл, который содержит ваши cronjobs, в этой форме:

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

есть другой способ сделать это, чтобы использовать Таскер, бегун задачи, который имеет поддержку cron (планировщик).

почему ? Иногда для запуска задания cron вам нужно смешать базовый образ (python, java, nodejs, ruby) с crond. Это означает, что нужно поддерживать другой образ. Tasker избежать этого, отделив crond и вы контейнер. Вы можете просто сосредоточиться на изображении, которое хотите выполнить свои команды, и настроить Tasker для его использования.

теги , это будет запускать некоторые задачи для вас
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")'

там есть 3 задачи, все они будут работать каждую минуту (every: minute), и каждый из них будет выполнять script код, внутри изображения, определенные в .

просто запустить docker-compose up и видим, как он работает. Вот РЕПО Tasker с полной документацией:

http://github.com/opsxcq/tasker


VonC это ответ довольно тщательно. Кроме того, я хотел бы добавить одну вещь, которая помогла мне.Если вы просто хотите запустить задание cron без слежения за файлом, у вас будет соблазн просто удалить && tail-f /var/log/cron.войдите из команды cron. Однако это приведет к выходу контейнера docker вскоре после запуска, потому что после завершения команды cron docker считает, что последняя команда вышла и, следовательно, убивает контейнер. Этого можно избежать, запустив cron в передний план через cron-f

Я бы написал это как комментарий, но у меня еще недостаточно очков:)


хотя это направлено на выполнение заданий рядом с запущенным процессом в контейнере через Docker's exec интерфейс, это может быть интересно для вас.

Я написал демон, который наблюдает за контейнерами и расписывает задания, определенные в их метаданных. Пример:

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

"классика", cron-как конфигурация также возможна.

здесь docs, вот репозиторий образов.


Я создал изображение докера на основе других ответов, которые можно использовать как

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

здесь /path/to/cron: абсолютный путь к файлу crontab

или использовать в качестве базы в Dockerfile

FROM gaafar/cron

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

# Add your commands here

при развертывании контейнера на другом хосте обратите внимание, что он не запускает процессы автоматически. Вы должны убедиться, что служба хрон работает внутри вашего контейнера. В нашем случае я использую Supervisord с другими службами для запуска службы 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

определите cronjob в выделенном контейнере, который запускает команду через docker exec для вашей службы.

это более высокая согласованность, и запущенный скрипт будет иметь доступ к переменным среды, определенным для вашей службы.

#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 хранятся в /var/spool/cron/crontabs (общее место во всех дистрибутивах, которые я знаю). Кстати, вы можете создать вкладку cron в bash, используя что-то вроде этого:

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

это создаст временный файл с задачей cron, а затем запрограммирует его с помощью crontab. Последняя строка удалить временный файл.


при запуске на некоторых обрезанных изображениях, которые ограничивают доступ root, мне пришлось добавить моего пользователя в sudoers и запустить как 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

может быть, это помогает кому-то


самый надежный способ, который я нашел до сих пор, - запустить независимый контейнер cron-установить клиент docker и привязать крепление носка docker, чтобы вы могли поговорить с сервером docker на хосте.

тогда просто используйте env vars для каждого задания cron и сценарий entrypoint для создания /etc / crontab