diff --git a/.env.dev b/.env.dev new file mode 100644 index 0000000..7856d53 --- /dev/null +++ b/.env.dev @@ -0,0 +1,7 @@ +SQLALCHEMY_DATABASE_URI=postgresql+psycopg2://postgres:postgres@db/flashlearn +SQL_HOST=db +SQL_PORT=5432 +DATABASE=postgres +POSTGRES_USER=postgres +POSTGRES_PASSWORD=postgres +POSTGRES_DB=flashlearn diff --git a/.gitignore b/.gitignore index 6e0233b..d8a13b3 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,6 @@ htmlcov *.sqlite3 .vscode .pytest_cache +postgres-data +.env.prod +.env.prod.db diff --git a/Dockerfile b/Dockerfile index 413becc..c1953b2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,6 +2,8 @@ FROM python:3.8-slim-buster ENV FLASK_RUN_HOST=0.0.0.0 WORKDIR /flashlearn +RUN apt-get update && apt-get -y install libpq-dev gcc netcat + COPY requirements.txt requirements.txt RUN pip3 install -r requirements.txt diff --git a/docker-compose.yml b/docker-compose.yml index c802153..36e9ce4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,9 +2,39 @@ version: "3.9" services: web: build: . + env_file: + - ./.env.prod + depends_on: + - db + expose: + - 5000 ports: - - "5000:5000" + - 5000:5000 volumes: - - .:/web + - .:/web redis: image: redis + db: + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: flashlearn + image: postgres:latest + networks: + - default + ports: + - 5405:5432 + env_file: + - ./.env.prod + volumes: + - ./postgres-data:/var/lib/postgresql/data + nginx: + build: ./nginx + ports: + - 1337:80 + depends_on: + - web + +volumes: + postgres-data: + external: true diff --git a/entrypoint.sh b/entrypoint.sh index a8a2f2f..bcb6c14 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -1,3 +1,17 @@ #!/usr/bin/env bash + +if [ "$DATABASE" = "postgres" ] +then + echo "Waiting for postgres..." + + while ! nc -z $SQL_HOST $SQL_PORT; do + sleep 0.1 + done + + echo "PostgreSQL started" +fi + python -m flask db upgrade -python -m flask run --host=0.0.0.0 +gunicorn --bind 0.0.0.0:5000 wsgi:app + +exec "$@" diff --git a/instance/config.py b/instance/config.py index 5a2c55e..510a89e 100644 --- a/instance/config.py +++ b/instance/config.py @@ -4,7 +4,6 @@ BASE_DIR = os.path.abspath(os.path.dirname(__file__)) ROOT_DIR = os.path.abspath(os.path.dirname(BASE_DIR)) - WIN = sys.platform.startswith("win") if WIN: prefix = "sqlite:///" @@ -22,7 +21,10 @@ class BaseConfig: USE_REDIS_CACHE = False CSRF_ENABLED = True FLASK_APP = "flashlearn" - SQLALCHEMY_DATABASE_URI = os.getenv("SQLALCHEMY_DATABASE_URI") + sqlite_db_path = os.path.join(BASE_DIR, "dev_db.sqlite3") + SQLALCHEMY_DATABASE_URI = os.getenv( + "SQLALCHEMY_DATABASE_URI", f"{prefix}{sqlite_db_path}" + ) SQLALCHEMY_TRACK_MODIFICATIONS = True LOG_FILE = os.getenv("LOG_FILE") or os.path.join(ROOT_DIR, "flashlearn.log") LOG_LEVEL = 20 @@ -32,8 +34,6 @@ class DevelopmentConfig(BaseConfig): """Development config class""" DEBUG = True - db_path = os.path.join(BASE_DIR, "dev_db.sqlite3") - SQLALCHEMY_DATABASE_URI = f"{prefix}{db_path}" class TestingConfig(BaseConfig): @@ -52,8 +52,6 @@ class ProductionConfig(BaseConfig): DEBUG = False TESTING = False - db_path = os.path.join(BASE_DIR, "dev_db.sqlite3") - SQLALCHEMY_DATABASE_URI = f"{prefix}{db_path}" # Replace with production database.. app_config = { diff --git a/nginx/Dockerfile b/nginx/Dockerfile new file mode 100644 index 0000000..964bab1 --- /dev/null +++ b/nginx/Dockerfile @@ -0,0 +1,6 @@ +FROM nginx:1.17-alpine + +RUN rm /etc/nginx/nginx.conf +COPY ./nginx.conf /etc/nginx/ +RUN rm /etc/nginx/conf.d/default.conf +COPY ./nginx.conf /etc/nginx/conf.d/ diff --git a/nginx/nginx.conf b/nginx/nginx.conf new file mode 100644 index 0000000..19602dd --- /dev/null +++ b/nginx/nginx.conf @@ -0,0 +1,25 @@ +upstream web { + server web:5000; + server localhost:5000; + server 127.0.0.1:5000; +} + +server { + + listen 80; + server_name flashlearn_nginx; + + location / { + proxy_pass http://web/; + + # Do not change this + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + + location /static { + rewrite ^/static(.*) /$1 break; + root /static; + } +} diff --git a/requirements.txt b/requirements.txt index fb54057..88170f3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -60,3 +60,67 @@ wrapt==1.12.1 WTForms==2.3.3 yarg==0.1.9 zipp==3.1.0 +alembic==1.4.3 +appdirs==1.4.4 +astroid==2.4.2 +atomicwrites==1.4.0 +attrs==19.3.0 +bcrypt==3.1.7 +black==20.8b1 +certifi==2020.6.20 +cffi==1.14.0 +chardet==3.0.4 +click==7.1.2 +colorama==0.4.3 +coverage==5.2.1 +docopt==0.6.2 +flake8==3.8.3 +Flask==1.1.2 +Flask-Bcrypt==0.7.1 +Flask-Caching==1.10.0 +Flask-Migrate==2.5.3 +Flask-SQLAlchemy==2.4.4 +Flask-WTF==0.14.3 +gunicorn==20.1.0 +idna==2.10 +importlib-metadata==1.7.0 +iniconfig==1.0.1 +isort==5.5.0 +itsdangerous==1.1.0 +Jinja2==2.11.3 +lazy-object-proxy==1.4.3 +Mako==1.1.3 +MarkupSafe==1.1.1 +mccabe==0.6.1 +more-itertools==8.4.0 +mypy-extensions==0.4.3 +packaging==20.4 +pathspec==0.8.0 +pluggy==0.13.1 +psycopg2==2.8.6 +py==1.10.0 +pycodestyle==2.6.0 +pycparser==2.20 +pyflakes==2.2.0 +pylint==2.6.0 +pyparsing==2.4.7 +pytest==6.0.1 +pytest-cov==2.10.0 +python-dateutil==2.8.1 +python-dotenv==0.14.0 +python-editor==1.0.4 +redis==3.5.3 +regex==2020.7.14 +requests==2.24.0 +six==1.15.0 +SQLAlchemy==1.3.18 +toml==0.10.1 +typed-ast==1.4.1 +typing-extensions==3.7.4.3 +urllib3==1.25.11 +wcwidth==0.2.5 +Werkzeug==1.0.1 +wrapt==1.12.1 +WTForms==2.3.3 +yarg==0.1.9 +zipp==3.1.0 diff --git a/wsgi.py b/wsgi.py new file mode 100644 index 0000000..4669a1f --- /dev/null +++ b/wsgi.py @@ -0,0 +1,10 @@ +import sys +import logging +from flashlearn import create_app + +logging.basicConfig(stream=sys.stderr) +sys.path.insert(0, "/var/www/") +app = create_app() + +if __name__ == "__main__": + app.run()