Setup dev and prod configurations for docker

This commit is contained in:
IRBorisov 2023-08-29 00:34:56 +03:00
parent aba28f7b39
commit 31cbb6f05a
22 changed files with 356 additions and 44 deletions

View File

@ -2,20 +2,11 @@
React + Django based web portal for editing RSForm schemas.
This readme file is used mostly to document project dependencies
# Developer Setup Notes
- Install Python 3.9, NodeJS, VSCode, Docker Desktop
- copy import wheels from ConceptCore to rsconcept\backend\import
- run rsconcept\backend\LocalEnvSetup.ps1
- run 'npm install' in rsconcept\frontend
- use VSCode configs in root folder to start developement
- production: create secrets secrets\db_password.txt and django_key.txt
- production: provide TLS certificate nginx\cert\portal-cert.pem and nginx\cert\portal-key.pem
# Contributing notes
!BEFORE PUSHING INTO MAIN!
- use Test config in VSCode to run tests before pushing commits / requests
- !BEFORE PUSHING INTO MAIN! in rsconcept\frontend run in terminal 'npm run build' and fix all errors
- when making major changes make sure that Docker production is building correctly. run 'docker compose -f docker-compose-prod.yml up'
- cd rsconcept/frontend & npm run build
- docker compose -f docker-compose-prod.yml up
# Frontend stack & Tooling [Vite + React + Typescript]
<details>
@ -62,11 +53,11 @@ This readme file is used mostly to document project dependencies
<details>
<summary>requirements</summary>
<pre>
- tzdata
- django
- djangorestframework
- django-cors-headers
- django-filter
- tzdata
- gunicorn
- coreapi
- psycopg2-binary
@ -96,3 +87,32 @@ This readme file is used mostly to document project dependencies
# DevOps
- Docker compose
- PowerShell
- Certbot
- Docker VSCode extension
# Developer Notes
## Local build (Windows 10+)
- this is main developers build
- Install Python 3.9, NodeJS, VSCode, Docker Desktop
- copy import wheels from ConceptCore to rsconcept/backend/import
- run rsconcept/backend/LocalEnvSetup.ps1
- run 'npm install' in rsconcept/frontend
- use VSCode configs in root folder to start developement
## Developement build
- this build does not use HTTPS and nginx for networking
- backend and frontend debugging is supported
- hmr (hot updates) for frontend
- run via 'docker compose -f "docker-compose-dev.yml" up --build -d'
- populate initial data: rsconcept/PopulateDevData.ps1 dev-portal-backend
## Local production build
- this build is same as production except not using production secrets and working on localhost
- provide TLS certificate (can be self-signed) 'nginx/cert/local-cert.pem' and 'nginx/cert/local-key.pem'
- run via 'docker compose -f "docker-compose-prod-local.yml" up --build -d'
- populate initial data: rsconcept/PopulateDevData.ps1 local-portal-backend
## Production build
- create secrets secrets/db_password.txt and django_key.txt
- provide TLS certificate 'nginx/cert/front-cert.pem' and 'nginx/cert/front-key.pem'
- run via 'docker compose -f "docker-compose-prod.yml" up --build -d'

55
docker-compose-dev.yml Normal file
View File

@ -0,0 +1,55 @@
name: dev-concept-portal
volumes:
postgres_volume:
name: "dev-portal-data"
django_static_volume:
name: "dev-portal-static"
django_media_volume:
name: "dev-portal-media"
networks:
default:
name: dev-concept-api-net
services:
frontend:
container_name: dev-portal-frontend
restart: always
depends_on:
- backend
build:
context: ./rsconcept/frontend
dockerfile: Dockerfile.dev
args:
BUILD_TYPE: development
ports:
- 3002:3002
command: npm run dev -- --host
backend:
container_name: dev-portal-backend
restart: always
depends_on:
- postgresql-db
build:
context: ./rsconcept/backend
env_file: ./rsconcept/backend/.env.dev
ports:
- 8002:8002
volumes:
- django_static_volume:/home/app/web/static
- django_media_volume:/home/app/web/media
command:
gunicorn -w 3 project.wsgi --bind 0.0.0.0:8002
postgresql-db:
container_name: dev-portal-db
restart: always
image: postgres:alpine
env_file: ./postgresql/.env.dev
volumes:
- postgres_volume:/var/lib/postgresql/data

View File

@ -0,0 +1,71 @@
name: local-concept-portal
volumes:
postgres_volume:
name: "local-portal-data"
django_static_volume:
name: "local-portal-static"
django_media_volume:
name: "local-portal-media"
networks:
default:
name: local-concept-api-net
services:
frontend:
container_name: local-portal-frontend
restart: always
depends_on:
- backend
build:
context: ./rsconcept/frontend
args:
BUILD_TYPE: production.local
expose:
- 3001
command: serve -s /home/node -l 3001
backend:
container_name: local-portal-backend
restart: always
depends_on:
- postgresql-db
build:
context: ./rsconcept/backend
env_file: ./rsconcept/backend/.env.prod.local
expose:
- 8001
volumes:
- django_static_volume:/home/app/web/static
- django_media_volume:/home/app/web/media
command:
gunicorn -w 3 project.wsgi --bind 0.0.0.0:8001
postgresql-db:
container_name: local-portal-db
restart: always
image: postgres:alpine
env_file: ./postgresql/.env.prod.local
volumes:
- postgres_volume:/var/lib/postgresql/data
nginx:
container_name: local-portal-router
restart: always
build:
context: ./nginx
args:
BUILD_TYPE: production.local
ports:
- 8001:8001
- 3001:3001
depends_on:
- backend
command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"
volumes:
- django_static_volume:/var/www/static
- django_media_volume:/var/www/media

View File

@ -26,6 +26,8 @@ services:
- backend
build:
context: ./rsconcept/frontend
args:
BUILD_TYPE: production
expose:
- 3000
command: serve -s /home/node -l 3000
@ -72,6 +74,8 @@ services:
restart: always
build:
context: ./nginx
args:
BUILD_TYPE: production
ports:
- 8000:8000
- 3000:3000

View File

@ -1,5 +1,6 @@
FROM nginx:stable-alpine3.17-slim
ARG BUILD_TYPE=production
# Сopу nginx configuration to the proxy-server
COPY ./default.conf /etc/nginx/conf.d/default.conf
COPY ./$BUILD_TYPE.conf /etc/nginx/conf.d/default.conf
COPY ./cert/* /etc/ssl/private/

View File

@ -10,7 +10,7 @@ server {
listen 8000 ssl;
ssl_certificate /etc/ssl/private/front-cert.pem;
ssl_certificate_key /etc/ssl/private/front-key.pem;
server_name dev.concept.ru www.dev.concept.ru portal.acconcept.ru www.portal.acconcept.ru api.portal.acconcept.ru www.api.portal.acconcept.ru mail.acconcept.ru www.mail.acconcept.ru;
server_name dev.concept.ru www.dev.concept.ru portal.acconcept.ru www.portal.acconcept.ru api.portal.acconcept.ru www.api.portal.acconcept.ru;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
@ -30,7 +30,7 @@ server {
listen 3000 ssl;
ssl_certificate /etc/ssl/private/front-cert.pem;
ssl_certificate_key /etc/ssl/private/front-key.pem;
server_name dev.concept.ru www.dev.concept.ru portal.acconcept.ru www.portal.acconcept.ru mail.acconcept.ru www.mail.acconcept.ru;
server_name dev.concept.ru www.dev.concept.ru portal.acconcept.ru www.portal.acconcept.ru;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

View File

@ -0,0 +1,41 @@
upstream innerdjango {
server backend:8001;
}
upstream innerreact {
server frontend:3001;
}
server {
listen 8001 ssl;
ssl_certificate /etc/ssl/private/local-cert.pem;
ssl_certificate_key /etc/ssl/private/local-key.pem;
server_name localhost;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_pass http://innerdjango;
proxy_redirect default;
}
location /static/ {
alias /var/www/static/;
}
location /media/ {
alias /var/www/media/;
}
}
server {
listen 3001 ssl;
ssl_certificate /etc/ssl/private/local-cert.pem;
ssl_certificate_key /etc/ssl/private/local-key.pem;
server_name localhost;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_pass http://innerreact;
proxy_redirect default;
}
}

5
postgresql/.env.dev Normal file
View File

@ -0,0 +1,5 @@
# WARNING! This config does not use 'real' production values for secrets
# DO NOT use PRODUCTION LOCAL build for deployment!
POSTGRES_USER=portal-admin
POSTGRES_DB=portal-db
POSTGRES_PASSWORD=78ACF6C4F3

View File

@ -0,0 +1,5 @@
# WARNING! This config does not use 'real' production values for secrets
# DO NOT use PRODUCTION LOCAL build for deployment!
POSTGRES_USER=portal-admin
POSTGRES_DB=portal-db
POSTGRES_PASSWORD=78ACF6C4F3

View File

@ -0,0 +1,13 @@
# Initialize database !
# FOR DEVELOPEMENT BUILDS ONLY!
$container= Read-Host -Prompt "Enter backend container name: "
docker exec -it $container python manage.py loaddata fixtures/InitialData.json
docker exec `
-e DJANGO_SUPERUSER_USERNAME=admin `
-e DJANGO_SUPERUSER_PASSWORD=1234 `
-e DJANGO_SUPERUSER_EMAIL=admin@admin.com `
-it $container python manage.py createsuperuser --noinput
pause

View File

@ -0,0 +1,27 @@
# Application settings
# WARNING! This config does not use 'real' production values for secrets
# DO NOT use PRODUCTION LOCAL build for deployment!
SECRET_KEY=s-55j!5jlan=x%8-6m1qnst^7s6nwby4dx@vei)5w8t)3_=mv1
ALLOWED_HOSTS=localhost
CSRF_TRUSTED_ORIGINS=http://localhost:3002;http://localhost:8002
CORS_ALLOWED_ORIGINS=http://localhost:3002
# File locations
STATIC_ROOT=/home/app/web/static
MEDIA_ROOT=/home/app/web/media
# Database settings
DB_ENGINE=django.db.backends.postgresql_psycopg2
DB_NAME=portal-db
DB_USER=portal-admin
DB_HOST=postgresql-db
DB_PORT=5432
DB_PASSWORD=78ACF6C4F3
# Debug settings
DEBUG=1
PYTHONDEVMODE=1
PYTHONTRACEMALLOC=1

View File

@ -1,5 +1,6 @@
# Application settings
# SECRET_KEY=
ALLOWED_HOSTS=portal.acconcept.ru;dev.concept.ru
CSRF_TRUSTED_ORIGINS=https://dev.concept.ru:3000;https://dev.concept.ru:8000;https://portal.acconcept.ru;https://portal.acconcept.ru:8081;https://portal.acconcept.ru:8082
CORS_ALLOWED_ORIGINS=https://dev.concept.ru:3000;https://portal.acconcept.ru;https://portal.acconcept.ru:8081
@ -16,6 +17,7 @@ DB_NAME=portal-db
DB_USER=portal-admin
DB_HOST=postgresql-db
DB_PORT=5432
# DB_PASSWORD=
# Debug settings

View File

@ -0,0 +1,27 @@
# Application settings
# WARNING! This config does not use 'real' production values for secrets
# DO NOT use PRODUCTION LOCAL build for deployment!
SECRET_KEY=s-55j!5jlan=x%8-6m1qnst^7s6nwby4dx@vei)5w8t)3_=mv1
ALLOWED_HOSTS=localhost
CSRF_TRUSTED_ORIGINS=https://localhost:3001;https://localhost:8001
CORS_ALLOWED_ORIGINS=https://localhost:3001
# File locations
STATIC_ROOT=/home/app/web/static
MEDIA_ROOT=/home/app/web/media
# Database settings
DB_ENGINE=django.db.backends.postgresql_psycopg2
DB_NAME=portal-db
DB_USER=portal-admin
DB_HOST=postgresql-db
DB_PORT=5432
DB_PASSWORD=78ACF6C4F3
# Debug settings
DEBUG=0
PYTHONDEVMODE=0
PYTHONTRACEMALLOC=0

View File

@ -1,3 +1,4 @@
# Dev specific
.gitignore
node_modules
.env.local

View File

@ -0,0 +1,5 @@
# Local build config
VITE_PORTAL_BACKEND=http://localhost:8000
VITE_PORTAL_FRONT_PORT=3000
VITE_PORTAL_FRONT_HTTPS=false

View File

@ -5,11 +5,14 @@ RUN apt-get update -qq && \
rm -rf /var/lib/apt/lists/*
# ======= Build =======
ARG BUILD_TYPE=production
FROM node-base as builder
WORKDIR /result
COPY ./ ./
COPY ./env/.env.$BUILD_TYPE ./
RUN rm -rf ./env
RUN npm install
ENV NODE_ENV production
RUN npm run build

View File

@ -0,0 +1,17 @@
# ======== Multi-stage base ==========
FROM node:bullseye-slim as node-base
RUN apt-get update -qq && \
apt-get upgrade -y && \
rm -rf /var/lib/apt/lists/*
# ========= Server =======
FROM node-base as product-server
ARG BUILD_TYPE=production
WORKDIR /home
COPY ./ ./
COPY ./env/.env.$BUILD_TYPE ./
RUN rm -rf ./env
RUN npm install

View File

@ -0,0 +1,5 @@
# Frontend public settings: Production Local
VITE_PORTAL_BACKEND=http://localhost:8002
VITE_PORTAL_FRONT_PORT=3002
VITE_PORTAL_FRONT_HTTPS=false

View File

@ -0,0 +1,5 @@
# Frontend public settings: Production
VITE_PORTAL_BACKEND=https://portal.acconcept.ru:8082
VITE_PORTAL_FRONT_PORT=3000
VITE_PORTAL_FRONT_HTTPS=true

View File

@ -0,0 +1,6 @@
# Frontend public settings: Production Local
VITE_PORTAL_BACKEND=https://localhost:8001
VITE_PORTAL_FRONT_PORT=3001
VITE_PORTAL_FRONT_HTTPS=true

View File

@ -1,16 +1,7 @@
// Constants
const prod = {
backend: 'https://portal.acconcept.ru:8082',
// backend: 'https://dev.concept.ru:8000',
// backend: 'https://localhost:8000',
// backend: 'https://api.portal.concept.ru',
export const config = {
backend: import.meta.env.VITE_PORTAL_BACKEND as string
};
const dev = {
backend: 'http://localhost:8000',
};
export const config = process.env.NODE_ENV === 'production' ? prod : dev;
export const TIMEOUT_UI_REFRESH = 100;
export const youtube = {

View File

@ -1,5 +1,5 @@
import react from '@vitejs/plugin-react';
import { defineConfig } from 'vite';
import { defineConfig, loadEnv } from 'vite';
import { dependencies } from './package.json'
@ -14,20 +14,28 @@ function renderChunks(deps: Record<string, string>) {
}
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
server: {
port: 3000
},
build: {
chunkSizeWarningLimit: 4000, // KB
sourcemap: false,
rollupOptions: {
output: {
manualChunks: {
...renderChunks(dependencies),
export default (({ mode }: { mode: string }) => {
process.env = {...process.env, ...loadEnv(mode, process.cwd())};
const enableHttps = process.env.VITE_PORTAL_FRONT_HTTPS === 'true';
return defineConfig({
plugins: [react()],
server: {
port: Number(process.env.VITE_PORTAL_FRONT_PORT),
// NOTE: https is not used for dev builds currently
https: enableHttps,
},
build: {
chunkSizeWarningLimit: 4000, // KB
sourcemap: false,
rollupOptions: {
output: {
manualChunks: {
// Load chunks for dependencies separately
...renderChunks(dependencies),
},
},
},
},
}
})
}
});
});