如何解决Docker化Flask应用中的SQLite OperationalError: attempt to write a readonly database错误
如何解决Docker化Flask应用中的SQLite OperationalError: attempt to write a readonly database错误
看起来你遇到的是Docker环境下典型的SQLite权限问题——核心原因是你用非特权用户appuser运行应用,但这个用户没有对SQLite数据库文件及其所在目录的写入权限(SQLite不仅需要数据库文件可写,还得能在同目录创建临时的WAL/日志文件)。我来帮你一步步解决:
1. 调整Dockerfile,修复目录权限
你的Dockerfile里用root用户复制了代码文件,然后直接切换到appuser,但此时/app目录和里面的数据库文件所有权还是root,导致appuser无法写入。你需要在切换用户前修改目录所有权:
优化后的关键Dockerfile片段:
# ...前面的依赖安装、日志文件创建步骤保持不变... # 重点:将/app目录的所有权更改为appuser,确保它有完整的读写权限 RUN chown -R appuser:appuser /app # 再切换到非特权用户运行应用 USER appuser # 注意:你原来的Dockerfile里有两次`COPY . .`,这是重复操作,删掉第二次即可(第一次已经复制了所有代码) # ...后面的EXPOSE、CMD命令保持不变...
如果你的数据库文件打算放在单独的目录(比如/app/db,更推荐这种方式),可以提前创建目录并设置权限:
# 在修改所有权之前,创建专门的数据库目录 RUN mkdir -p /app/db && chown -R appuser:appuser /app/db
然后把Flask代码里的数据库连接路径改成/app/db/identifier.sqlite。
2. 用Docker卷持久化数据库(可选但强烈推荐)
如果希望容器重启或重建后,数据库数据不丢失,同时自动适配权限,建议给应用挂载Docker卷。修改你的docker-compose.yml:
version: "3.8" services: python_app: build: . ports: - "8000:8000" networks: - main-internal-net depends_on: - ngrok entrypoint: > /bin/sh -c "sleep 10 && python ngrok_url.py && flask run --host=0.0.0.0 --port=8000" # 添加卷挂载,持久化数据库数据 volumes: - sqlite_data:/app # 如果用了单独的db目录,就改成- sqlite_data:/app/db # ...ngrok服务配置保持不变... networks: main-internal-net: driver: bridge # 定义用于持久化SQLite数据的卷 volumes: sqlite_data:
Docker卷会自动处理权限问题,并且数据会独立于容器生命周期保存。
3. 验证数据库连接路径
确保Flask代码里的SQLite连接路径正确指向容器内的文件:
con = sqlite3.connect("/app/identifier.sqlite") # 或者用单独目录的路径:con = sqlite3.connect("/app/db/identifier.sqlite")
最后,重新构建镜像并启动容器:
docker-compose down docker-compose build --no-cache docker-compose up -d
再测试写入操作,应该就不会再出现只读数据库的错误了。
备注:内容来源于stack exchange,提问作者Dima
相关产品推荐
相关产品推荐

