Docker生产环境下Django数据库无法更新的问题求助
Django+Postgres生产环境迁移失效问题解决
问题现状
生产环境使用Django和Postgres时,数据库结构无法更新:
- 手动执行迁移命令,始终返回
migrations are already applied或no changes are detected - 本地migrations文件夹有新增迁移文件,但服务器上的迁移未实际生效
- 打开Django Admin面板出现数据库字段不存在的错误
- 目前只能通过
docker compose down -v删除数据库重新初始化,导致数据丢失
核心原因
你的判断正确:Git忽略了migrations目录下的实际迁移文件,仅推送了migrations/__init__.py。这引发两个关键问题:
- 容器构建时未包含本地生成的迁移文件,Django无法识别需要执行的迁移任务
- entrypoint脚本在生产环境自动执行
makemigrations,生成的临时迁移与本地开发的迁移不一致,而django_migrations表已记录旧迁移状态,最终导致模型与数据库结构不匹配
可行解决办法
1. 修正Git忽略规则,提交迁移文件到版本库
不要忽略migrations下的.py迁移文件,仅忽略缓存文件。修改.gitignore:
# 保留migrations目录下的所有.py文件,只忽略缓存 */migrations/__pycache__/ */migrations/*.pyc !*/migrations/__init__.py !*/migrations/*.py
提交所有本地已生成的迁移文件到Git,确保构建镜像时这些文件被包含。
2. 调整生产环境entrypoint脚本
生产环境禁止自动执行makemigrations,迁移文件必须在本地开发时生成并提交,生产仅执行migrate。修改entrypoint.sh:
#!/bin/sh echo "----------python migrate----------" python manage.py migrate --noinput echo "----------python collectstatic----------" python manage.py collectstatic --noinput echo "----------python runserver----------" uvicorn config.asgi:application --host 0.0.0.0 --port 8000 & python manage.py rqworker default --with-scheduler exec "$@"
3. 修复当前生产数据库(无需删库)
步骤1:备份数据库
先做全量备份,防止操作失误:
docker exec my_project-postgres pg_dump -U ${POSTGRES_USER} ${POSTGRES_DB} > production_backup.sql
步骤2:同步迁移文件到服务器
- 确保本地迁移文件已提交到Git,重新构建并推送镜像
- 拉取新镜像后重启容器,此时容器内已有正确的迁移文件
步骤3:执行迁移并修正状态
进入web容器,查看当前迁移状态:
docker exec -it ${API_CONTAINER_NAME} python manage.py showmigrations
如果有未应用的迁移,执行:
docker exec -it ${API_CONTAINER_NAME} python manage.py migrate --noinput
如果存在错误的迁移记录(比如之前自动生成的临时迁移),可针对指定应用重置后重新执行:
# 标记app_name的所有迁移为未应用 docker exec -it ${API_CONTAINER_NAME} python manage.py migrate --fake app_name zero # 重新执行迁移 docker exec -it ${API_CONTAINER_NAME} python manage.py migrate app_name
附用户提供的配置文件
Dockerfile
FROM python:3.10-buster RUN apt-get update #RUN useradd -m myapp RUN mkdir -p /home/myapp/app WORKDIR /home/myapp/app ENV PYTHONDONTWRITEBYTECODE=1 ENV PYTHONUNBUFFERED=1 ENV PATH $PATH:/home/myapp/.local/bin COPY requirements.txt . RUN pip install --upgrade pip RUN pip install -r requirements.txt COPY . . RUN chmod +x ./entrypoint.sh ENTRYPOINT ["sh", "./entrypoint.sh"]
docker-compose.yml
version: "3.8" networks: my_project_network: name: my_project_network services: web: image: ${TAG_LATEST} container_name: ${API_CONTAINER_NAME} command: ["./entrypoint.sh"] volumes: - my_project_media_data:/home/myapp/app/media/ - my_project_static_data:/home/myapp/app/static/ restart: always ports: - 8000:8000 networks: - my_project_network depends_on: - db db: image: postgres:latest container_name: my_project-postgres volumes: - my_project_postgres_data:/var/lib/postgresql/data/ environment: - POSTGRES_DB=${POSTGRES_DB} - POSTGRES_USER=${POSTGRES_USER} - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - POSTGRES_PORT=${POSTGRES_PORT} networks: - my_project_network restart: always redis: image: redis:latest container_name: my_project-redis ports: - 6379:6379 networks: - my_project_network restart: always depends_on: - db volumes: my_project_media_data: name: my_project_media_data my_project_static_data: name: my_project_static_data my_project_postgres_data: name: my_project_postgres_data
entrypoint.sh(原版本)
#!/bin/sh echo "----------python makemigrations----------" python manage.py makemigrations --noinput python manage.py migrate --noinput echo "----------python collectstatic----------" python manage.py collectstatic --noinput echo "----------python runserver----------" uvicorn config.asgi:application --host 0.0.0.0 --port 8000 & python manage.py rqworker default --with-scheduler exec "$@"
gitlab-ci.yml
image: alpine:3 stages: - build - deploy variables: TAG_LATEST: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME:latest TAG_COMMIT: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME:$CI_COMMIT_SHORT_SHA build: image: docker:latest stage: build only: - main services: - name: docker:dind alias: thedockerhost variables: DOCKER_HOST: tcp://thedockerhost:2375/ DOCKER_DRIVER: overlay2 DOCKER_TLS_CERTDIR: "" before_script: - chmod +x deploy.sh - ./deploy.sh script: - docker build -t $TAG_COMMIT -t $TAG_LATEST . - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - docker push $TAG_COMMIT - docker push $TAG_LATEST deploy: stage: deploy only: - main before_script: - chmod +x deploy.sh - ./deploy.sh script: - chmod og= $ID_RSA - apk update && apk add openssh-client - ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP -p $SERVER_SSH_PORT "sudo docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY" - ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP -p $SERVER_SSH_PORT "sudo docker pull $TAG_LATEST" - ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP -p $SERVER_SSH_PORT "sudo docker container rm $API_CONTAINER_NAME -f || true" - scp -i $ID_RSA -o StrictHostKeyChecking=no -P $SERVER_SSH_PORT -r ./.env ./docker-compose.yml $SERVER_USER@$SERVER_IP:/home/dev/projects/my_project-service - ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP -p $SERVER_SSH_PORT "cd /home/dev/projects/my_project-service && sudo docker compose up -d"
数据库错误截图

内容的提问来源于stack exchange,提问作者Fateme Fouladkar
相关产品推荐
相关产品推荐

