Whew! That's a long title, isn't it? I'm going to show you how to get cron jobs working in a Docker container. Specifically, I'll be using the whenever gem to create those cron jobs.
Copy environment variables to crontab
First, we're going to add a couple lines to our
schedule.rb file so that whenever will copy our environment variables into our crontab. We do this because cron jobs are run with a mostly empty environment. If we don't do this, our jobs will have a hard time finding the binaries they need:
# schedule.rb ... ENV.each_key do |key| env key.to_sym, ENV[key] end ...
These lines iterate over all of the environment variables that are set at the time that
bundle exec whenever --update-crontab is run and copies them into the crontab file that is generated. This way we have access to the same exact environment variables in our jobs as we do in our normal interactive shell.
Set Rails environment
Next, we need to add one more line to our
# schedule.rb ... set :environment, ENV["RAILS_ENV"] ...
This line is needed to make sure that our RAILS_ENV variable is respected by our cron jobs. The whenever gem explicity sets the RAILS_ENV variable in the crontab job lines that it creates and overrides whatever it was set to. The line above ensures that the jobs in the crontab use the RAILS_ENV setting that was present when the crontab file was created.
Run Docker container
Finally, we need to run the Docker container. Here's an example Dockerfile to get you started:
# Dockerfile FROM ruby:2.3 RUN apt-get update && \ apt-get install -qq -y --no-install-recommends cron && \ rm -rf /var/lib/apt/lists/* ENV APP_HOME /usr/src/app ENV RAILS_LOG_TO_STDOUT true ENV RAILS_ENV production RUN mkdir -p $APP_HOME WORKDIR $APP_HOME COPY Gemfile $APP_HOME/Gemfile COPY Gemfile.lock $APP_HOME/Gemfile.lock RUN bundle install COPY . $APP_HOME CMD bash -c "bundle exec whenever --update-crontab && cron -f"
The important parts to note are explained below.
This line installs cron:
... RUN apt-get update && \ apt-get install -qq -y --no-install-recommends cron && \ rm -rf /var/lib/apt/lists/* ...
And this line updates the crontab and runs cron:
... CMD bash -c "bundle exec whenever --update-crontab && cron -f"
And that's it! The biggest challenge in getting this to run was figuring out that environment variables can be copied into the crontab. Before that I ran into so many issues with jobs not being able to find the programs they needed.
Photo by Glenn Carstens-Peters