<!-- TITLE: Crontab In Docker -->
<!-- SUBTITLE: 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
```Dockerfile
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
```sh
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.
```sh
env > /opt/app/cronenv
```
Setup whenever to generate tasks with following additions:
```sh
* * * * * /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:
```sh
* * * * * 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'
```