Crontab In Docker

Dockerfile to run crontab tasks

Crontab in Docker for Rails

This approach allows to run cron tasks of Rails application usually maintained by Whenever gem.

Dockerfile with Cron

FROM ruby:2.4.3-slim-stretch

RUN apt-get update -qq && apt-get install --no-install-recommends -y \
    build-essential \
    patch \
    ruby-dev \
    zlib1g-dev \
    liblzma-dev \
    libxml2 \
    libxml2-dev \
    libpq-dev \
    default-libmysqlclient-dev \
    imagemagick \
    git \
    wget \
    gnupg2 \
    curl \
    nodejs-dev \
    node-gyp \
    libssl1.0-dev \
    cron \
    && wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - \
    && echo "deb http://apt.postgresql.org/pub/repos/apt/ stretch"-pgdg main | tee  /etc/apt/sources.list.d/pgdg.list \
    && apt-get update -qq && apt-get install --no-install-recommends --no-upgrade -y \
    postgresql-client-11 \
    && rm -rf /var/lib/apt/lists/*

RUN curl -fsSLO --compressed "https://nodejs.org/dist/v8.17.0/node-v8.17.0-linux-x64.tar.xz" \
  && tar -xJf "node-v8.17.0-linux-x64.tar.xz" -C /usr/local --strip-components=1 --no-same-owner \
  && rm "node-v8.17.0-linux-x64.tar.xz" \
  && ln -s /usr/local/bin/node /usr/local/bin/nodejs \
  && npm install -g yarn

WORKDIR /opt/app
COPY ./config/entrypoint.sh /usr/bin/entrypoint.sh
RUN chmod +x /usr/bin/entrypoint.sh && crontab -l | { cat; echo ""; } | crontab -

RUN gem install bundler -v 2.0.1

ADD Gemfile* /opt/app/
RUN bundle install

ARG RAILS_ENV
ARG ACTION_CABLE_URL

COPY . /opt/app

RUN yarn install --check-files
RUN RAILS_ENV=$RAILS_ENV bundle exec rake assets:precompile

EXPOSE 9292

The docker-compose.yml part to start container with cron

version: "3"
services:
  crontab:
    image: ${PROJECT_HUB}/${PROJECT_NAME}/backend:${IMAGE_TAG}
    container_name: ${PROJECT_NAME}_crontab
    restart: on-failure
    networks:
      overlay:
        aliases:
          - crontab
    working_dir: /opt/app
    env_file:
    - ./.env
    command: bash -c 'env > /opt/app/cronenv && bundle exec whenever --update-crontab && cron -f'
    depends_on:
      - redis
      - db

This file is required to run cron tasks in the same enviroment. We create it on startup.

    env > /opt/app/cronenv

Setup whenever to generate tasks with following additions:

* * * * * /bin/bash -l -c 'for line in `cat /opt/app/cronenv` ; do export $line ; done && cd /opt/app && RAILS_ENV=production bundle exec rake addons:process_repeat_addons >> /var/log/cron.log 2>&1'

The approach is a bit naive, but whenever does not allow to edit command before /bin/bash, otherwise we can do as follows:

* * * * * env - `cat /opt/app/cronenv` /bin/bash -l -c 'cd /opt/app && bundle install && RAILS_ENV=production bundle exec rake addons:process_repeat_addons >> /var/log/cron.log 2>&1'