Cron 作业显示但未在 dockerized Django 应用程序中执行

Cron jobs show but are not executed in dockerized Django app

我安装的应用程序中有“django_crontab”。

我配置了一个 cron 作业

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

我的 YAML 看起来像这样:

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 然后我打开 CLI:

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

那我试试看:

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

很好,但 cronjob 从未执行过。我没有按预期每分钟看到新的数据库转储。

django-crontab 本身不 运行 计划作业;它只是系统 cron 守护程序的包装器(例如,您需要使用 crontab(1) 的位置来配置它)。由于 Docker 容器只有 运行 一个进程,因此您需要第二个容器来 运行 cron 守护进程。

我在这里可能推荐的设置是编写一些其他脚本来执行所有必需的启动时设置,然后 运行s 一些可以作为附加参数传递的命令:

#!/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 "$@"

然后在您的 Docker 文件中,将此脚本设为 ENTRYPOINT。确保也提供默认的 CMD,可能 运行 主服务器。两者都提供,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

现在,在 docker-compose.yml 文件中,您可以从同一映像提供两个容器,但只覆盖 cron 容器的 command:。入口点脚本将为两者 运行 但在最后一行启动不同的命令。

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: