From ef37dab5068134aa7caef213635671719ed167b7 Mon Sep 17 00:00:00 2001 From: Ivan Procaccini <ivanprocaccini905@gmail.com> Date: Tue, 30 Aug 2022 15:24:09 +0100 Subject: [PATCH] Build: Add production compose, nginx files and pipeline deployment jobs --- .gitlab-ci.yml | 61 +++++++++++++++++++++++++++++++++++++++++++++- app/config.py | 8 +++--- docker-compose.yml | 29 ++++++++++++++++++++++ nginx/Dockerfile | 12 +++++++++ nginx/ssl.conf | 39 +++++++++++++++++++++++++++++ 5 files changed, 143 insertions(+), 6 deletions(-) create mode 100644 docker-compose.yml create mode 100644 nginx/Dockerfile create mode 100644 nginx/ssl.conf diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 94d4c6a..caf5b58 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -2,6 +2,7 @@ stages: - lint - test - build + - deploy before_script: - apt-get update @@ -65,7 +66,40 @@ unit_test: coverage_format: cobertura path: coverage.xml -build_image: +build nginx image: + image: docker:latest + stage: building + interruptible: true + except: + changes: + - "**/README.md" + only: + - rewrite + variables: + DOCKER_TLS_CERTDIR: "/certs" + GIT_SUBMODULE_STRATEGY: recursive + CERTIFICATE: $CERT_CHAIN_PEM + PRIVATE_KEY: $CERT_PRIV_KEY + tags: + - docker + services: + - docker:dind + before_script: [] + script: + - > + docker build + --tag $CI_REGISTRY_IMAGE-nginx:latest + --build-arg certificate="$CERTIFICATE" + --build-arg private_key="$PRIVATE_KEY" + --cache-from $CI_REGISTRY_IMAGE-nginx:latest + --file nginx/Dockerfile + . + - docker tag $CI_REGISTRY_IMAGE-nginx:latest $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME-nginx + - docker login -u $CI_DEPLOY_USER -p $CI_DEPLOY_PASSWORD $CI_REGISTRY + - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME-nginx + + +build app image: stage: build except: refs: @@ -92,3 +126,28 @@ build_image: - docker tag $CI_REGISTRY_IMAGE:latest $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME - docker login -u $CI_DEPLOY_USER -p $CI_DEPLOY_PASSWORD $CI_REGISTRY - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME + + +deploy prod: + stage: deploy + variables: + SECRET_KEY: $SECRET_KEY + POSTGRES_DB: $POSTGRES_DB + POSTGRES_USER: $POSTGRES_USER + POSTGRES_PASSWORD: $POSTGRES_PASSWORD + except: + changes: + - README.md + only: + - master + before_script: [] + script: + - docker login -u $CI_DEPLOY_USER -p $CI_DEPLOY_PASSWORD $CI_REGISTRY + - docker stack deploy -c docker-compose.yml project-allocator --with-registry-auth + - docker exec $(docker ps -qf "name=web" | head -n1) flask db upgrade + tags: + - deploy-prod + environment: + name: production + url: https://project-allocator.doc.ic.ac.uk + diff --git a/app/config.py b/app/config.py index baa96da..2cdd176 100644 --- a/app/config.py +++ b/app/config.py @@ -6,7 +6,6 @@ class BaseConfig: # Secret Keys =============================================== SECRET_KEY = os.environ.get("SECRET_KEY", "dev_secret_key") - WTF_CSRF_SECRET_KEY = os.environ.get("WTF_CSRF_SECRET_KEY", "dev_wtf_secret_key") # LDAP Service ============================================== LDAP_URL = "ldaps://ldaps-vip.cc.ic.ac.uk:636" @@ -14,17 +13,16 @@ class BaseConfig: # Database =================================================== SQLALCHEMY_TRACK_MODIFICATIONS = True + SQLALCHEMY_DATABASE_URI = os.environ.get("DB_OVERRIDE", "sqlite:///dev.db") class DevConfig(BaseConfig): - SQLALCHEMY_DATABASE_URI = os.environ.get("DB_OVERRIDE", "sqlite:///dev.db") DEBUG = True class StagingConfig(BaseConfig): - SQLALCHEMY_DATABASE_URI = "sqlite:///staging.db" + pass class ProductionConfig(BaseConfig): - # This one should be changed to a postgres db - SQLALCHEMY_DATABASE_URI = "sqlite:///production.db" + SQLALCHEMY_DATABASE_URI = os.environ["DB_URL"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..37a68e4 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,29 @@ +version: "3.9" + +services: + db: + image: postgres + environment: + - POSTGRES_USER + - POSTGRES_PASSWORD + - POSTGRES_DB + volumes: + - postgres_data:/var/lib/postgresql/data + web: + image: ${CI_REGISTRY_IMAGE}:${CI_COMMIT_REF_NAME} + environment: + - ENV=production + - SECRET_KEY + - DB_URL=postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@db/$POSTGRES_DB + depends_on: + - db + reverse_proxy: + image: ${CI_REGISTRY_IMAGE}:${CI_COMMIT_REF_NAME}-nginx + ports: + - "80:80" + - "443:443" + depends_on: + - web + +volumes: + postgres_data: diff --git a/nginx/Dockerfile b/nginx/Dockerfile new file mode 100644 index 0000000..03a50f5 --- /dev/null +++ b/nginx/Dockerfile @@ -0,0 +1,12 @@ +FROM nginx +ARG certificate +ARG private_key + +# Copy configuration +COPY ./nginx/ssl.conf /etc/nginx/conf.d/project-allocator.doc.ic.ac.uk.conf +RUN mkdir /etc/nginx/certs +RUN echo $certificate | sed 's/ CERTIFICATE/xCERTIFICATE/g;s/ /\n/g;s/xCERTIFICATE/ CERTIFICATE/g' > /etc/nginx/certs/fullchain.pem +RUN echo $private_key | sed 's/ PRIVATE KEY/xPRIVATExKEY/g;s/ /\n/g;s/xPRIVATExKEY/ PRIVATE KEY/g' > /etc/nginx/certs/privkey.key + + + diff --git a/nginx/ssl.conf b/nginx/ssl.conf new file mode 100644 index 0000000..5aebbdb --- /dev/null +++ b/nginx/ssl.conf @@ -0,0 +1,39 @@ +# /etc/nginx/sites-available/project-allocator.doc.ic.ac.uk + +error_log stderr; +access_log /dev/stdout; +proxy_connect_timeout 500; +proxy_send_timeout 500; +proxy_read_timeout 500; +send_timeout 500; + +server { + listen 80; + server_name project-allocator.doc.ic.ac.uk; + return 301 https://$server_name$request_uri; +} + +server { + listen 443 ssl; + server_name project-allocator.doc.ic.ac.uk; + + client_max_body_size 200M; + + ssl_certificate /etc/nginx/certs/fullchain.pem; + ssl_certificate_key /etc/nginx/certs/privkey.key; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_ciphers HIGH:!aNULL:!MD5; + ssl_prefer_server_ciphers on; + + + location / { + # Pass the request to Gunicorn + proxy_pass http://127.0.0.1:8000; + + # Set HTTP headers st our app knows where request came from + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + add_header X-Frame-Options "DENY"; + } +} -- GitLab