From 7b144d893d0ae40c6aef34ad3d0df88007c64e8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Ram=C3=ADrez=20de=20la=20Corte?= Date: Tue, 21 Apr 2026 14:25:04 +0200 Subject: [PATCH] conf: Parametrizar settings y Docker con variables de entorno MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Permite configurar el proyecto via variables de entorno para facilitar despliegues en diferentes entornos sin modificar código. Se elimina docker-settings.py a favor de env_file en docker-compose y se reemplaza git clone por COPY en el Dockerfile con un entrypoint configurable. --- .dockerignore | 11 ++++++++ .gitignore | 2 ++ README.md | 13 ++++++--- decide/decide/settings.py | 52 ++++++++++++++++++++++++++++-------- docker/.env.decide.example | 40 +++++++++++++++++++++++++++ docker/.env.postgres.example | 1 + docker/Dockerfile | 16 +++++------ docker/docker-compose.yml | 11 +++++--- docker/docker-settings.py | 45 ------------------------------- docker/entrypoint.sh | 28 +++++++++++++++++++ 10 files changed, 147 insertions(+), 72 deletions(-) create mode 100644 .dockerignore create mode 100644 docker/.env.decide.example create mode 100644 docker/.env.postgres.example delete mode 100644 docker/docker-settings.py create mode 100644 docker/entrypoint.sh diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..03f537ede --- /dev/null +++ b/.dockerignore @@ -0,0 +1,11 @@ +.git +.github +.venv +*.pyc +__pycache__ +*.egg-info +tags + +# Docker +docker/ +!docker/entrypoint.sh diff --git a/.gitignore b/.gitignore index b823e313b..5d4e5e8f6 100644 --- a/.gitignore +++ b/.gitignore @@ -81,6 +81,8 @@ celerybeat-schedule # dotenv .env +docker/.env.* +!docker/.env.*.example # virtualenv .venv diff --git a/README.md b/README.md index 7bd6302a0..53580aea0 100644 --- a/README.md +++ b/README.md @@ -233,14 +233,21 @@ contenedores se pueden destruir sin miedo a perder datos: * decide\_db * decide\_static -Se puede editar el fichero docker-settings.py para modificar el settings -del proyecto django antes de crear las imágenes del contenedor. +La configuración se realiza mediante variables de entorno. Copiar los +ficheros de ejemplo y editarlos según sea necesario: + + $ cd docker + $ cp .env.decide.example .env.decide + $ cp .env.postgres.example .env.postgres Crear imágenes y lanzar contenedores: - $ cd docker $ docker-compose up -d +Generar ficheros estáticos (solo si es necesario): + + $ docker exec -ti decide_web ./manage.py collectstatic + Parar contenedores: $ docker-compose down diff --git a/decide/decide/settings.py b/decide/decide/settings.py index 1d22b6732..aaadc4019 100644 --- a/decide/decide/settings.py +++ b/decide/decide/settings.py @@ -12,6 +12,15 @@ import os + +def env_list(env_name, default=None): + """Get environment var and convert in python list. Example .env: APPS=x1,y2,z3""" + if default is None: + default = [] + list_vars = os.environ.get(env_name, None) + return list_vars.split(",") if list_vars else default + + # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) @@ -20,12 +29,12 @@ # See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = '^##ydkswfu0+=ofw0l#$kv^8n)0$i(qd&d&ol#p9!b$8*5%j1+' +SECRET_KEY = os.environ.get('SECRET_KEY', '^##ydkswfu0+=ofw0l#$kv^8n)0$i(qd&d&ol#p9!b$8*5%j1+') # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True +DEBUG = os.environ.get('DEBUG', 'True') == 'True' -ALLOWED_HOSTS = [] +ALLOWED_HOSTS = env_list('ALLOWED_HOSTS', []) # Application definition @@ -70,7 +79,19 @@ 'voting', ] -BASEURL = 'http://localhost:8000' +BASEURL = os.environ.get('BASEURL', 'http://localhost:8000') + +APIS = { + 'authentication': os.environ.get('API_AUTHENTICATION', BASEURL), + 'base': os.environ.get('API_BASE', BASEURL), + 'booth': os.environ.get('API_BOOTH', BASEURL), + 'census': os.environ.get('API_CENSUS', BASEURL), + 'mixnet': os.environ.get('API_MIXNET', BASEURL), + 'postproc': os.environ.get('API_POSTPROC', BASEURL), + 'store': os.environ.get('API_STORE', BASEURL), + 'visualizer': os.environ.get('API_VISUALIZER', BASEURL), + 'voting': os.environ.get('API_VOTING', BASEURL), +} MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', @@ -108,12 +129,12 @@ DATABASES = { 'default': { - 'ENGINE': 'django.db.backends.postgresql', - 'NAME': 'decide', - 'USER': 'decide', - 'PASSWORD': 'decide', - 'HOST': 'localhost', - 'PORT': '5432', + 'ENGINE': os.environ.get('DB_ENGINE', 'django.db.backends.postgresql'), + 'NAME': os.environ.get('DB_NAME', 'decide'), + 'USER': os.environ.get('DB_USER', 'decide'), + 'PASSWORD': os.environ.get('DB_PASSWORD', 'decide'), + 'HOST': os.environ.get('DB_HOST', 'localhost'), + 'PORT': os.environ.get('DB_PORT', '5432'), } } @@ -156,7 +177,16 @@ # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/2.0/howto/static-files/ -STATIC_URL = '/static/' +STATIC_URL = os.environ.get('STATIC_URL', '/static/') +STATIC_ROOT = os.environ.get('STATIC_ROOT', os.path.join(BASE_DIR, 'static')) + +MEDIA_URL = os.environ.get('MEDIA_URL', '/media/') +MEDIA_ROOT = os.environ.get('MEDIA_ROOT', os.path.join(BASE_DIR, 'media')) + +CSRF_TRUSTED_ORIGINS = env_list('CSRF_TRUSTED_ORIGINS', []) + +_secure_proxy_ssl = env_list('SECURE_PROXY_SSL_HEADER') +SECURE_PROXY_SSL_HEADER = tuple(_secure_proxy_ssl) if _secure_proxy_ssl else None # number of bits for the key, all auths should use the same number of bits KEYBITS = 256 diff --git a/docker/.env.decide.example b/docker/.env.decide.example new file mode 100644 index 000000000..9bc81dc1b --- /dev/null +++ b/docker/.env.decide.example @@ -0,0 +1,40 @@ +SECRET_KEY=^##ydkswfu0+=ofw0l#$kv^8n)0$i(qd&d&ol#p9!b$8*5%j1+ +DEBUG=True + +# Database +DB_ENGINE=django.db.backends.postgresql +DB_NAME=postgres +DB_USER=postgres +DB_PASSWORD= +DB_HOST=db +DB_PORT=5432 + +# Hosts +ALLOWED_HOSTS=* +CSRF_TRUSTED_ORIGINS=http://10.5.0.1:8000 +BASEURL=http://10.5.0.1:8000 + +# Static & Media +STATIC_URL=/static/ +STATIC_ROOT=/app/static/ +MEDIA_URL=/media/ +MEDIA_ROOT=/app/static/media/ + +# Gunicorn +GUNICORN_WORKERS=5 +GUNICORN_BIND=0.0.0.0:5000 +GUNICORN_TIMEOUT=500 + +# SSL Proxy (uncomment and set if behind a reverse proxy with SSL) +#SECURE_PROXY_SSL_HEADER=HTTP_X_FORWARDED_PROTO,https + +# APIs (default to BASEURL if not set) +#API_AUTHENTICATION=http://10.5.0.1:8000 +#API_BASE=http://10.5.0.1:8000 +#API_BOOTH=http://10.5.0.1:8000 +#API_CENSUS=http://10.5.0.1:8000 +#API_MIXNET=http://10.5.0.1:8000 +#API_POSTPROC=http://10.5.0.1:8000 +#API_STORE=http://10.5.0.1:8000 +#API_VISUALIZER=http://10.5.0.1:8000 +#API_VOTING=http://10.5.0.1:8000 diff --git a/docker/.env.postgres.example b/docker/.env.postgres.example new file mode 100644 index 000000000..c14aa52f7 --- /dev/null +++ b/docker/.env.postgres.example @@ -0,0 +1 @@ +POSTGRES_PASSWORD= diff --git a/docker/Dockerfile b/docker/Dockerfile index 1e119996c..c052a807f 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,7 +1,6 @@ from python:3.9-alpine -RUN apk add --no-cache git postgresql-dev gcc libc-dev -RUN apk add --no-cache gcc g++ make libffi-dev python3-dev build-base +RUN apk add --no-cache postgresql-dev gcc libc-dev gcc g++ make libffi-dev python3-dev build-base RUN pip install gunicorn RUN pip install psycopg2 @@ -10,14 +9,13 @@ RUN pip install ipython WORKDIR /app -RUN git clone https://github.com/decide-update-4-1/decide-update-4.1.git . +COPY docker/entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh + +COPY requirements.txt . RUN pip install -r requirements.txt +COPY . . WORKDIR /app/decide -# local settings.py -ADD docker-settings.py /app/decide/local_settings.py - -RUN ./manage.py collectstatic - -#CMD ["gunicorn", "-w 5", "decide.wsgi", "--timeout=500", "-b 0.0.0.0:5000"] +ENTRYPOINT ["/entrypoint.sh"] diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 50ff01798..88c706ba2 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -9,14 +9,15 @@ services: - db:/var/lib/postgresql/data networks: - decide - environment: - - POSTGRES_PASSWORD= + env_file: + - .env.postgres web: restart: always container_name: decide_web image: decide_web:latest - build: . - command: ash -c "python manage.py migrate && gunicorn -w 5 decide.wsgi --timeout=500 -b 0.0.0.0:5000" + build: + context: .. + dockerfile: docker/Dockerfile expose: - "5000" volumes: @@ -25,6 +26,8 @@ services: - db networks: - decide + env_file: + - .env.decide nginx: restart: always container_name: decide_nginx diff --git a/docker/docker-settings.py b/docker/docker-settings.py deleted file mode 100644 index fb0e6b5c6..000000000 --- a/docker/docker-settings.py +++ /dev/null @@ -1,45 +0,0 @@ -DEBUG = True - -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.postgresql', - 'NAME': 'postgres', - 'USER': 'postgres', - 'PASSWORD':'', - 'HOST': 'db', - 'PORT': 5432, - } -} - -STATIC_ROOT = '/app/static/' -MEDIA_ROOT = '/app/static/media/' -ALLOWED_HOSTS = ['*'] - -CSRF_TRUSTED_ORIGINS = ['http://10.5.0.1:8000'] - -# Modules in use, commented modules that you won't use -MODULES = [ - 'authentication', - 'base', - 'booth', - 'census', - 'mixnet', - 'postproc', - 'store', - 'visualizer', - 'voting', -] - -BASEURL = 'http://10.5.0.1:8000' - -APIS = { - 'authentication': 'http://10.5.0.1:8000', - 'base': 'http://10.5.0.1:8000', - 'booth': 'http://10.5.0.1:8000', - 'census': 'http://10.5.0.1:8000', - 'mixnet': 'http://10.5.0.1:8000', - 'postproc': 'http://10.5.0.1:8000', - 'store': 'http://10.5.0.1:8000', - 'visualizer': 'http://10.5.0.1:8000', - 'voting': 'http://10.5.0.1:8000', -} diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh new file mode 100644 index 000000000..73b8a36f0 --- /dev/null +++ b/docker/entrypoint.sh @@ -0,0 +1,28 @@ +#!/bin/sh +set -e + +GUNICORN_WORKERS=${GUNICORN_WORKERS:-5} +GUNICORN_BIND=${GUNICORN_BIND:-"0.0.0.0:5000"} +GUNICORN_TIMEOUT=${GUNICORN_TIMEOUT:-500} + +COMMAND=${1:-""} + +case "$COMMAND" in + start) + exec gunicorn -w "$GUNICORN_WORKERS" decide.wsgi --timeout="$GUNICORN_TIMEOUT" -b "$GUNICORN_BIND" + ;; + migrate) + exec python manage.py migrate + ;; + collectstatic) + exec python manage.py collectstatic --noinput + ;; + manage) + shift + exec python manage.py "$@" + ;; + *) + python manage.py migrate + exec gunicorn -w "$GUNICORN_WORKERS" decide.wsgi --timeout="$GUNICORN_TIMEOUT" -b "$GUNICORN_BIND" + ;; +esac