1

I have "django_crontab" in my installed apps.

I have a cron job configured

CRONJOBS = [
    ('* * * * *', 'django.core.management.call_command',['dbbackup']),
]

my YAML looks like this:

web:
    build: .
    command:
      - /bin/bash
      - -c
      - |
        python manage.py migrate
        python manage.py crontab add
        python manage.py runserver 0.0.0.0:8000

build + up then I open the CLI:

$ python manage.py crontab show
Currently active jobs in crontab:
efa8dfc6d4b0cf6963932a5dc3726b23 -> ('* * * * *', 'django.core.management.call_command', ['dbbackup'])

Then I try that:

$ python manage.py crontab run efa8dfc6d4b0cf6963932a5dc3726b23
Backing Up Database: postgres
Writing file to default-858b61d9ccb6-2021-07-05-084119.psql

All good, but the cronjob never gets executed. I don't see new database dumps every minute as expected.

Vincent Roye
  • 2,751
  • 7
  • 33
  • 53
  • and to precise : $ crontab -l * * * * * /usr/local/bin/python /code/manage.py crontab run efa8dfc6d4b0cf6963932a5dc3726b23 # django-cronjobs for mysite – Vincent Roye Jul 05 '21 at 09:25

1 Answers1

2

django-crontab doesn't run scheduled jobs itself; it's just a wrapper around the system cron daemon (you need to configure it with the location of crontab(1), for example). Since a Docker container only runs one process, you need to have a second container to run the cron daemon.

A setup I might recommend here is to write some other script that does all of the required startup-time setup, then runs some command that can be passed as additional arguments:

#!/bin/sh
# entrypoint.sh: runs as the main container process
# Gets passed the container's command as arguments

# Run database migrations.  (Should be safe, if inefficient, to run
# multiple times concurrently.)
python manage.py migrate

# Set up scheduled jobs, if this is the cron container.
python manage.py crontab add

# Run whatever command we got passed.
exec "$@"

Then in your Dockerfile, make this script be the ENTRYPOINT. Make sure to supply a default CMD too, probably what would run the main server. With both provided, Docker will pass the CMD as arguments to the ENTRYPOINT.

# You probably already have a line like
# COPY . .
# which includes entrypoint.sh; it must be marked executable too

ENTRYPOINT ["./entrypoint.sh"] # must be JSON-array form
CMD python manage.py runserver 0.0.0.0:8000

Now in the docker-compose.yml file, you can provide both containers, from the same image, but only override the command: for the cron container. The entrypoint script will run for both but launch a different command at its last line.

version: '3.8'
services:
  web:
    build: .
    ports:
      - '8000:8000'
    # use the Dockerfile CMD, don't need a command: override
  cron:
    build: .
    command: crond -n # for Vixie cron; BusyBox uses "crond -f"
    # no ports:
David Maze
  • 130,717
  • 29
  • 175
  • 215
  • Thanks for your answer. I am getting this error message: cron_1 | ./entrypoint.sh: 13: exec: crond: not found and then cron_1 exited with code 127 – Vincent Roye Jul 05 '21 at 12:57
  • My Dockerfile starts with FROM python:3.8.6-slim-buster – Vincent Roye Jul 05 '21 at 12:58
  • I have replaced "command: crond -n" by "command: cron" And I get " cron: can't open or create /var/run/crond.pid: Permission denied " – Vincent Roye Jul 05 '21 at 13:09
  • In the end I have: - created that additional service that David mentionned - ran it with a specific Dockerfile (in which I copied my django project + a DB dump script + added a cronjob ) ~ I got inspiration from https://stackoverflow.com/questions/37458287/how-to-run-a-cron-job-inside-a-docker-container - – Vincent Roye Jul 07 '21 at 03:17