Created
January 30, 2026 11:23
-
-
Save h0tw1r3/0c26ca958600a87f63f6cf947306e7ef to your computer and use it in GitHub Desktop.
Running cron in docker... what could go wrong?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| SHELL=/bin/bash | |
| BASH_ENV=/etc/environment | |
| @reboot root echo "yes, it's working" > >(logger -t CRON[$$]) 2> >(logger -p user.err -t CRON[$$]) | |
| * * * * * root echo "this happened" > >(logger -t CRON[$$]) 2> >(logger -p user.err -t CRON[$$]) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| FROM debian:bookworm-slim AS install | |
| ENV DEBIAN_FRONTEND=noninteractive | |
| ENV LANG=C.UTF-8 | |
| SHELL ["/bin/bash", "-euxo", "pipefail", "-c"] | |
| # Install cron and backup requirements | |
| RUN <<EOF | |
| echo "LANG=${LANG}" > /etc/default/locale | |
| apt-get -qq update | |
| apt-get -qq install --no-install-recommends -y cron rsyslog | |
| ### Install any packages required to support jobs here ### | |
| # remove any default cron jobs | |
| rm -rf /etc/cron.*/* | |
| # cleanup | |
| apt-get purge -y --allow-remove-essential --auto-remove apt | |
| rm -rf /var/lib/apt /var/cache/apt | |
| EOF | |
| FROM scratch | |
| COPY --from=install / / | |
| # needed to log cron service output | |
| COPY rsyslog.conf /etc/rsyslog.conf | |
| COPY entrypoint.sh /usr/local/bin/docker-entrypoint.sh | |
| COPY cron.d/ /etc/cron.d/ | |
| COPY healthcheck.sh /healthcheck | |
| HEALTHCHECK --start-period=5s --timeout=5s --retries=2 CMD /healthcheck | |
| STOPSIGNAL SIGINT | |
| ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] | |
| CMD [] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # if command is specified, run it and exit | |
| if [ $# -gt 0 ] ; then | |
| exec "$@" | |
| exit $? | |
| fi | |
| # check required environment variables | |
| required_vars=() | |
| missing_vars="" | |
| for var in "${required_vars[@]}"; do | |
| if [ -z "${!var:-}" ]; then | |
| missing_vars+=", $var" | |
| fi | |
| done | |
| if [ -n "${missing_vars}" ] ; then | |
| echo >&2 "ERROR: required environment variables are not set: ${missing_vars:2}" | |
| exit 1 | |
| fi | |
| unset missing_vars | |
| # boilerplate entrypoint code | |
| set -o nounset -o pipefail -o errtrace -o errexit -o functrace | |
| exec 0<&- | |
| # trap all errors and report line number, error code and command | |
| error_trap() { | |
| local el=${1:=??} ec=${2:=??} lc="$BASH_COMMAND" | |
| echo >&2 "ERROR in $(basename "$0") : $el error $ec : $lc" | |
| exit "${2:=1}" | |
| } | |
| trap 'error_trap ${LINENO} ${?}' ERR | |
| # support for graceful shutdown | |
| shutdown() { | |
| sleep 1 | |
| exec >/dev/fd/1 2>/dev/fd/2 | |
| kill "${LOG_PID:-1}" 2>/dev/null | |
| exit | |
| } | |
| interrupt() { echo "received shutdown signal: $*"; shutdown ; } | |
| trap "interrupt int" INT | |
| trap "interrupt term" SIGTERM | |
| # start rsyslog to capture logs | |
| rsyslogd -n & | |
| LOG_PID=$! | |
| # wait for rsyslogd to start | |
| timeout 10s bash -c 'while [ ! -S /dev/log ] ; do sleep 0.2; done' || { | |
| echo >&2 "rsyslogd failed to start" | |
| exit 1 | |
| } | |
| # redirect stdout/stderr to logger | |
| exec 1> >(logger -t "entrypoint") 2>&1 | |
| # write required vars so they are available to cron jobs | |
| echo "writing required environment variables to /etc/environment" | |
| for var in "${required_vars[@]}"; do | |
| echo "$var='${!var}'" >> /etc/environment | |
| done | |
| cron -f & | |
| # keep waiting for rsyslogd | |
| while kill -0 $LOG_PID 2>/dev/null; do | |
| wait $LOG_PID || sleep 1 | |
| done |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| set -e -o pipefail -o nounset -o errexit | |
| shopt -s extglob | |
| # update interval counter | |
| intervalfile="/dev/shm/healthcheck.interval" | |
| count=0 | |
| if read -r count < "$intervalfile" ; then | |
| count=$((count + 1)) | |
| fi | |
| echo "$count" >"$intervalfile" | |
| only_every() { | |
| local interval=$1 | |
| shift | |
| (( count % interval == 0 )) || return | |
| "$@" | |
| } | |
| fail_pid() { | |
| echo >&2 "failed to validate PID of $*" | |
| exit 1 | |
| } | |
| verify_pidfile() { # $1: pidfile, $2: pattern | |
| pid=$(<"$1") | |
| verify_pid "${pid##*( )}" "$2" | |
| } | |
| verify_pid() { | |
| if ! grep -aq "$2" "/proc/$1/cmdline" 2>/dev/null ; then | |
| if [ -z "${3:-}" ] ; then | |
| # sometimes start-stop-daemon causes pidfile to be -1 | |
| # of the real process... | |
| pid=$(($1 + 1)) | |
| verify_pid $pid "$2" stop | |
| else | |
| return 1 | |
| fi | |
| fi | |
| } | |
| # expected processes running | |
| verify_pidfile /run/crond.pid ^cron || fail_pid cron | |
| verify_pidfile /run/rsyslogd.pid ^rsyslogd || fail_pid rsyslogd |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| global(workDirectory="/tmp") | |
| template(name="docker" type="string" string="%$.syslogtag% <%syslogpriority-text%> %$.msg%\r\n") | |
| # local logging (e.g. via logger command) | |
| module(load="imuxsock" SysSock.Use="on") | |
| # messages may not well formatted, clean them up here | |
| ruleset(name="rewrite_logs") { | |
| set $.syslogtag = $syslogtag; | |
| set $.msg = rtrim(ltrim($msg)); | |
| if $programname == 'CRON' then { | |
| if re_match($.msg, 'pam_unix\\(cron:session\\): session (opened|closed) for user root') then { stop } | |
| set $.found = re_extract($.msg, '( ?> >\\(logger .*CRON\\[..\\]\\) 2> >\\(logger .*CRON\\[..\\]\\))', 0, 1, ""); | |
| if ($.found != "") then { | |
| set $.msg = replace($.msg, $.found, ""); | |
| } | |
| } | |
| action(type="omfile" file="/proc/1/fd/1" template="docker") | |
| } | |
| # attach the ruleset | |
| input(type="imuxsock" socket="/dev/log" ruleset="rewrite_logs") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment