diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a519a52 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,32 @@ +ARG PYTHON_VERSION=3.6 +FROM python:${PYTHON_VERSION}-alpine as base +RUN apk update && \ + apk add \ + --no-cache \ + --virtual \ + .build-deps \ + gcc musl-dev \ + postgresql-dev \ + libxml2-dev \ + libxslt-dev \ + libxslt-dev \ + postgresql-libs + +FROM base as build +WORKDIR /wheels +COPY requirements/* ./ +ARG ENV=production +RUN pip install -U pip \ + && pip wheel -r ./${ENV}.txt + +FROM base as final +ARG APP_DIR=/app +WORKDIR $APP_DIR +COPY --from=build /wheels /wheels +ARG ENV=production +RUN pip install -U pip \ + && pip install -r /wheels/${ENV}.txt \ + -f /wheels \ + && rm -rf /wheels \ + && rm -rf /root/.cache/pip/* +COPY . . diff --git a/docker-compose.yml b/docker-compose.yml index 05abb4f..55137ae 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,15 +1,22 @@ --- -version: "3" +version: "2.4" services: - db: + postgres: image: postgres:9.5 volumes: - db-data:/var/lib/postgresql ports: - "5432:5432" + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 10s + timeout: 5s + retries: 5 environment: - POSTGRES_USER: libreborme + POSTGRES_USER: &db_user libreborme + POSTGRES_PASSWORD: &db_pass libreborme + POSTGRES_DB: &db_name libreborme elasticsearch: image: docker.elastic.co/elasticsearch/elasticsearch:5.6.9 @@ -18,16 +25,52 @@ services: environment: discovery.type: single-node xpack.security.enabled: "false" + + django_base: &django + image: libreborme + build: + context: . + dockerfile: Dockerfile + args: + PYTHON_VERSION: 3.6 + ENV: production + APP_DIR: /app + target: final + depends_on: + postgres: + condition: service_healthy + elasticsearch: + condition: service_started + environment: + DATABASES_DEFAULT_NAME: *db_name + DATABASES_DEFAULT_USER: *db_user + DATABASES_DEFAULT_PASSWORD: *db_pass + DATABASES_DEFAULT_HOST: postgres + DATABASES_DEFAULT_PORT: 5432 + ELASTICSEARCH_URI: http://elastic:changeme@elasticsearch:9200 + ALLOWED_HOSTS: "127.0.0.1,localhost" + + django_init: + <<: *django + command: + - sh + - -c + - "python manage.py migrate; python manage.py loaddata libreborme/fixtures/config.json; echo yes |python manage.py collectstatic" -# django: -# build: docker/Dockerfile -# ports: -# - "8000:8000" -# links: -# - db -# environment: -# - ENV_TYPE: development + django: + <<: *django + ports: + - "8000:8000" + healthcheck: + test: "/usr/bin/wget --quiet --tries=1 --spider http://localhost:8000/healthz/ || exit 1" + interval: 10s + timeout: 5s + retries: 5 + command: + - python + - manage.py + - runserver + - 0.0.0.0:8000 volumes: db-data: - es-data: diff --git a/libreborme/settings.py b/libreborme/settings.py index 4e6a01c..3681ad6 100644 --- a/libreborme/settings.py +++ b/libreborme/settings.py @@ -9,20 +9,23 @@ """ # Build paths inside the project like this: os.path.join(BASE_DIR, ...) -import os -BASE_DIR = os.path.dirname(os.path.dirname(__file__)) +from os import environ, path +from dotenv import load_dotenv + +load_dotenv() + +BASE_DIR = path.dirname(path.dirname(__file__)) # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/1.6/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = '41+h()yq5-!*=)sh+_%4wal8=+*e)dlrau*81odpu7n&9^7d5h' +SECRET_KEY = environ.get('SECRET_KEY', '41+h()yq5-!*=)sh+_%4wal8=+*e)dlrau*81odpu7n&9^7d5h') # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True - -ALLOWED_HOSTS = ['127.0.0.1', 'libreborme.net', 'librebor.me'] +DEBUG = environ.get("DEBUG", "True").upper() == "TRUE" +ALLOWED_HOSTS = environ.get("ALLOWED_HOSTS", "127.0.0.1, libreborme.net, librebor.me").split(",") # Application definition @@ -34,6 +37,10 @@ 'django.contrib.messages', 'django.contrib.postgres', 'django.contrib.staticfiles', + + 'health_check', + 'health_check.db', + 'bootstrap', 'django_static_jquery', 'fontawesome', @@ -91,13 +98,13 @@ # ) -ROOT_URLCONF = 'libreborme.urls' +ROOT_URLCONF = environ.get("ROOT_URLCONF", "libreborme.urls") TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], - 'APP_DIRS': True, + "BACKEND": environ.get("TEMPLATES_BACKEND", "django.template.backends.django.DjangoTemplates"), + "DIRS": [dir for dir in environ.get("TEMPLATES_DIRS", "").split(",") if dir], + "APP_DIRS": environ.get("TEMPLATES_APP_DIRS", "True").upper() == "TRUE", 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', @@ -111,7 +118,7 @@ }, ] -WSGI_APPLICATION = 'libreborme.wsgi.application' +WSGI_APPLICATION = environ.get("WSGI_APPLICATION", "libreborme.wsgi.application") # DEBUG # DEBUG_TOOLBAR_CONFIG{'JQUERY_URL': '//ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js'} @@ -120,69 +127,73 @@ # https://docs.djangoproject.com/en/1.6/ref/settings/#databases DATABASES = { 'default': { - 'ENGINE': 'django.db.backends.postgresql_psycopg2', - 'NAME': 'libreborme', - 'USER': 'libreborme', - 'PASSWORD': 'password', - 'HOST': 'localhost', - 'PORT': '', + "ENGINE": environ.get("DATABASES_DEFAULT_ENGINE", "django.db.backends.postgresql_psycopg2"), + "NAME": environ.get("DATABASES_DEFAULT_NAME", "libreborme"), + "USER": environ.get("DATABASES_DEFAULT_USER", "libreborme"), + "PASSWORD": environ.get("DATABASES_DEFAULT_PASSWORD", "password"), + "HOST": environ.get("DATABASES_DEFAULT_HOST", "localhost"), + "PORT": environ.get("DATABASES_DEFAULT_PORT", ""), } } -ELASTICSEARCH_URI = "http://elastic:changeme@localhost:9200" +ELASTICSEARCH_URI = environ.get("ELASTICSEARCH_URI", "http://elastic:changeme@localhost:9200") ELASTICSEARCH_DSL = { 'default': { - 'hosts': ELASTICSEARCH_URI.split('http://')[1] + "hosts": environ.get("ELASTICSEARCH_DSL_DEFAULT_HOSTS", ELASTICSEARCH_URI.split('http://')[1]) }, } # ELASTICSEARCH_DSL_AUTOSYNC = False # ELASTICSEARCH_DSL_AUTO_REFRESH = False -TASTYPIE_DEFAULT_FORMATS = ['json'] +TASTYPIE_DEFAULT_FORMATS = environ.get("TASTYPIE_DEFAULT_FORMATS", "json").split(",") # Internationalization # https://docs.djangoproject.com/en/1.6/topics/i18n/ -LANGUAGE_CODE = 'es' +LANGUAGE_CODE = environ.get("LANGUAGE_CODE", "es") -TIME_ZONE = 'Europe/Madrid' +TIME_ZONE = environ.get("TIME_ZONE", "Europe/Madrid") -USE_I18N = True +USE_I18N = environ.get("USE_I18N", "True").upper() == "TRUE" -USE_L10N = True +USE_L10N = environ.get("USE_L10N", "True").upper() == "TRUE" -USE_TZ = True +USE_TZ = environ.get("USE_TZ", "True").upper() == "TRUE" # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/1.6/howto/static-files/ -STATIC_URL = '/static/' +STATIC_URL = environ.get("STATIC_URL", "/static/") -PIWIK_URL = '' -PIWIK_SITE_ID = '' +PIWIK_URL = environ.get("PIWIK_URL", "") +PIWIK_SITE_ID = environ.get("PIWIK_SITE_ID", "") # NĂºmero de elementos a mostrar en las tablas de cargos -CARGOS_LIMIT = 20 +CARGOS_LIMIT = int(environ.get("CARGOS_LIMIT", "20")) # BORME -BORME_ROOT = os.path.expanduser('~/.bormes') -BORME_PDF_ROOT = os.path.join(BORME_ROOT, 'pdf') -BORME_XML_ROOT = os.path.join(BORME_ROOT, 'xml') -BORME_JSON_ROOT = os.path.join(BORME_ROOT, 'json') +BORME_ROOT = environ.get("BORME_ROOT", path.expanduser('~/.bormes')) +BORME_PDF_ROOT = environ.get("BORME_PDF_ROOT", path.join(BORME_ROOT, 'pdf')) +BORME_XML_ROOT = environ.get("BORME_XML_ROOT", path.join(BORME_ROOT, 'xml')) +BORME_JSON_ROOT = environ.get("BORME_JSON_ROOT", path.join(BORME_ROOT, 'json')) + +STATIC_ROOT = environ.get("STATIC_ROOT", "/app/libreborme/static") -BORME_LOG_ROOT = os.path.join(BASE_DIR, '..', 'log') +BORME_LOG_ROOT = environ.get("BORME_LOG_ROOT", path.join(BASE_DIR, '..', 'log')) -EMAIL_CONTACT = 'contact@domain' +EMAIL_CONTACT = environ.get("EMAIL_CONTACT", "contact@domain") -LOPD = {'provider': 'Some real name', - 'id': 'Some real state issued ID number', - 'domain': 'The domain that hosts this website', - 'email': EMAIL_CONTACT, - 'address': 'Some real address'} +LOPD = { + "provider": environ.get("LOPD_PROVIDER", "Some real name"), + "id": environ.get("LOPD_ID", "Some real state issued ID number"), + "domain": environ.get("LOPD_DOMAIN", "The domain that hosts this website"), + "email": environ.get("LOPD_EMAIL", EMAIL_CONTACT), + "address": environ.get("LOPD_ADDRESS", "Some real address"), +} -HOST_BUCKET = "https://libreborme-prod.ams3.digitaloceanspaces.com" +HOST_BUCKET = environ.get("HOST_BUCKET", "https://libreborme-prod.ams3.digitaloceanspaces.com") -INTERNAL_IPS = ('127.0.0.1') -LOGIN_URL = '/admin/login/' +INTERNAL_IPS = environ.get("INTERNAL_IPS", "127.0.0.1").split(",") +LOGIN_URL = environ.get("LOGIN_URL", "/admin/login/") diff --git a/libreborme/urls.py b/libreborme/urls.py index f656062..8a34b35 100644 --- a/libreborme/urls.py +++ b/libreborme/urls.py @@ -13,6 +13,8 @@ path('robots.txt', views.robotstxt), path('humans.txt', t(template_name='humans.txt', content_type='text/plain')), + path('healthz/', include('health_check.urls')), + path('about/', views.AboutView.as_view(), name='about'), path('aviso-legal/', views.AvisoLegalView.as_view(), name='aviso_legal'), path('contact/', t(template_name="libreborme/contact.html"), name='contact'), diff --git a/requirements/base.txt b/requirements/base.txt index 251aa0a..427f192 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -1,4 +1,4 @@ -bormeparser==0.3.1 +bormeparser>=0.4.0 Django==2.0.3 django-bootstrap-form==3.2.1 django-bootstrap-static==3.3.7.2 @@ -6,6 +6,9 @@ django-elasticsearch-dsl==0.5.0 django-maintenancemode==0.11.2 django-static-jquery==2.1.4 django-tastypie==0.14.1 +django-debug-toolbar elasticsearch==5.5.2 elasticsearch-dsl==5.4.0 psycopg2-binary==2.7.4 +python-dotenv==0.12.0 +django-health-check==3.12.1