Docker容器中SQLite3写入失败:Django迁移报错求助
问题描述
我正尝试在EC2实例部署Django/React应用,本地Windows环境运行正常,但将代码部署到Ubuntu 22.04.3容器时出现以下错误:
django.db.migrations.exceptions.MigrationSchemaMissing: Unable to create the django_migrations table (attempt to write a readonly database)
请问这是Linux系统还是Dockerfile的问题?我原本计划熟练后改用PostgreSQL,是否现在就应该切换?
Dockerfile:
ARG PYTHON_VERSION=3.9-slim-bullseye FROM python:${PYTHON_VERSION} as python # Stage1: Create Wheels FROM python as python-build-stage ARG BUILD_ENVIRONMENT=local # required for make and setup for postgres (not used yet) RUN apt-get update && apt-get install --no-install-recommends -y \ build-essential \ libpq-dev COPY Backend/requirements . RUN pip wheel --wheel-dir /usr/src/app/wheels \ -r ${BUILD_ENVIRONMENT}.txt # Stage 2: Setup Django FROM python as python-run-stage ARG BUILD_ENVIRONMENT=local ARG APP_HOME=/app ENV PYTHONDONTWRITEBYTECODE 1 ENV PYTHONUNBUFFERED 1 ENV BUILD_ENV ${BUILD_ENVIRONMENT} WORKDIR ${APP_HOME} RUN addgroup --system django \ && adduser --system --ingroup django django RUN apt-get update && apt-get install --no-install-recommends -y \ libpq-dev \ netcat \ && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \ && rm -rf /var/lib/apt/lists/* COPY --from=python-build-stage /usr/src/app/wheels /wheels/ RUN pip install --no-cache-dir --no-index --find-links=/wheels/ /wheels/* \ && rm -rf /wheels/ # django app COPY --chown=django:django ./Webserver/django/entrypoint /entrypoint RUN sed -i 's/\r$//g' /entrypoint RUN chmod +x /entrypoint COPY --chown=django:django ./Webserver/django/start /start RUN sed -i 's/\r$//g' /start RUN chmod +x /start COPY --chown=django:django . ${APP_HOME} RUN chown django:django ${APP_HOME} USER django ENTRYPOINT ["/entrypoint"]
entrypoint:
#!/bin/bash set -o errexit set -o pipefail set -o nounset exec "$@"
Start:
#!/bin/bash set -o errexit set -o pipefail set -o nounset python3 Backend/manage.py migrate --no-input python3 Backend/manage.py collectstatic --no-input sudo python3 Backend/manage.py runserver 0.0.0.0:8000 # sudo gunicorn finalstrip.wsgi:application --bind 0.0.0.0:8000 --timeout 600
问题分析与解决方案
错误根源
这个问题是Docker配置和启动脚本的问题,和Linux系统本身无关,核心原因有两点:
- sudo权限冲突:你在
start脚本里用sudo执行服务,但容器内的django系统用户没有sudo权限,强制切换到root后,数据库文件的所有者变成root,后续django用户再操作时就会触发只读限制。 - SQLite路径权限:如果用默认的SQLite数据库,它的存储文件(默认是
Backend/db.sqlite3)需要django用户有读写权限,sudo切换用户后会打破这个权限规则,导致无法写入。
修复步骤
1. 移除start脚本中的sudo
直接用django用户运行服务,删除sudo关键字:
#!/bin/bash set -o errexit set -o pipefail set -o nounset python3 Backend/manage.py migrate --no-input python3 Backend/manage.py collectstatic --no-input python3 Backend/manage.py runserver 0.0.0.0:8000 # python3 gunicorn finalstrip.wsgi:application --bind 0.0.0.0:8000 --timeout 600
2. 确保数据库目录权限
如果项目中已经存在db.sqlite3,在Dockerfile末尾添加权限配置,确保django用户能读写:
# 确保Django项目目录有读写权限 RUN mkdir -p ${APP_HOME}/Backend && chown django:django ${APP_HOME}/Backend
3. 容器内避免使用sudo
容器环境下尽量用非root用户直接运行服务,既符合安全规范,也能避免不必要的权限冲突。
是否现在切换到PostgreSQL?
建议立刻切换,理由如下:
- SQLite不适合生产环境:它是单文件数据库,并发性能差,不支持多进程写入,而生产环境常用的Gunicorn是多进程模式,很容易出现锁死或读写错误。
- 提前适配生产流程:现在切换可以提前解决数据库迁移、环境变量配置、权限等问题,避免后期从SQLite迁移到PostgreSQL时出现数据兼容或配置遗漏。
- 你的Dockerfile已经预装了
libpq-dev,已经为PostgreSQL做好了依赖准备,切换成本极低。
切换参考步骤:
- 在对应环境的依赖文件(比如
requirements/local.txt)中添加psycopg2-binary - 修改Django的
settings.py数据库配置:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': os.environ.get('POSTGRES_DB'), 'USER': os.environ.get('POSTGRES_USER'), 'PASSWORD': os.environ.get('POSTGRES_PASSWORD'), 'HOST': 'postgres', # 用Docker Compose时对应服务名,EC2部署则填实例IP 'PORT': '5432', } }
- 用Docker Compose编排PostgreSQL服务,或者在EC2实例上单独部署PostgreSQL。
内容的提问来源于stack exchange,提问作者justin107d
相关产品推荐
相关产品推荐

