From 0b979cfadaf2991a6a370818d37d85dbc4eb351a Mon Sep 17 00:00:00 2001 From: Markus Rosenstihl Date: Tue, 14 Apr 2026 08:40:14 +0200 Subject: [PATCH 1/3] Initial container build --- Dockerfile | 61 ++++++++++++++++++++++++++++++++++++++++++++++++ requirements.txt | 3 +++ 2 files changed, 64 insertions(+) create mode 100644 Dockerfile create mode 100644 requirements.txt diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..871253b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,61 @@ +# Use the official Python runtime image +FROM python:3.13-alpine + +# Create the app directory +RUN mkdir /app + +# Set the working directory inside the container +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 + +# Set environment variables +# Prevents Python from writing pyc files to disk +ENV PYTHONDONTWRITEBYTECODE=1 +# Prevents Python from buffering stdout and stderr +ENV PYTHONUNBUFFERED=1 +# Ignore pip warning about running as root +ENV PIP_ROOT_USER_ACTION=ignore + +# Upgrade pip +#RUN pip install --upgrade pip + +# 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. +RUN --mount=type=cache,target=/root/.cache/pip \ + --mount=type=bind,source=requirements.txt,target=/requirements.txt \ + python -m pip install -r /requirements.txt + +## run this command to install all dependencies +#RUN pip install --no-cache-dir -r requirements.txt +##RUN pip install --no-cache-dir django-tailwind + +# Switch to the non-privileged user to run the application. +USER appuser + +# allow all hosts +ENV DJANGO_ALLOWED_HOSTS=* + +# Copy the Django project files to the container +COPY --chown=appuser:appuser excel_mimic /app/excel_mimic +COPY --chown=appuser:appuser sheets /app/sheets +COPY --chown=appuser:appuser manage.py db.sqlite3 /app/ + +# Expose the Django port +EXPOSE 8000 + +# Run Django’s development server +CMD ["python", "manage.py", "migrate"] +CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"] diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..14324ca --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +asgiref==3.8.1 +Django==5.1.6 +sqlparse==0.5.3 From a953bce90eda9f7906f7bc823a4cd60616b1178a Mon Sep 17 00:00:00 2001 From: Markus Rosenstihl Date: Tue, 14 Apr 2026 11:43:35 +0200 Subject: [PATCH 2/3] fixed permissions for db.sqlite3 --- .gitignore | 4 ++++ Dockerfile | 16 +++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..851fc41 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +venv +.venv +__pycache__ +.idea diff --git a/Dockerfile b/Dockerfile index 871253b..ea832f2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,13 @@ # Use the official Python runtime image FROM python:3.13-alpine +#COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ + +# Disable development dependencies +#ENV UV_NO_DEV=1 # Create the app directory RUN mkdir /app -# Set the working directory inside the container -WORKDIR /app # Create a non-privileged user that the app will run under. # See https://docs.docker.com/go/dockerfile-user-best-practices/ @@ -34,6 +36,8 @@ ENV PIP_ROOT_USER_ACTION=ignore # 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. +# using pip (uv is below) + RUN --mount=type=cache,target=/root/.cache/pip \ --mount=type=bind,source=requirements.txt,target=/requirements.txt \ python -m pip install -r /requirements.txt @@ -41,6 +45,8 @@ RUN --mount=type=cache,target=/root/.cache/pip \ ## run this command to install all dependencies #RUN pip install --no-cache-dir -r requirements.txt ##RUN pip install --no-cache-dir django-tailwind + +RUN chown appuser:appuser /app # Switch to the non-privileged user to run the application. USER appuser @@ -55,7 +61,11 @@ COPY --chown=appuser:appuser manage.py db.sqlite3 /app/ # Expose the Django port EXPOSE 8000 + +# Set the working directory inside the container +WORKDIR /app + +#RUN uv sync --locked # Run Django’s development server -CMD ["python", "manage.py", "migrate"] CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"] From b4f39381e3f3c19ae6cb7a879424f218d56e122a Mon Sep 17 00:00:00 2001 From: Markus Rosenstihl Date: Tue, 14 Apr 2026 13:02:01 +0200 Subject: [PATCH 3/3] Moved to uv packaging --- Dockerfile | 60 ++++++++++++++++++++++-------------------------- pyproject.toml | 9 ++++++++ requirements.txt | 3 --- uv.lock | 55 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 91 insertions(+), 36 deletions(-) create mode 100644 pyproject.toml delete mode 100644 requirements.txt create mode 100644 uv.lock diff --git a/Dockerfile b/Dockerfile index ea832f2..9e4a87f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,12 +1,12 @@ # Use the official Python runtime image FROM python:3.13-alpine -#COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ -# Disable development dependencies -#ENV UV_NO_DEV=1 # Create the app directory -RUN mkdir /app +#RUN mkdir /app +# Set the working directory inside the container +WORKDIR /app # Create a non-privileged user that the app will run under. @@ -14,14 +14,17 @@ RUN mkdir /app ARG UID=10001 RUN adduser \ --disabled-password \ - --gecos "" \ - --home "/nonexistent" \ --shell "/sbin/nologin" \ - --no-create-home \ --uid "${UID}" \ appuser # Set environment variables + +## Django +# Allow all hosts +ENV DJANGO_ALLOWED_HOSTS=* + +## Python # Prevents Python from writing pyc files to disk ENV PYTHONDONTWRITEBYTECODE=1 # Prevents Python from buffering stdout and stderr @@ -29,43 +32,34 @@ ENV PYTHONUNBUFFERED=1 # Ignore pip warning about running as root ENV PIP_ROOT_USER_ACTION=ignore -# Upgrade pip -#RUN pip install --upgrade pip +## uv +# Enable bytecode compilation +ENV UV_COMPILE_BYTECODE=1 +# Copy from the cache instead of linking since it's a mounted volume +ENV UV_LINK_MODE=copy +# Disable development dependencies +ENV UV_NO_DEV=1 -# 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. -# using pip (uv is below) +# copy project settings +COPY pyproject.toml uv.lock /app/ -RUN --mount=type=cache,target=/root/.cache/pip \ - --mount=type=bind,source=requirements.txt,target=/requirements.txt \ - python -m pip install -r /requirements.txt - -## run this command to install all dependencies -#RUN pip install --no-cache-dir -r requirements.txt -##RUN pip install --no-cache-dir django-tailwind +# Install the project's dependencies using the lockfile and settings +RUN --mount=type=cache,target=/root/.cache/uv \ + uv sync --locked --no-install-project RUN chown appuser:appuser /app -# Switch to the non-privileged user to run the application. -USER appuser - -# allow all hosts -ENV DJANGO_ALLOWED_HOSTS=* - # Copy the Django project files to the container COPY --chown=appuser:appuser excel_mimic /app/excel_mimic COPY --chown=appuser:appuser sheets /app/sheets COPY --chown=appuser:appuser manage.py db.sqlite3 /app/ - + # Expose the Django port EXPOSE 8000 -# Set the working directory inside the container -WORKDIR /app -#RUN uv sync --locked - +# Switch to the non-privileged user to run the application. +USER appuser + # Run Django’s development server -CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"] +CMD ["uv", "run", "manage.py", "runserver", "0.0.0.0:8000"] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..980a946 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,9 @@ +[project] +name = "he-database" +version = "0.1.0" +description = "Add your description here" +readme = "README.md" +requires-python = ">=3.12" +dependencies = [ + "django==6.0.4", +] diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 14324ca..0000000 --- a/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -asgiref==3.8.1 -Django==5.1.6 -sqlparse==0.5.3 diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..b50187e --- /dev/null +++ b/uv.lock @@ -0,0 +1,55 @@ +version = 1 +revision = 3 +requires-python = ">=3.12" + +[[package]] +name = "asgiref" +version = "3.11.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/63/40/f03da1264ae8f7cfdbf9146542e5e7e8100a4c66ab48e791df9a03d3f6c0/asgiref-3.11.1.tar.gz", hash = "sha256:5f184dc43b7e763efe848065441eac62229c9f7b0475f41f80e207a114eda4ce", size = 38550, upload-time = "2026-02-03T13:30:14.33Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/0a/a72d10ed65068e115044937873362e6e32fab1b7dce0046aeb224682c989/asgiref-3.11.1-py3-none-any.whl", hash = "sha256:e8667a091e69529631969fd45dc268fa79b99c92c5fcdda727757e52146ec133", size = 24345, upload-time = "2026-02-03T13:30:13.039Z" }, +] + +[[package]] +name = "django" +version = "6.0.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asgiref" }, + { name = "sqlparse" }, + { name = "tzdata", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/60/b9/4155091ad1788b38563bd77a7258c0834e8c12a7f56f6975deaf54f8b61d/django-6.0.4.tar.gz", hash = "sha256:8cfa2572b3f2768b2e84983cf3c4811877a01edb64e817986ec5d60751c113ac", size = 10907407, upload-time = "2026-04-07T13:55:44.961Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/47/3d61d611609764aa71a37f7037b870e7bfb22937366974c4fd46cada7bab/django-6.0.4-py3-none-any.whl", hash = "sha256:14359c809fc16e8f81fd2b59d7d348e4d2d799da6840b10522b6edf7b8afc1da", size = 8368342, upload-time = "2026-04-07T13:55:37.999Z" }, +] + +[[package]] +name = "he-database" +version = "0.1.0" +source = { virtual = "." } +dependencies = [ + { name = "django" }, +] + +[package.metadata] +requires-dist = [{ name = "django", specifier = "==6.0.4" }] + +[[package]] +name = "sqlparse" +version = "0.5.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/90/76/437d71068094df0726366574cf3432a4ed754217b436eb7429415cf2d480/sqlparse-0.5.5.tar.gz", hash = "sha256:e20d4a9b0b8585fdf63b10d30066c7c94c5d7a7ec47c889a2d83a3caa93ff28e", size = 120815, upload-time = "2025-12-19T07:17:45.073Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl", hash = "sha256:12a08b3bf3eec877c519589833aed092e2444e68240a3577e8e26148acc7b1ba", size = 46138, upload-time = "2025-12-19T07:17:46.573Z" }, +] + +[[package]] +name = "tzdata" +version = "2026.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/19/f5/cd531b2d15a671a40c0f66cf06bc3570a12cd56eef98960068ebbad1bf5a/tzdata-2026.1.tar.gz", hash = "sha256:67658a1903c75917309e753fdc349ac0efd8c27db7a0cb406a25be4840f87f98", size = 197639, upload-time = "2026-04-03T11:25:22.002Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b0/70/d460bd685a170790ec89317e9bd33047988e4bce507b831f5db771e142de/tzdata-2026.1-py2.py3-none-any.whl", hash = "sha256:4b1d2be7ac37ceafd7327b961aa3a54e467efbdb563a23655fbfe0d39cfc42a9", size = 348952, upload-time = "2026-04-03T11:25:20.313Z" }, +]