Как запустить задание 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 с полной документацией:
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