Docker 容器中的 Cronjob 使用 Django 中过时的设置,尽管 Docker Compose 中存在环境变量

问题描述 投票:0回答:1

我在使用 Django REST FrameworkDjango 应用程序中面临持续存在的问题。该应用程序有多个模型,其中一个名为 Project ,带有 created_at 时间戳。如果用户在项目创建后 72 小时内未对其采取操作,manage.py 中有一个管理命令,该命令会将项目存档。该命令由生产中的 cronjob 执行,整个设置在 Docker 容器中运行。

初始设置

以前,我把后端环境分成两个Docker容器:

一个容器运行 Django 应用程序并提供 API。 另一个容器专门用于运行执行这些管理命令的 cronjob。

组合容器的原因

此设置与过时的设置存在相同的问题,并且单独管理两个容器会增加大量开销,因为我需要清除两个容器的缓存并频繁重建它们。为了简化,我将 API 和 cronjob 合并到一个容器中,并使用 Supervisor 来管理该容器内的 cronjob。请注意,Supervisor 运行正常,因为 cronjob 本身按计划运行(日志证实了这一点),但这只是 cronjob 中的环境变量问题。

问题

cronjob 使用过时的设置,特别是指向测试数据库的旧 DB_HOST,而不是 Docker Compose 设置的环境变量中定义的正确数据库 URL。但是,Django 应用程序本身(正常访问时)可以正确连接到这些环境变量中指定的生产数据库。

奇怪的是,当我使用

手动运行archive_old_projects命令时
docker exec -it backend python3 manage.py archive_expired_new_project

它工作正常并使用正确的 DB_HOST 变量。只有当 cronjob 执行时,它才会回退到旧的、无法访问的数据库配置。这迫使我经常清理 Docker、删除缓存数据并重建映像以恢复功能,这对于持续维护来说是不切实际的解决方案。

对于每个本地构建,我始终使用

--pull
--no-cache
参数来确保一切都尽可能新鲜。不幸的是,这似乎对解决这个问题没有帮助——尽管采取了这些措施,cronjob 仍会间歇性地回退到过时的环境配置。

以下是有关我在测试和生产中使用环境变量的更多详细信息:

  • 在本地,我通过 .env 文件使用 DB_HOST 以及测试数据库的其他配置设置环境变量。
  • 部署时,Docker Compose 将生产变量直接注入容器中,DB_HOST正确指向生产数据库。

似乎 django 命令在从 cron 执行时依赖于某些“缓存”,但我无法找到并理解在哪里以及如何执行。

问题

为什么 cronjob 会使用过时的设置运行,即使它和 Django 应用程序都驻留在同一个 Docker 容器中并且应该有权访问相同的环境变量?

我尝试过的步骤

Docker Cleanup:重建 Docker 镜像,清除缓存层,并确保 Docker Compose 环境变量是最新的。这暂时解决了问题,但问题又出现了。

配置检查:验证 DB_HOST 和其他关键设置是否从 settings.py 中的环境中正确加载。

Cronjob 命令:检查 cronjob 条目以确保它使用正确的 management.py 路径,并且不会以某种方式引用过时的配置或设置文件。

相关设置

Dockerfile

FROM python:3.10.12-slim
WORKDIR /app

COPY requirements.txt /app/
RUN pip install --no-cache-dir -r requirements.txt
COPY . /app/

RUN apt-get update && \
    apt-get install -y cron && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

COPY crontab /etc/cron.d/cron_jobs
RUN chmod 0644 /etc/cron.d/cron_jobs
RUN crontab /etc/cron.d/cron_jobs

RUN pip install supervisor

COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf

EXPOSE 8000

CMD ["supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]

crontab

*/5 * * * * /usr/local/bin/python3 /app/manage.py archive_expired_new_project >> /app/logs/cron.log 2>&1
*/5 * * * * /usr/local/bin/python3 /app/manage.py archive_expired_to_contact_project >> /app/logs/cron.log 2>&1

supervisord.conf

[supervisord]
nodaemon=true

[program:gunicorn]
command=gunicorn --bind 0.0.0.0:8000 backend.wsgi:application
autostart=true
autorestart=true
stderr_logfile=/dev/stderr
stdout_logfile=/dev/stdout

[program:cron]
command=cron -f
autostart=true
autorestart=true
stderr_logfile=/dev/stderr
stdout_logfile=/dev/stdout

docker-compose.yml

name: my-app

services:
  backend:
    image: docker-user/repo-name:1.0.2
    container_name: backend
    expose:
      - "8000"
    networks:
      - app-network
    volumes:
      - ./logs:/app/logs
      - ./media:/app/media
    environment:
      SECRET_KEY: "*****"
      ...
      DB_HOST: "DATABASE_URL"
      DB_DATABASE: "db_name"
      DB_PORT: "5432"
      DB_USER: "db_user"
      DB_PASSWORD: "*****"
      ...

  frontend:
     ...

  nginx:
     ...

设置.py

...

DATABASES = {
  'default': {
    'ENGINE': 'django.db.backends.postgresql',
    'NAME': getenv('DB_DATABASE'),
    'USER': getenv('DB_USER'),
    'PASSWORD': getenv('DB_PASSWORD'),
    'HOST': getenv('DB_HOST'),
    'PORT': getenv('DB_PORT', 5432),
    'OPTIONS': {
      'sslmode': 'require',
    },
  }
}
django docker docker-compose cron environment-variables
1个回答
0
投票

由于我找不到 Docker 保留此缓存的任何原因,因此我使用了以下解决方法,以防其他用户在同一类型的项目中遇到相同的问题。

我停止使用管理命令和专用应用程序 cron 容器。

我将这些管理命令移至 REST 视图,只有具有特定身份验证令牌的特定用户才能启动。

我为 cron 作业创建了一个新的简单容器,用于在这些 URL 上执行curl 请求。

现在一切正常。

© www.soinside.com 2019 - 2024. All rights reserved.