Add multi-stage Dockerfile for container deployment

Three-stage build:
- assets: Node 22 + Vite + Tailwind CSS 4 → static/dist/main.css
- python-deps: uv sync --frozen --no-dev against pyproject + uv.lock,
  with the issue-core path dependency satisfied via a BuildKit
  named context (--build-context issue-core=...)
- runtime: python:3.12-slim-bookworm + libpq5 + curl, non-root 'app'
  user, collectstatic at build time, gunicorn on :8000,
  /health/ HEALTHCHECK every 30s

Adds gunicorn>=22 to project dependencies (was missing).

Build:
  docker build --build-context issue-core=/home/worsch/issue-core \
    -t gitea.coulomb.social/coulomb/vergabe-teilnahme:<tag> .

Smoke-verified: container reports (healthy) and /health/ returns
{"status": "ok"} without a database connection.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-18 23:32:51 +02:00
parent 17f511fbcd
commit 483a4dfd3b
4 changed files with 133 additions and 0 deletions

14
uv.lock generated
View File

@@ -329,6 +329,18 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/a7/a7/a600f8f30d4505e89166de51dd121bd540ab8e560e8cf0901de00a81de8c/faker-40.15.0-py3-none-any.whl", hash = "sha256:71ab3c3370da9d2205ab74ffb0fd51273063ad562b3a3bb69d0026a20923e318", size = 2004447 },
]
[[package]]
name = "gunicorn"
version = "26.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "packaging" },
]
sdist = { url = "https://files.pythonhosted.org/packages/6d/b7/a4a3f632f823e432ce6bc65f62961b7980c898c77f075a2f7118cb3846fe/gunicorn-26.0.0.tar.gz", hash = "sha256:ca9346f85e3a4aeeb64d491045c16b9a35647abd37ea15efe53080eb8b090baf", size = 727286 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e6/40/9c2384fc2be4ad25dd4a49decd5ad9ea5a3639814c11bd40ab77cb9f0a14/gunicorn-26.0.0-py3-none-any.whl", hash = "sha256:40233d26a5f0d1872916188c276e21641155111c2853f0c2cd55260aec0d24fc", size = 212009 },
]
[[package]]
name = "idna"
version = "3.15"
@@ -756,6 +768,7 @@ dependencies = [
{ name = "dj-database-url" },
{ name = "django" },
{ name = "django-storages" },
{ name = "gunicorn" },
{ name = "issue-core" },
{ name = "psycopg", extra = ["binary"] },
{ name = "python-decouple" },
@@ -777,6 +790,7 @@ requires-dist = [
{ name = "dj-database-url", specifier = ">=2.1" },
{ name = "django", specifier = ">=5.2" },
{ name = "django-storages", specifier = ">=1.14" },
{ name = "gunicorn", specifier = ">=22.0" },
{ name = "issue-core", directory = "../issue-core" },
{ name = "psycopg", extras = ["binary"], specifier = ">=3.2" },
{ name = "python-decouple", specifier = ">=3.8" },