docker-ise backend
This commit is contained in:
parent
d2335c8851
commit
3a96ee1f39
7
.gitignore
vendored
7
.gitignore
vendored
|
@ -1,9 +1,9 @@
|
||||||
*.csv
|
*.csv
|
||||||
.idea/
|
.idea/
|
||||||
config.json
|
backend/api/backend/static/
|
||||||
backend/static/
|
|
||||||
*.gexf
|
*.gexf
|
||||||
whitelist.txt
|
backend/api/backend/whitelist.txt
|
||||||
|
data/
|
||||||
|
|
||||||
# Byte-compiled / optimized / DLL files
|
# Byte-compiled / optimized / DLL files
|
||||||
__pycache__/
|
__pycache__/
|
||||||
|
@ -90,6 +90,7 @@ celerybeat-schedule
|
||||||
|
|
||||||
# Environments
|
# Environments
|
||||||
.env
|
.env
|
||||||
|
.env*
|
||||||
.venv
|
.venv
|
||||||
env/
|
env/
|
||||||
venv/
|
venv/
|
||||||
|
|
12
backend/api/Dockerfile
Normal file
12
backend/api/Dockerfile
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
FROM python:3
|
||||||
|
ENV PYTHONUNBUFFERED 1
|
||||||
|
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -qqy --no-install-recommends \
|
||||||
|
postgresql-client-9.6=9.6.10-0+deb9u1
|
||||||
|
|
||||||
|
RUN mkdir /code
|
||||||
|
WORKDIR /code
|
||||||
|
COPY requirements.txt /code/
|
||||||
|
RUN pip install -r requirements.txt
|
||||||
|
COPY . /code/
|
|
@ -14,35 +14,11 @@ import os
|
||||||
import json
|
import json
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
|
|
||||||
with open(os.environ.get('FEDIVERSE_CONFIG')) as f:
|
SECRET_KEY = os.getenv("SECRET_KEY")
|
||||||
configs = json.loads(f.read())
|
|
||||||
|
|
||||||
|
|
||||||
def get_config(setting):
|
|
||||||
try:
|
|
||||||
val = configs[setting]
|
|
||||||
if val == 'True':
|
|
||||||
val = True
|
|
||||||
elif val == 'False':
|
|
||||||
val = False
|
|
||||||
return val
|
|
||||||
except KeyError:
|
|
||||||
error_msg = "ImproperlyConfigured: Set {0} environment variable".format(setting)
|
|
||||||
raise ImproperlyConfigured(error_msg)
|
|
||||||
|
|
||||||
|
|
||||||
SECRET_KEY = get_config("SECRET_KEY")
|
|
||||||
|
|
||||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
|
|
||||||
# Quick-start development settings - unsuitable for production
|
|
||||||
# See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/
|
|
||||||
|
|
||||||
ALLOWED_HOSTS = []
|
|
||||||
|
|
||||||
|
|
||||||
# Application definition
|
# Application definition
|
||||||
|
|
||||||
INSTALLED_APPS = [
|
INSTALLED_APPS = [
|
||||||
|
@ -76,7 +52,7 @@ ROOT_URLCONF = 'backend.urls'
|
||||||
TEMPLATES = [
|
TEMPLATES = [
|
||||||
{
|
{
|
||||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||||
'DIRS': [os.path.join(BASE_DIR, '../frontend/build')],
|
'DIRS': [os.path.join(BASE_DIR, '../../frontend/build')],
|
||||||
'APP_DIRS': True,
|
'APP_DIRS': True,
|
||||||
'OPTIONS': {
|
'OPTIONS': {
|
||||||
'context_processors': [
|
'context_processors': [
|
||||||
|
@ -97,10 +73,12 @@ WSGI_APPLICATION = 'backend.wsgi.application'
|
||||||
|
|
||||||
DATABASES = {
|
DATABASES = {
|
||||||
'default': {
|
'default': {
|
||||||
'ENGINE': get_config("DATABASE_ENGINE"),
|
'ENGINE': 'django.db.backends.postgresql',
|
||||||
'NAME': get_config("DATABASE_NAME"),
|
'NAME': os.getenv("POSTGRES_DB"),
|
||||||
'USER': get_config("DATABASE_USER"),
|
'USER': os.getenv("POSTGRES_USER"),
|
||||||
'PASSWORD': get_config("DATABASE_PASSWORD"),
|
'PASSWORD': os.getenv("POSTGRES_PASSWORD"),
|
||||||
|
'HOST': 'db',
|
||||||
|
'PORT': 5432,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,7 +121,7 @@ USE_TZ = False
|
||||||
|
|
||||||
STATIC_URL = '/static/'
|
STATIC_URL = '/static/'
|
||||||
STATICFILES_DIRS = [
|
STATICFILES_DIRS = [
|
||||||
os.path.join(BASE_DIR, '../frontend/build/static')
|
os.path.join(BASE_DIR, '../../frontend/build/static')
|
||||||
]
|
]
|
||||||
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
|
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
|
||||||
|
|
|
@ -2,7 +2,7 @@ from .base import *
|
||||||
|
|
||||||
DEBUG = True
|
DEBUG = True
|
||||||
|
|
||||||
ALLOWED_HOSTS += ['localhost']
|
ALLOWED_HOSTS = ['localhost']
|
||||||
|
|
||||||
CORS_ORIGIN_WHITELIST = [
|
CORS_ORIGIN_WHITELIST = [
|
||||||
'localhost:3000',
|
'localhost:3000',
|
|
@ -1,6 +1,8 @@
|
||||||
from .base import *
|
from .base import *
|
||||||
|
|
||||||
ALLOWED_HOSTS += ['fediverse.space']
|
DEBUG = False
|
||||||
|
|
||||||
|
ALLOWED_HOSTS = ['fediverse.space']
|
||||||
|
|
||||||
CORS_ORIGIN_WHITELIST = [
|
CORS_ORIGIN_WHITELIST = [
|
||||||
'fediverse.space',
|
'fediverse.space',
|
|
@ -8,9 +8,6 @@ https://docs.djangoproject.com/en/2.1/howto/deployment/wsgi/
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from django.core.wsgi import get_wsgi_application
|
from django.core.wsgi import get_wsgi_application
|
||||||
|
|
||||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings.production')
|
|
||||||
|
|
||||||
application = get_wsgi_application()
|
application = get_wsgi_application()
|
|
@ -3,9 +3,9 @@ import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')
|
|
||||||
try:
|
try:
|
||||||
from django.core.management import execute_from_command_line
|
from django.core.management import execute_from_command_line
|
||||||
|
|
||||||
except ImportError as exc:
|
except ImportError as exc:
|
||||||
raise ImportError(
|
raise ImportError(
|
||||||
"Couldn't import Django. Are you sure it's installed and "
|
"Couldn't import Django. Are you sure it's installed and "
|
|
@ -10,6 +10,7 @@ django-silk==3.0.1
|
||||||
djangorestframework==3.8.2
|
djangorestframework==3.8.2
|
||||||
future==0.16.0
|
future==0.16.0
|
||||||
gprof2dot==2016.10.13
|
gprof2dot==2016.10.13
|
||||||
|
gunicorn==19.9.0
|
||||||
idna==2.7
|
idna==2.7
|
||||||
Jinja2==2.10
|
Jinja2==2.10
|
||||||
MarkupSafe==1.0
|
MarkupSafe==1.0
|
26
backend/api/scripts/docker-entrypoint.sh
Normal file
26
backend/api/scripts/docker-entrypoint.sh
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#! /bin/bash
|
||||||
|
|
||||||
|
SLEEP_SECONDS=3
|
||||||
|
|
||||||
|
>&2 echo "Checking Postgres status..."
|
||||||
|
|
||||||
|
# https://docs.docker.com/compose/startup-order/
|
||||||
|
export PGPASSWORD=$POSTGRES_PASSWORD
|
||||||
|
until psql -h db -U "$POSTGRES_USER" -p 5432 -d "$POSTGRES_DB" -c '\q'
|
||||||
|
do
|
||||||
|
>&2 echo "Postgres is unavailable - sleeping"
|
||||||
|
sleep $SLEEP_SECONDS
|
||||||
|
done
|
||||||
|
>&2 echo "Postgres is up"
|
||||||
|
|
||||||
|
python manage.py migrate --noinput
|
||||||
|
|
||||||
|
|
||||||
|
if [[ $ENVIRONMENT == "development" ]]
|
||||||
|
then
|
||||||
|
>&2 echo "Running Django server on port 8000 for development"
|
||||||
|
python manage.py runserver 0.0.0.0:8000
|
||||||
|
else
|
||||||
|
>&2 echo "Running gunicorn server"
|
||||||
|
gunicorn backend.wsgi -c /config/gunicorn.conf.py
|
||||||
|
fi
|
0
gephi/gradlew → backend/gephi/gradlew
vendored
0
gephi/gradlew → backend/gephi/gradlew
vendored
|
@ -1,7 +0,0 @@
|
||||||
{
|
|
||||||
"SECRET_KEY": "df4p)6h(#ktn*#ckh2m^^(-)w6_9mn$b%^!+$02vnb&e3sz&!r",
|
|
||||||
"DATABASE_ENGINE": "django.db.backends.sqlite",
|
|
||||||
"DATABASE_NAME": "os.path.join(BASE_DIR, 'db.sqlite3')",
|
|
||||||
"DATABASE_USER": "",
|
|
||||||
"DATABASE_PASSWORD": ""
|
|
||||||
}
|
|
196
config/gunicorn.conf.py
Normal file
196
config/gunicorn.conf.py
Normal file
|
@ -0,0 +1,196 @@
|
||||||
|
#
|
||||||
|
# Server socket
|
||||||
|
#
|
||||||
|
# bind - The socket to bind.
|
||||||
|
#
|
||||||
|
# A string of the form: 'HOST', 'HOST:PORT', 'unix:PATH'.
|
||||||
|
# An IP is a valid HOST.
|
||||||
|
#
|
||||||
|
# backlog - The number of pending connections. This refers
|
||||||
|
# to the number of clients that can be waiting to be
|
||||||
|
# served. Exceeding this number results in the client
|
||||||
|
# getting an error when attempting to connect. It should
|
||||||
|
# only affect servers under significant load.
|
||||||
|
#
|
||||||
|
# Must be a positive integer. Generally set in the 64-2048
|
||||||
|
# range.
|
||||||
|
#
|
||||||
|
|
||||||
|
bind = ['unix:/var/gunicorn/.sock', ':8000']
|
||||||
|
|
||||||
|
#
|
||||||
|
# Worker processes
|
||||||
|
#
|
||||||
|
# workers - The number of worker processes that this server
|
||||||
|
# should keep alive for handling requests.
|
||||||
|
#
|
||||||
|
# A positive integer generally in the 2-4 x $(NUM_CORES)
|
||||||
|
# range. You'll want to vary this a bit to find the best
|
||||||
|
# for your particular application's work load.
|
||||||
|
#
|
||||||
|
# worker_class - The type of workers to use. The default
|
||||||
|
# sync class should handle most 'normal' types of work
|
||||||
|
# loads. You'll want to read
|
||||||
|
# http://docs.gunicorn.org/en/latest/design.html#choosing-a-worker-type
|
||||||
|
# for information on when you might want to choose one
|
||||||
|
# of the other worker classes.
|
||||||
|
#
|
||||||
|
# A string referring to a Python path to a subclass of
|
||||||
|
# gunicorn.workers.base.Worker. The default provided values
|
||||||
|
# can be seen at
|
||||||
|
# http://docs.gunicorn.org/en/latest/settings.html#worker-class
|
||||||
|
#
|
||||||
|
# worker_connections - For the eventlet and gevent worker classes
|
||||||
|
# this limits the maximum number of simultaneous clients that
|
||||||
|
# a single process can handle.
|
||||||
|
#
|
||||||
|
# A positive integer generally set to around 1000.
|
||||||
|
#
|
||||||
|
# timeout - If a worker does not notify the master process in this
|
||||||
|
# number of seconds it is killed and a new worker is spawned
|
||||||
|
# to replace it.
|
||||||
|
#
|
||||||
|
# Generally set to thirty seconds. Only set this noticeably
|
||||||
|
# higher if you're sure of the repercussions for sync workers.
|
||||||
|
# For the non sync workers it just means that the worker
|
||||||
|
# process is still communicating and is not tied to the length
|
||||||
|
# of time required to handle a single request.
|
||||||
|
#
|
||||||
|
# keepalive - The number of seconds to wait for the next request
|
||||||
|
# on a Keep-Alive HTTP connection.
|
||||||
|
#
|
||||||
|
# A positive integer. Generally set in the 1-5 seconds range.
|
||||||
|
#
|
||||||
|
|
||||||
|
# try:
|
||||||
|
# # fail 'successfully' if either of these modules aren't installed
|
||||||
|
# from gevent import monkey
|
||||||
|
# from psycogreen.gevent import patch_psycopg
|
||||||
|
|
||||||
|
|
||||||
|
# # setting this inside the 'try' ensures that we only
|
||||||
|
# # activate the gevent worker pool if we have gevent installed
|
||||||
|
# worker_class = 'gevent'
|
||||||
|
# workers = 4
|
||||||
|
# # this ensures forked processes are patched with gevent/gevent-psycopg2
|
||||||
|
# def do_post_fork(server, worker):
|
||||||
|
# monkey.patch_all()
|
||||||
|
# patch_psycopg()
|
||||||
|
|
||||||
|
# # you should see this text in your gunicorn logs if it was successful
|
||||||
|
# worker.log.info("Made Psycopg2 Green")
|
||||||
|
|
||||||
|
# post_fork = do_post_fork
|
||||||
|
# except ImportError:
|
||||||
|
# pass
|
||||||
|
|
||||||
|
workers = 4
|
||||||
|
# worker_connections = 1000
|
||||||
|
# timeout = 30
|
||||||
|
# keepalive = 2
|
||||||
|
|
||||||
|
#
|
||||||
|
# spew - Install a trace function that spews every line of Python
|
||||||
|
# that is executed when running the server. This is the
|
||||||
|
# nuclear option.
|
||||||
|
#
|
||||||
|
# True or False
|
||||||
|
#
|
||||||
|
|
||||||
|
spew = False
|
||||||
|
|
||||||
|
#
|
||||||
|
# Server mechanics
|
||||||
|
#
|
||||||
|
# daemon - Detach the main Gunicorn process from the controlling
|
||||||
|
# terminal with a standard fork/fork sequence.
|
||||||
|
#
|
||||||
|
# True or False
|
||||||
|
#
|
||||||
|
# pidfile - The path to a pid file to write
|
||||||
|
#
|
||||||
|
# A path string or None to not write a pid file.
|
||||||
|
#
|
||||||
|
# user - Switch worker processes to run as this user.
|
||||||
|
#
|
||||||
|
# A valid user id (as an integer) or the name of a user that
|
||||||
|
# can be retrieved with a call to pwd.getpwnam(value) or None
|
||||||
|
# to not change the worker process user.
|
||||||
|
#
|
||||||
|
# group - Switch worker process to run as this group.
|
||||||
|
#
|
||||||
|
# A valid group id (as an integer) or the name of a user that
|
||||||
|
# can be retrieved with a call to pwd.getgrnam(value) or None
|
||||||
|
# to change the worker processes group.
|
||||||
|
#
|
||||||
|
# umask - A mask for file permissions written by Gunicorn. Note that
|
||||||
|
# this affects unix socket permissions.
|
||||||
|
#
|
||||||
|
# A valid value for the os.umask(mode) call or a string
|
||||||
|
# compatible with int(value, 0) (0 means Python guesses
|
||||||
|
# the base, so values like "0", "0xFF", "0022" are valid
|
||||||
|
# for decimal, hex, and octal representations)
|
||||||
|
#
|
||||||
|
# tmp_upload_dir - A directory to store temporary request data when
|
||||||
|
# requests are read. This will most likely be disappearing soon.
|
||||||
|
#
|
||||||
|
# A path to a directory where the process owner can write. Or
|
||||||
|
# None to signal that Python should choose one on its own.
|
||||||
|
#
|
||||||
|
|
||||||
|
daemon = False
|
||||||
|
pidfile = '/var/gunicorn/.pid'
|
||||||
|
umask = 0
|
||||||
|
user = None
|
||||||
|
group = None
|
||||||
|
tmp_upload_dir = None
|
||||||
|
|
||||||
|
#
|
||||||
|
# Logging
|
||||||
|
#
|
||||||
|
# logfile - The path to a log file to write to.
|
||||||
|
#
|
||||||
|
# A path string. "-" means log to stdout.
|
||||||
|
#
|
||||||
|
# loglevel - The granularity of log output
|
||||||
|
#
|
||||||
|
# A string of "debug", "info", "warning", "error", "critical"
|
||||||
|
#
|
||||||
|
|
||||||
|
errorlog = '-'
|
||||||
|
loglevel = 'warning'
|
||||||
|
accesslog = '-'
|
||||||
|
access_log_format = '%(h)s %(t)s %(m)s %(U)s %(q)s %(H)s %(s)s %(B)s %(f)s %(a)s %(L)s'
|
||||||
|
|
||||||
|
#
|
||||||
|
# Process naming
|
||||||
|
#
|
||||||
|
# proc_name - A base to use with setproctitle to change the way
|
||||||
|
# that Gunicorn processes are reported in the system process
|
||||||
|
# table. This affects things like 'ps' and 'top'. If you're
|
||||||
|
# going to be running more than one instance of Gunicorn you'll
|
||||||
|
# probably want to set a name to tell them apart. This requires
|
||||||
|
# that you install the setproctitle module.
|
||||||
|
#
|
||||||
|
# A string or None to choose a default of something like 'gunicorn'.
|
||||||
|
#
|
||||||
|
|
||||||
|
proc_name = None
|
||||||
|
|
||||||
|
#
|
||||||
|
# Server hooks
|
||||||
|
#
|
||||||
|
# post_fork - Called just after a worker has been forked.
|
||||||
|
#
|
||||||
|
# A callable that takes a server and worker instance
|
||||||
|
# as arguments.
|
||||||
|
#
|
||||||
|
# pre_fork - Called just prior to forking the worker subprocess.
|
||||||
|
#
|
||||||
|
# A callable that accepts the same arguments as after_fork
|
||||||
|
#
|
||||||
|
# pre_exec - Called just prior to forking off a secondary
|
||||||
|
# master process during things like config reloading.
|
||||||
|
#
|
||||||
|
# A callable that takes a server instance as the sole argument.
|
||||||
|
#
|
20
config/nginx/conf.d/local.conf
Normal file
20
config/nginx/conf.d/local.conf
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
upstream app {
|
||||||
|
server unix:/var/gunicorn/.sock;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80 default_server;
|
||||||
|
server_name localhost;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
allow all;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_set_header X-Cluster-Client-Ip $remote_addr;
|
||||||
|
proxy_pass http://app;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Note that nginx doesn't serve any static files.
|
||||||
|
}
|
||||||
|
|
38
docker-compose.production.yml
Normal file
38
docker-compose.production.yml
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
version: '3'
|
||||||
|
services:
|
||||||
|
db:
|
||||||
|
restart: always
|
||||||
|
networks:
|
||||||
|
- database_network
|
||||||
|
web:
|
||||||
|
restart: always
|
||||||
|
volumes:
|
||||||
|
- gunicorn-socket:/var/gunicorn
|
||||||
|
- ./config/gunicorn.conf.py:/config/gunicorn.conf.py
|
||||||
|
networks:
|
||||||
|
- database_network
|
||||||
|
- nginx_network
|
||||||
|
environment:
|
||||||
|
- ENVIRONMENT=production
|
||||||
|
- DJANGO_SETTINGS_MODULE=backend.settings.production
|
||||||
|
nginx:
|
||||||
|
image: nginx:1.14
|
||||||
|
# build:
|
||||||
|
# context: .
|
||||||
|
# dockerfile: Dockerfile.nginx
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
volumes:
|
||||||
|
- gunicorn-socket:/var/gunicorn
|
||||||
|
- ./config/nginx/conf.d:/etc/nginx/conf.d
|
||||||
|
networks:
|
||||||
|
- nginx_network
|
||||||
|
depends_on:
|
||||||
|
- web
|
||||||
|
networks:
|
||||||
|
database_network:
|
||||||
|
driver: bridge
|
||||||
|
nginx_network:
|
||||||
|
driver: bridge
|
||||||
|
volumes:
|
||||||
|
gunicorn-socket:
|
31
docker-compose.yml
Normal file
31
docker-compose.yml
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
version: '3'
|
||||||
|
services:
|
||||||
|
db:
|
||||||
|
image: postgres
|
||||||
|
environment:
|
||||||
|
# Set these in .env
|
||||||
|
- POSTGRES_USER
|
||||||
|
- POSTGRES_PASSWORD
|
||||||
|
- POSTGRES_DB
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
||||||
|
volumes:
|
||||||
|
- pgdata:/var/lib/postgresql/data
|
||||||
|
web:
|
||||||
|
environment:
|
||||||
|
# Set these in .env
|
||||||
|
- SECRET_KEY
|
||||||
|
- POSTGRES_USER
|
||||||
|
- POSTGRES_PASSWORD
|
||||||
|
- POSTGRES_DB
|
||||||
|
- DJANGO_SETTINGS_MODULE
|
||||||
|
build: ./backend/api
|
||||||
|
command: bash scripts/docker-entrypoint.sh
|
||||||
|
volumes:
|
||||||
|
- ./backend/api:/code
|
||||||
|
ports:
|
||||||
|
- "8000:8000"
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
volumes:
|
||||||
|
pgdata:
|
5
example.env
Normal file
5
example.env
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
SECRET_KEY=a-long-secret-key
|
||||||
|
POSTGRES_USER=postgres
|
||||||
|
POSTGRES_PASSWORD=postgres
|
||||||
|
POSTGRES_DB=fediverse
|
||||||
|
DJANGO_SETTINGS_MODULE=backend.settings.dev
|
Loading…
Reference in a new issue