diff --git a/.gitignore b/.gitignore index e9a0324f..822575d7 100644 --- a/.gitignore +++ b/.gitignore @@ -54,21 +54,18 @@ db.db #*.out *.sqlite3 .DS_Store -log/ -static/release/css -static/release/js -static/release/img -static/src/upload_image/* build.txt tmp/ -test_case/ -release/ -upload/ custom_settings.py -docker-compose.yml *.zip -rsyncd.passwd -node_modules/ -update.sh -ssh.sh +data/log/* +!data/log/.gitkeep +data/testcase/* +!data/testcase/.gitkeep +data/ssl/* +!data/ssl/.gitkeep +data/static/upload/* +!data/static/upload/.gitkeep +data/static/avatar/* +!data/static/avatar/default.png diff --git a/data/log/.gitkeep b/data/log/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/data/public/avatar/default.png b/data/public/avatar/default.png new file mode 100644 index 00000000..97f34956 Binary files /dev/null and b/data/public/avatar/default.png differ diff --git a/data/public/upload/.gitkeep b/data/public/upload/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/data/ssl/.gitkeep b/data/ssl/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/data/testcase/.gitkeep b/data/testcase/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/deploy/Dockerfile b/deploy/Dockerfile index 55af5225..d7416a20 100644 --- a/deploy/Dockerfile +++ b/deploy/Dockerfile @@ -3,11 +3,10 @@ FROM python:3.6-alpine3.6 ENV OJ_ENV production RUN apk add --no-cache supervisor jpeg-dev zlib-dev postgresql-dev freetype-dev -ADD requirements.txt /tmp -RUN apk add --no-cache build-base && \ +ADD deploy/requirements.txt /tmp +RUN apk add --update --no-cache build-base nginx openssl && \ pip install --no-cache-dir -r /tmp/requirements.txt -i https://pypi.doubanio.com/simple && \ apk del build-base --purge -VOLUME [ "/app" ] - +ADD . /app CMD sh /app/deploy/run.sh diff --git a/deploy/oj.conf b/deploy/oj.conf new file mode 100644 index 00000000..504de814 --- /dev/null +++ b/deploy/oj.conf @@ -0,0 +1,62 @@ +user nobody; +daemon off; +pid /tmp/nginx.pid; +worker_processes auto; +pcre_jit on; +error_log /data/log/nginx_error.log warn; + +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + server_tokens off; + keepalive_timeout 65; + sendfile on; + tcp_nodelay on; + + gzip on; + gzip_vary on; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /app/data/log/nginx_access.log main; + + upstream backend { + server 127.0.0.1:8080; + keepalive 32; + } + + server { + listen 8000 default_server; + server_name _; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $http_host; + client_max_body_size 200M; + + location /public { + root /app/data; + } + + location /api { + proxy_pass http://backend; + proxy_set_header Host $host; + } + + location /admin { + root /app/dist/admin; + try_files $uri $uri/ /index.html =404; + } + + location / { + root /app/dist; + try_files $uri $uri/ /index.html =404; + } + } + +} + diff --git a/deploy/run.sh b/deploy/run.sh index c8ca9d58..64a13b51 100644 --- a/deploy/run.sh +++ b/deploy/run.sh @@ -1,39 +1,28 @@ #!/bin/bash BASE=/app +DATA=$BASE/data -if [ ! -f "$BASE/custom_settings.py" ]; then - echo SECRET_KEY=\"$(cat /dev/urandom | head -1 | md5sum | head -c 32)\" >> /app/oj/custom_settings.py +if [ ! -f "$BASE/oj/custom_settings.py" ]; then + echo SECRET_KEY=\"$(cat /dev/urandom | head -1 | md5sum | head -c 32)\" >> $BASE/oj/custom_settings.py fi -if [ ! -d "$BASE/log" ]; then - mkdir -p $BASE/log -fi +mkdir -p $DATA/log $DATA/testcase $DATA/public/upload cd $BASE -find . -name "*.pyc" -delete - -# wait for postgresql start -sleep 6 n=0 -while [ $n -lt 3 ] +while [ $n -lt 5 ] do -python manage.py migrate -if [ $? -ne 0 ]; then - echo "Can't start server, try again in 3 seconds.." - sleep 3 - let "n+=1" - continue -fi -python manage.py initinstall -break + python manage.py migrate --no-input && + python manage.py initinstall && + break + n=$(($n+1)) + echo "Failed to migrate, going to retry..." + sleep 8 done -if [ $n -eq 3 ]; then - echo "Can't start server, please check log file for details." - exit 1 -fi +cp $BASE/deploy/oj.conf /etc/nginx/conf.d/default.conf -chown -R nobody:nogroup /data/log /data/test_case /data/avatar /data/upload +chown -R nobody:nogroup $DATA $BASE/dist exec supervisord -c /app/deploy/supervisor.conf diff --git a/deploy/supervisor.conf b/deploy/supervisor.conf index fc248d80..f36cf836 100644 --- a/deploy/supervisor.conf +++ b/deploy/supervisor.conf @@ -1,20 +1,32 @@ [supervisord] -logfile=/app/log/supervisord.log +logfile=/app/data/log/supervisord.log logfile_maxbytes=10MB logfile_backups=10 loglevel=info pidfile=/tmp/supervisord.pid nodaemon=true -childlogdir=/data/log/ +childlogdir=/app/data/log/ [supervisorctl] serverurl=unix:///tmp/supervisor.sock -[program:gunicorn] -command=sh -c "gunicorn oj.wsgi --user nobody -b 0.0.0.0:8080 --reload -w `grep -c ^processor /proc/cpuinfo`" +[program:nginx] +command=nginx -c /app/deploy/oj.conf directory=/app/ -stdout_logfile=/data/log/gunicorn.log -stderr_logfile=/data/log/gunicorn.log +stdout_logfile=/app/data/log/nginx.log +stderr_logfile=/app/data/log/nginx.log +autostart=true +autorestart=true +startsecs=5 +stopwaitsecs = 5 +killasgroup=true + +[program:gunicorn] +command=sh -c "gunicorn oj.wsgi --user nobody -b 127.0.0.1:8080 --reload -w `grep -c ^processor /proc/cpuinfo`" +directory=/app/ +user=nobody +stdout_logfile=/app/data/log/gunicorn.log +stderr_logfile=/app/data/log/gunicorn.log autostart=true autorestart=true startsecs=5 @@ -25,8 +37,8 @@ killasgroup=true command=celery -A oj worker -l warning directory=/app/ user=nobody -stdout_logfile=/data/log/celery.log -stderr_logfile=/data/log/celery.log +stdout_logfile=/app/data/log/celery.log +stderr_logfile=/app/data/log/celery.log autostart=true autorestart=true startsecs=5 diff --git a/oj/dev_settings.py b/oj/dev_settings.py index 5d9cb9e5..5c75a0b2 100644 --- a/oj/dev_settings.py +++ b/oj/dev_settings.py @@ -7,7 +7,7 @@ DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'HOST': '127.0.0.1', - 'PORT': 5432, + 'PORT': 5433, 'NAME': "onlinejudge", 'USER': "onlinejudge", 'PASSWORD': 'onlinejudge' @@ -24,16 +24,4 @@ DEBUG = True ALLOWED_HOSTS = ["*"] -TEST_CASE_DIR = "/tmp" - -LOG_PATH = f"{BASE_DIR}/log/" - -AVATAR_URI_PREFIX = "/static/avatar" -AVATAR_UPLOAD_DIR = f"{BASE_DIR}{AVATAR_URI_PREFIX}" - -UPLOAD_PREFIX = "/static/upload" -UPLOAD_DIR = f"{BASE_DIR}{UPLOAD_PREFIX}" - -STATICFILES_DIRS = [ - os.path.join(BASE_DIR, "static"), -] +DATA_DIR = f"{BASE_DIR}/data" diff --git a/oj/production_settings.py b/oj/production_settings.py index 3f9dee66..026c53a9 100644 --- a/oj/production_settings.py +++ b/oj/production_settings.py @@ -8,8 +8,8 @@ def get_env(name, default=""): DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', - 'HOST': get_env("POSTGRES_HOST", "postgres"), - 'PORT': get_env("POSTGRES_PORT", "5433"), + 'HOST': get_env("POSTGRES_HOST", "oj-postgres"), + 'PORT': get_env("POSTGRES_PORT", "5432"), 'NAME': get_env("POSTGRES_DB"), 'USER': get_env("POSTGRES_USER"), 'PASSWORD': get_env("POSTGRES_PASSWORD") @@ -17,7 +17,7 @@ DATABASES = { } REDIS_CONF = { - "host": get_env("REDIS_HOST", "redis"), + "host": get_env("REDIS_HOST", "oj-redis"), "port": get_env("REDIS_PORT", "6379") } @@ -25,12 +25,4 @@ DEBUG = False ALLOWED_HOSTS = ['*'] -AVATAR_URI_PREFIX = "/static/avatar" -AVATAR_UPLOAD_DIR = "/data/avatar" - -UPLOAD_PREFIX = "/static/upload" -UPLOAD_DIR = "/data/upload" - -TEST_CASE_DIR = "/data/test_case" -LOG_PATH = "/data/log" -DEFAULT_JUDGE_SERVER_SERVICE_URL = "http://judge-server:8080/" +DATA_DIR = "/data" diff --git a/oj/settings.py b/oj/settings.py index 0c6e7687..e1de79bf 100644 --- a/oj/settings.py +++ b/oj/settings.py @@ -109,10 +109,22 @@ USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/1.8/howto/static-files/ -STATIC_URL = '/static/' +STATIC_URL = '/storage/' AUTH_USER_MODEL = 'account.User' +TEST_CASE_DIR = os.path.join(DATA_DIR, "testcase") +LOG_PATH = os.path.join(DATA_DIR, "log") + +AVATAR_URI_PREFIX = "/public/avatar" +AVATAR_UPLOAD_DIR = f"{DATA_DIR}{AVATAR_URI_PREFIX}" + +UPLOAD_PREFIX = "/public/upload" +UPLOAD_DIR = f"{DATA_DIR}{UPLOAD_PREFIX}" + +STATICFILES_DIRS = [os.path.join(DATA_DIR, "public")] + + LOGGING = { 'version': 1, 'disable_existing_loggers': False,