javan/whenever

Cron jobs inside a docker container

spryffee opened this issue · 6 comments

What's a better way to make whenever running tasks with app running inside a docker container? I migrated my deployment to Kamal and Cron tasks do not work anymore. Kamal doc suggests running cron job on specific container with settings stored in config/crontab but this is not what we expect using whenever.

Have you tried adding this to your Dockerfile?

RUN bundle exec whenever --update-crontab

Have you tried adding this to your Dockerfile?

RUN bundle exec whenever --update-crontab

Unfortunately, It doesn't work

#20 [stage-2 5/5] RUN bundle exec whenever --update-crontab
#20 0.502 bundler: failed to load command: whenever (/usr/local/bundle/ruby/3.2.0/bin/whenever)
#20 0.502 /usr/local/bundle/ruby/3.2.0/gems/whenever-1.0.0/lib/whenever/command_line.rb:77:in `popen': No such file or directory - crontab (Errno::ENOENT)

Cron is intalled

Are you using the ruby-slim or ruby-alpine images?

They may require special configuration to install cron properly.
(See here or here for example)

I'm using standard production Dockerfile that comes with Rails 7.1. So it's ruby:$RUBY_VERSION-slim

  1. add cron and privileges for your rails user (Dockerfile)
....
# Install packages needed for deployment
RUN apt-get update -qq && \
    apt-get install --no-install-recommends -y curl postgresql-client cron && \
    rm -rf /var/lib/apt/lists /var/cache/apt/archives
....
# Run and own only the runtime files as a non-root user for security
RUN useradd rails --create-home --shell /bin/bash && \
    chmod gu+rw /var/run && \
    chmod gu+s /usr/sbin/cron && \
    chown -R rails:rails db log tmp
...
  1. add to your entrypoint (default - bin/docker-entrypoint)
#!/bin/bash -e

touch ./log/cron.log
cron
./bin/bundle exec whenever --update-crontab

./bin/rails db:prepare

exec "${@}"
  1. add to config/schedule.rb
ENV.each { |k, v| env(k, v) }

set :output, 'log/cron.log'
set :environment, ENV['RAILS_ENV']

job_type :runner, "cd :path && bin/rails runner -e :environment ':task' :output"

that's what helped me

now you can check if cron is running (service cron status in container's bash) and debug jobs output in log/cron.log

My initial issue was that I was installing Cron in wrong place of Dockerfile that comes with Rails 7.1. Cron should be installed on the final stage for app image (under "FROM base" section). But I end up moving to pure cron without using this gem as suggested here.

@nbnp11 your solution also works, thank you!