diff --git a/Dockerfile b/Dockerfile index 21d545d..1efdb06 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,21 @@ FROM python:3.5.1 + +# System packages +RUN apt-key update && apt-get update +#Supervisor for running application in production +RUN apt-get install supervisor -y +# Clean up package manager +RUN apt-get autoremove -y +RUN rm -rvf /var/cache/apt + +# Environment variables ENV PYTHONUNBUFFERED 1 + +# Directories RUN mkdir /code WORKDIR /code ADD . /code/ RUN pip install -r requirements.txt + +# Default entrypoint +ENTRYPOINT "/code/scripts/run_prod.sh" diff --git a/README.md b/README.md index a240ea7..493a753 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Sometimes the postgres image takes a while to load on first run and the Django s The code in the repository is also mounted as a volume in the task-service container. This means you can edit code on your host machine, using your favorite editor, and the django server will automatically restart to reflect the code changes. -The server should start up at http://localhost:8080/, see the [API docs](https://github.com/cognoma/task-service/blob/master/doc/api.md). +The server should start up at http://localhost:8001/, see the [API docs](https://github.com/cognoma/task-service/blob/master/doc/api.md). ## Running tests locally diff --git a/config/prod/gunicorn.conf b/config/prod/gunicorn.conf new file mode 100644 index 0000000..ab7c05d --- /dev/null +++ b/config/prod/gunicorn.conf @@ -0,0 +1,29 @@ +# For full details, see: +# http://docs.gunicorn.org/en/stable/settings.html + +# Address +bind = '0.0.0.0:8001' + +# Worker configuration +# http://docs.gunicorn.org/en/stable/design.html#async-workers +worker_class = 'eventlet' + +# Rule of thumb for workers is (2 * ncpus) + 1 +# http://docs.gunicorn.org/en/stable/design.html#how-many-workers +workers = 2 +threads = 8 +worker_connections = 10 + +# Restart of worker after certain number of requests to avoid memory leaks +max_requests = 1000 +max_requests_jitter = 100 + +# Timeout settings +graceful_timeout = 300 +timeout = 300 + +# Logging +loglevel = 'info' + +# Daemonization +daemon = False diff --git a/config/prod/supervisord.conf b/config/prod/supervisord.conf new file mode 100644 index 0000000..0bedd4d --- /dev/null +++ b/config/prod/supervisord.conf @@ -0,0 +1,19 @@ +[supervisord] +; Don't want supervisord to be daemonised, as otherwise when running under +; Docker it will assume that the command has completed, whereas we want +; supervisord to stay up as long as the application is running +nodaemon=true + + +[program:core_service] +command=/usr/local/bin/gunicorn task_service.wsgi:application -c /code/config/prod/gunicorn.conf +directory=/code +; User account with minimal privileges +user=nobody +numprocs=1 +autostart=true +autorestart=true +; Redirect all logging to Docker stdout +redirect_stderr=true +stdout_logfile=/dev/fd/1 +stdout_logfile_maxbytes=0 diff --git a/docker-compose.yml b/docker-compose.yml index 6eb532d..ae95a19 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,7 +4,7 @@ services: image: postgres task: build: . - command: bash -c "python manage.py migrate && python manage.py runserver 0.0.0.0:8001" + entrypoint: ./scripts/run_dev.sh volumes: - .:/code ports: diff --git a/requirements.txt b/requirements.txt index c813734..41c31a3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,3 +9,5 @@ pyasn1==0.1.9 pycparser==2.16 PyJWT==1.4.2 six==1.10.0 +gunicorn==19.6.0 +eventlet==0.20.1 diff --git a/scripts/run_dev.sh b/scripts/run_dev.sh new file mode 100755 index 0000000..406a28f --- /dev/null +++ b/scripts/run_dev.sh @@ -0,0 +1,4 @@ +#!/bin/bash -x + +manage.py migrate -v3 --no-input +python manage.py runserver 0.0.0.0:8001 diff --git a/scripts/run_prod.sh b/scripts/run_prod.sh new file mode 100755 index 0000000..5d2969a --- /dev/null +++ b/scripts/run_prod.sh @@ -0,0 +1,5 @@ +#!/bin/bash -x + +# Application is configured to run under Supervisord, which in turn monitors +# the Gunicorn web server +supervisord -c /code/config/prod/supervisord.conf