From c9091bd11e650ab6dcd9000cc8cc9ef0e88ec60c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arkadiusz=20Ba=C5=82akier?= Date: Thu, 12 Mar 2026 15:18:02 +0100 Subject: [PATCH 1/2] add psycopg2-binary version specification to requirements.txt --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 2dc12c67..844b379c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,3 +8,4 @@ djangorestframework djangorestframework-simplejwt drf-spectacular Pillow +psycopg2-binary == 2.9.11 \ No newline at end of file From fc467f9297b70fed392392fb2db13c855481d7cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arkadiusz=20Ba=C5=82akier?= Date: Tue, 17 Mar 2026 13:11:21 +0100 Subject: [PATCH 2/2] Add Docker support with Dockerfile and docker-compose, configure environment variables, and create management commands --- .dockerignore | 15 +++++++++++ Dockerfile | 25 +++++++++++++++++ cinema/management/__init__.py | 0 cinema/management/commands/__init__.py | 0 cinema/management/commands/wait_for_db.py | 17 ++++++++++++ cinema_service/settings.py | 20 +++++++++----- docker-compose.yml | 33 +++++++++++++++++++++++ 7 files changed, 103 insertions(+), 7 deletions(-) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 cinema/management/__init__.py create mode 100644 cinema/management/commands/__init__.py create mode 100644 cinema/management/commands/wait_for_db.py create mode 100644 docker-compose.yml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..febbadee --- /dev/null +++ b/.dockerignore @@ -0,0 +1,15 @@ +.git +.gitignore + +.venv +venv +env +__pycache__ +*.pyc + +*.sqlite3 + +.env + +staticfiles +media \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..01867d83 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,25 @@ +FROM python:3.12-slim + +WORKDIR /app + +RUN apt-get update && apt-get install -y --no-install-recommends \ + build-essential gcc libpq-dev libjpeg-dev zlib1g-dev curl && \ + rm -rf /var/lib/apt/lists/* + +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +RUN adduser --disabled-password --no-create-home django-user + +RUN mkdir -p /vol/web/media && \ + chown -R django-user:django-user /vol && \ + chmod -R 755 /vol/web + +COPY . /app +RUN chown -R django-user:django-user /app + +USER django-user + +EXPOSE 8000 + +CMD ["gunicorn", "cinema_service.wsgi:application", "--bind", "0.0.0.0:8000"] diff --git a/cinema/management/__init__.py b/cinema/management/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/cinema/management/commands/__init__.py b/cinema/management/commands/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/cinema/management/commands/wait_for_db.py b/cinema/management/commands/wait_for_db.py new file mode 100644 index 00000000..b176c4e4 --- /dev/null +++ b/cinema/management/commands/wait_for_db.py @@ -0,0 +1,17 @@ +import time +from django.db import connections +from django.db.utils import OperationalError +from django.core.management.base import BaseCommand + + +class Command(BaseCommand): + """Django command that waits for the database to be available.""" + + def handle(self, *args, **options): + db_conn = None + while not db_conn: + try: + db_conn = connections["default"] + except OperationalError: + self.stdout.write("Database unavailable, waiting 1 second...") + time.sleep(1) diff --git a/cinema_service/settings.py b/cinema_service/settings.py index 90dde772..4072c9b4 100644 --- a/cinema_service/settings.py +++ b/cinema_service/settings.py @@ -9,8 +9,10 @@ For the full list of settings and their values, see https://docs.djangoproject.com/en/4.0/ref/settings/ """ + from datetime import timedelta from pathlib import Path +import os # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent @@ -20,14 +22,14 @@ # See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = ( - "django-insecure-6vubhk2$++agnctay_4pxy_8cq)mosmn(*-#2b^v4cgsh-^!i3" +SECRET_KEY = os.environ.get( + "SECRET_KEY", default="django-insecure-+_!@#%&*()_+1234567890" ) # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True +DEBUG = bool(os.environ.get("DEBUG", default=0)) -ALLOWED_HOSTS = [] +ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS").split(" ") INTERNAL_IPS = [ "127.0.0.1", @@ -86,8 +88,12 @@ DATABASES = { "default": { - "ENGINE": "django.db.backends.sqlite3", - "NAME": BASE_DIR / "db.sqlite3", + "ENGINE": os.environ.get("SQL_ENGINE", "django.db.backends.sqlite3"), + "NAME": os.environ.get("SQL_DATABASE", BASE_DIR / "db.sqlite3"), + "USER": os.environ.get("SQL_USER", "user"), + "PASSWORD": os.environ.get("SQL_PASSWORD", "password"), + "HOST": os.environ.get("SQL_HOST", "localhost"), + "PORT": os.environ.get("SQL_PORT", "5432"), } } @@ -134,7 +140,7 @@ STATIC_URL = "static/" MEDIA_URL = "/media/" -MEDIA_ROOT = BASE_DIR / "media" +MEDIA_ROOT = "/vol/web/media" # Default primary key field type # https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..bf54a38b --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,33 @@ +services: + app: + build: + context: . + ports: + - "8000:8000" + command: > + sh -c "python manage.py wait_for_db && + python manage.py migrate && + python manage.py runserver 0.0.0.0:8000" + env_file: + - .env + + volumes: + - ./:/app + - media_volume:/vol/web/media + depends_on: + - db + db: + image: postgres:14-alpine + ports: + - "5433:5432" + env_file: + - .env + volumes: + - pgdata:/var/lib/postgresql/data + environment: + - POSTGRES_USER=hello_django + - POSTGRES_PASSWORD=hello_django + - POSTGRES_DB=hello_django_dev +volumes: + pgdata: + media_volume: