Dima
Dima

Reputation: 13

How to Fix 'SQLite OperationalError: Attempt to Write a Read-Only Database' in a Dockerized Flask App

I want to use sqlite db in docker container but when I try to add or change data I get this error

    Traceback (most recent call last):
  File "/usr/local/lib/python3.12/site-packages/flask/app.py", line 1511, in wsgi_app
    response = self.full_dispatch_request()
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/flask/app.py", line 919, in full_dispatch_request
    rv = self.handle_user_exception(e)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/flask/app.py", line 917, in full_dispatch_request
    rv = self.dispatch_request()
         ^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/flask/app.py", line 902, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)  # type: ignore[no-any-return]
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/app/app.py", line 67, in create_user
    add_user(data['name'], data['unit'], data['email'], data['password'])
  File "/app/app.py", line 29, in add_user
    cur.execute("INSERT INTO Users (Name, Unit, Email, Password) VALUES (?, ?, ?, ?)",
sqlite3.OperationalError: attempt to write a readonly database
2025-02-24 21:28:03,229 - INFO - 172.18.0.2 - - [24/Feb/2025 21:28:03] "POST /post-user/create-user HTTP/1.1" 500 -
2025-02-24 21:28:17,293 - ERROR - Exception on /post-user/create-user [POST]
Traceback (most recent call last):
  File "/usr/local/lib/python3.12/site-packages/flask/app.py", line 1511, in wsgi_app
    response = self.full_dispatch_request()
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/flask/app.py", line 919, in full_dispatch_request
    rv = self.handle_user_exception(e)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/flask/app.py", line 917, in full_dispatch_request
    rv = self.dispatch_request()
         ^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/flask/app.py", line 902, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)  # type: ignore[no-any-return]
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/app/app.py", line 67, in create_user
    add_user(data['name'], data['unit'], data['email'], data['password'])
  File "/app/app.py", line 29, in add_user
    cur.execute("INSERT INTO Users (Name, Unit, Email, Password) VALUES (?, ?, ?, ?)",
sqlite3.OperationalError: attempt to write a readonly database

My Docker file

ARG PYTHON_VERSION=3.12.7
FROM python:${PYTHON_VERSION}-slim as base

# Prevents Python from writing pyc files.
ENV PYTHONDONTWRITEBYTECODE=1

# Keeps Python from buffering stdout and stderr to avoid situations where
# the application crashes without emitting any logs due to buffering.
ENV PYTHONUNBUFFERED=1

WORKDIR /app

# Create a non-privileged user that the app will run under.
# See https://docs.docker.com/go/dockerfile-user-best-practices/
ARG UID=10001
RUN adduser \
    --disabled-password \
    --gecos "" \
    --home "/nonexistent" \
    --shell "/sbin/nologin" \
    --no-create-home \
    --uid "${UID}" \
    appuser

# Download dependencies as a separate step to take advantage of Docker's caching.
# Leverage a cache mount to /root/.cache/pip to speed up subsequent builds.
# Leverage a bind mount to requirements.txt to avoid having to copy them into
# into this layer.
COPY . .
USER root
# Install dependencies using cache and bind mount for requirements.txt
RUN --mount=type=cache,target=/root/.cache/pip \
    --mount=type=bind,source=requirements.txt,target=requirements.txt \
    python -m pip install -r requirements.txt


# Create log file and update permissions
RUN mkdir -p /app && touch /app/logs.log && chmod 666 /app/logs.log


# Switch to the non-privileged user to run the application.
USER appuser

# Copy the source code into the container.
COPY . .

# Expose the port that the application listens on.
EXPOSE 4040


# Run the application.
CMD gunicorn app:app --bind=0.0.0.0:8000

My Compose file

version: "3.8"

services:
  python_app:
    build: .
    ports:
      - "8000:8000"  # Exposing Flask on port 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"

  ngrok:
    image: ngrok/ngrok:latest
    command:
      - "http"
      - "--url=${URL}"
      - "http://python_app:8000"
    environment:
      NGROK_AUTHTOKEN: ${API_NGROK}
    ports:
      - "4040:4040"
    networks:
      - main-internal-net

networks:
  main-internal-net:
    driver: bridge

Usage

con = sqlite3.connect("identifier.sqlite")
cur = con.cursor()
cur.execute("INSERT INTO Users (Name, Unit, Email, Password) VALUES (?, ?, ?, ?)",
            (name, unit, email, password))
con.commit()
con.close()

I have tried solutions from similar resolved questions on Stack Overflow, but they didn’t work for me. I also tried manually changing the file permissions in the Docker terminal, but the issue persists.

Upvotes: -1

Views: 33

Answers (1)

Dima
Dima

Reputation: 13

The problem was with project folder permissions and database permissions

This worked for me

RUN chown -R user:user /app && chmod 777 /project_folder

RUN chmod 666 /path_to_db/db.sqlite

Upvotes: 0

Related Questions