[Django]-How to make django-crontab execute commands in Docker container?

7👍

A Docker container only runs one process. You need to run two separate things: the main application server, and (after some initial setup) the cron daemon. You can straightforwardly run two separate containers running two separate commands from the same image, with the correct setup.

The first change I would make here is to combine what you currently have as a split ENTRYPOINT and CMD into a single CMD:

# no ENTRYPOINT, but
CMD ["python3", "manage.py", "runserver", "0.0.0.0:8080"]

With this setup, you can launch one container using this default command, and a second command from the same image but overriding command: in the Compose setup.

version: '3.8'
services:
  db: { ... }
 webapp:
  build: ./back
  restart: unless-stopped
  ports:
   - "8000:8000"
  env_file:
   - .env
  depends_on:
   - db
  # run the default command: from the image; no override
  # skip unnecessary links:, container_name:, volumes: options
 cron:
  build: ./back     # same as main application
  restart: unless-stopped
  env_file:
   - .env
  depends_on:
   - db
  command: cron -f  # as a long-running foreground process

The thing we haven’t done here is populate the crontab at container startup. This is where ENTRYPOINT can come in: if you have an ENTRYPOINT, it gets run instead of the CMD, but it gets passed the CMD as arguments. A pretty typical pattern here is to use ENTRYPOINT for a shell script that does some first-time setup, and then ends with exec "$@" to run whatever the provided CMD/command: was.

#!/bin/sh
# docker-entrypoint.sh

# If this is going to be a cron container, set up the crontab.
if [ "$1" = cron ]; then
  ./manage.py crontab add
fi

# Launch the main container command passed as arguments.
exec "$@"

Then in the Dockerfile, specify this script as the ENTRYPOINT.

...
WORKDIR /back
COPY . ./                                         # including docker-entrypoint.sh
...
ENTRYPOINT ["./docker-entrypoint.sh"]             # must be JSON-array syntax
CMD ["./manage.py", "runserver", "0.0.0.0:8080"]  # as before

You don’t need to override entrypoint: here. Commands like docker-compose run web app bash to get an interactive debugging shell will work fine; they’ll go via that entrypoint script, and run the shell as the final exec "$@" line.

Leave a comment