Запланированное задание Docker cron не выполняется

#linux #docker #docker-compose #cron

Вопрос:

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

Моя служба docker-compose настроена следующим образом:

   cron:
    image: alpine:3.11
    command: /usr/local/startup.sh amp;amp; crond -f -l 8
    volumes:
      - ./cron_tasks_folder/1min:/etc/periodic/1min/:ro
      - ./cron_tasks_folder/15min:/etc/periodic/15min/:ro
      - ./cron_tasks_folder/hourly:/etc/periodic/hourly/:ro
      - ./scripts/startup.sh:/usr/local/startup.sh:ro
 

Таким образом, он запускает начальный сценарий, называемый startup.sh , а затем запускает демона cron. startup.sh Сценарий содержит следующее:

 #!/bin/sh

echo "Starting startup.sh.."
echo "*       *       *       *       *       run-parts /etc/periodic/1min" >> /etc/crontabs/root
crontab -l
sleep 300
 

Я сбросил туда команду sleep только для того, чтобы запустить интерактивную оболочку в контейнере и убедиться, что все внутри выглядит хорошо. Скрипт создает другую папку для 1мин скриптов. Я добавил туда тестовый сценарий, и я могу убедиться, что он там есть:

 /etc/periodic/1min # ls -a
.           ..          testScript
 

Скрипт является исполняемым:

 /etc/periodic/1min # ls -l testScript 
-rwxr-xr-x    1 root     root            31 Jul 30 01:51 testScript
 

И testScript это просто эхо-утверждение, чтобы убедиться, что оно работает в первую очередь:

 echo "The donkey is in charge"
 

И, просматривая root файл в etc/crontabs, я вижу следующее (я несколько раз запускал контейнер повторно, и каждый раз он создавал новую папку на 1 минуту, что не нужно, но я думаю, что проблема здесь не в этом):

 # do daily/weekly/monthly maintenance
# min   hour    day     month   weekday command
*/15    *       *       *       *       run-parts /etc/periodic/15min
0       *       *       *       *       run-parts /etc/periodic/hourly
0       2       *       *       *       run-parts /etc/periodic/daily
0       3       *       *       6       run-parts /etc/periodic/weekly
0       5       1       *       *       run-parts /etc/periodic/monthly

*       *       *       *       *       run-parts /etc/periodic/1min
*       *       *       *       *       run-parts /etc/periodic/1min
*       *       *       *       *       run-parts /etc/periodic/1min
*       *       *       *       *       run-parts /etc/periodic/1min
*       *       *       *       *       run-parts /etc/periodic/1min
 

Оператор echo в testScript никогда не печатается на моем терминале, и контейнер выходит с кодом выхода 0 вскоре после запуска. Я хочу печатать это заявление каждую минуту… что я упускаю?

Комментарии:

1. как вы думаете, где вы запускаете планировщик хрона? crontab -l перечисляет задания cron, но не запускает планировщик. Исходя из предоставленных вами данных, я бы сказал, что на самом деле вы не запускаете cron.

2. @DanielFarrell, насколько я понимаю, amp;amp; crond -f -l 8 в command docker-compose это делает.

3. Ладно, ладно, я это пропустил. Но startup.sh придется выйти до того, как запущенная оболочка command выполнит crond. Ты ждешь эти 5 минут? На твоем месте я бы поставил exec crond -f -l 8 на место sleep «в startup.sh «. Убедитесь, что вы проверяете журналы докеров, если это не работает.

4. Это работает! Сейчас я получаю следующую ошибку, но это другая проблема: run-parts: can't execute '/etc/periodic/1min/testScript': Exec format error . Тем не менее, я также могу удалить команду amp;amp; crond -f -l 8 из моего docker-compose. Является ли такая конфигурация приемлемой практикой? Если вы хотите ответить этим ответом, я приму его. Спасибо.

5. я дам реальный ответ. Можете ли вы указать ENTRYPOINT , если таковые имеются, в своем файле dockerfile?

Ответ №1:

В файле компоновки docker у вас есть

     command: /usr/local/startup.sh amp;amp; crond -f -l 8
 

Намерение состоит в том, чтобы работать как команда оболочки, но из вопроса совсем не ясно, что произойдет; это зависит от вас ENTRYPOINT . Поскольку он определен в [] скобках, дополнительная оболочка не будет предоставлена. command Значение будет передано в качестве аргументов в ENTRYPOINT .

Предполагая, что это станет командой оболочки, amp;amp; в оболочке выполняется левая сторона, и если это удастся, то выполняется правая сторона. Поэтому startup.sh необходимо завершить до crond того, как будет выполнено. startup.sh заканчивается на

 sleep 300
 

crond вызывается только после этого 300 секунд.

В любом случае crond либо вообще не вызывается, либо sleep не завершается. Комментарии показывают, что crond была обнаружена ошибка запуска.

Использование точки входа, подобной этой, является стандартной практикой для настройки среды до или предоставления параметров среды выполнения при вызове основного исполняемого файла. Чтобы сделать это правильно, вы должны убедиться, что используете exec для запуска основной исполняемый файл, чтобы он получал сигналы, которые в противном случае отправлялись бы в оболочку bash, выполняющую сценарий точки входа.

Итак, в конце startup.sh :

 exec crond -f -l 8
 

Заменит запущенную оболочку startup.sh crond , чтобы crond она принимала все сигналы (в этот момент оболочка исчезла). Это тонко, но важно!

В общем, сохраняйте вызов приложения как можно более простым. В данном случае процесс выполнения был разделен между точкой входа, командой и сценарием запуска без четкого интерфейса между ними. Вы бы не зациклились на вызове, если бы вставили crond его непосредственно в файл Dockerfile и оставили на этом. Иногда аргументы должны предоставляться во время выполнения, но переменные среды, которые имеют имена, а не только позиции, часто являются предпочтительными. Это упрощает вызов и упрощает отладку. Но, когда это не работает, точка входа в сценарий оболочки — отличное решение-просто убедитесь в exec своем окончательном процессе!

Комментарии:

1. Вы могли бы рассмотреть возможность завершения сценария точки входа с exec "$@" помощью , а затем настройки CMD crond -f -l 8 . Это будет иметь тот же чистый эффект, за исключением того, что вы можете docker run --rm -it your-image sh запустить сценарий установки точки входа, но завершить его интерактивной оболочкой вместо демона cron или иным образом запустить какую-либо альтернативную команду после выполнения первой настройки.

2. Важно отметить, что моя последняя ошибка была устранена путем добавления #!/bin/sh ошибки в верхней части моего сценария, а не только самого оператора echo.