How to setup Cron jobs with Django-crontab inside Docker

After lots and lots of searches. Here is the solution I have found:

  1. Define your packages in the requirements.txt file so they can be installed by docker when the container is created:
Django>=4.0
psycopg2>=2.9
factory_boy==3.2.1
django-crontab==0.7.1
  1. Add django_crontabto your project’s INSTALLED_APPS. IMPORTANT to note that its django_crontabnot django-crontab
INSTALLED_APPS = [
	'django_crontab',
	...
]
  1. Add your cronjob to the appropriate app within the folder, for me it was in watchman/cron.py
from watchman.factories import RecordFactory

def change_timezones():
    record = RecordFactory()
    record.save()
  1. Add this cron file to your running CRONJOBS in the settings.py file
CRONJOBS = [
    ('* * * * *', 'watchman.cron.change_timezones')
]
  1. At this point, our django project is properly setup but we still need to setup docker. Our Dockerfile is pretty standard, but we can install cron and vim packages. vim isn’t required but it does make it easier to debug stuff.
# syntax=docker/dockerfile:1
FROM python:3
RUN apt-get update && apt-get install -y cron vim # Installing cron and vim
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
WORKDIR /code
COPY requirements.txt /code/
RUN pip install -r requirements.txt
COPY . /code
  1. In our docker-compose.yml file, we need to add another container which will run the cron job. Since docker containers run one process, so we can’t run this inside the container for the frontend. In the cron container, we will add all our cron jobs with python [manage.py](http://manage.py) crontab add and then run cron -f which runs cron as a foreground process. We need to provide our environment variables here so we our cron job can access the database. So here’s our updated docker-compose.yml file:
version: "3.9"

services:
  db:
		...
  web:
		...
  cron:
    build: .
    command: bash -c "python manage.py crontab add && cron -f" 
    depends_on:
      - db
    environment:
      - POSTGRES_DB=postgres
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
  1. Now, even though we have added our environment variables, crontab still won’t be able to access these variables because of some weird reason? An easy way to fix this is to manually specify the environment variables along with the command. To do this, we can specify a CRONJOB_COMMAND_PREFIX in the settings.py file as follows:
CRONTAB_COMMAND_PREFIX = f"POSTGRES_DB={os.environ.get('POSTGRES_DB')} POSTGRES_USER={os.environ.get('POSTGRES_USER')} POSTGRES_PASSWORD={os.environ.get('POSTGRES_PASSWORD')}"
  1. Now you can start the docker container and the cron job should work. You can view your current cron table by opening a shell session in the croncontainer and running crontab -l which will give you the following output
crontab -l
# Expected Output:
* * * * * POSTGRES_DB=postgres POSTGRES_USER=postgres POSTGRES_PASSWORD=postgres /usr/local/bin/python /code/manage.py crontab run a7953f0b20e26eb1fc404bb5bd57d0d4 # django-cronjobs for core