diff --git a/README.md b/README.md index 66a4aa63..bd2b4a6a 100755 --- a/README.md +++ b/README.md @@ -138,6 +138,42 @@ Run the container on host port 8000 docker run -d -p 8000:8000 pokeapi ``` + +## Docker Compose + +There is also a multi-container setup, managed by [Docker Compose](https://docs.docker.com/compose/). This setup allow you to deploy a production-like environment, with separate containers for each services. + +Create data volumes for Redis and Postgres +``` +docker volume create --name=redis_data +docker volume create --name=pg_data +``` + +Start the process using +``` +docker-compose up +``` +You can specify the ```-d``` switch to start in detached mode. +This will bind port 80 and 443. Unfortunately, unlike the ```docker``` command, there is no command line arguments to specify ports. If you want to change them, edit the ```docker-compose.yml``` file. + +After that, start the migration process +``` +docker-compose exec app python manage.py migrate +``` + +And then, import the data using the shell +``` +docker-compose exec app python manage.py shell +``` + +You can use the ```build_all()``` method, or individuals data building functions (See _V2 Database setup_) +``` +from data.v2.build import build_all +build_all() +``` + +For the moment, this setup doesn't allow you to use the ```scale``` command. + ## Contributing All contributions are welcome: bug fixes, data contributions, recommendations. diff --git a/Resources/docker/app/Dockerfile b/Resources/docker/app/Dockerfile new file mode 100644 index 00000000..65bbfa18 --- /dev/null +++ b/Resources/docker/app/Dockerfile @@ -0,0 +1,16 @@ +FROM python:2.7 + +ENV PYTHONUNBUFFERED 1 +ENV DJANGO_SETTINGS_MODULE 'config.docker-compose' +ENV PYTHONHASHSEED 'random' + +RUN mkdir /code +WORKDIR /code +VOLUME /code + +ADD requirements.txt /code/ +RUN pip install --no-cache-dir -r requirements.txt +ADD . /code/ + +CMD gunicorn config.wsgi:application -c gunicorn.py.ini +EXPOSE 8000 diff --git a/Resources/docker/web/Dockerfile b/Resources/docker/web/Dockerfile new file mode 100644 index 00000000..3b701f42 --- /dev/null +++ b/Resources/docker/web/Dockerfile @@ -0,0 +1,2 @@ +FROM nginx:alpine +COPY ./nginx/nginx.conf /etc/nginx/nginx.conf diff --git a/Resources/nginx/nginx.conf b/Resources/nginx/nginx.conf new file mode 100644 index 00000000..eefadad1 --- /dev/null +++ b/Resources/nginx/nginx.conf @@ -0,0 +1,68 @@ +worker_processes 1; + +events { + worker_connections 1024; + accept_mutex off; + use epoll; +} + +http { + include mime.types; + default_type application/octet-stream; + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + + keepalive_timeout 5; + + upstream pokeapi_upstream { + # 'app' is the Django container name in Docker + # DO NOT EDIT IT ALONE or it'll break docker-compose + server app:8000 fail_timeout=0; + } + + limit_req_zone $binary_remote_addr zone=api:10m rate=2r/s; + + server { + listen 80 deferred; + server_name _; + + client_body_timeout 5s; + client_header_timeout 5s; + + root /code; + + location /media/ { + root /code; + autoindex off; + } + + location /static/ { + alias /code/assets/; + autoindex off; + } + + location /api/ { + limit_req zone=api burst=10; + + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Host $http_host; + + proxy_redirect off; + + proxy_pass http://pokeapi_upstream; + } + + location / { + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Host $http_host; + + proxy_redirect off; + + proxy_pass http://pokeapi_upstream; + } + } +} diff --git a/config/docker-compose.py b/config/docker-compose.py new file mode 100644 index 00000000..087fb78e --- /dev/null +++ b/config/docker-compose.py @@ -0,0 +1,27 @@ +# Docker settings +from .settings import * # NOQA + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql_psycopg2', + 'NAME': 'pokeapi', + 'USER': 'ash', + 'PASSWORD': 'pokemon', + 'HOST': 'db', + 'PORT': 5432, + } +} + + +CACHES = { + "default": { + "BACKEND": "django_redis.cache.RedisCache", + "LOCATION": "redis://cache:6379/1", + "OPTIONS": { + "CLIENT_CLASS": "django_redis.client.DefaultClient", + } + } +} + +DEBUG = False +TASTYPIE_FULL_DEBUG = False diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..edaade43 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,43 @@ +version: '2' +services: + cache: + image: redis:alpine + volumes: + - redis_data:/data + + db: + image: postgres + environment: + POSTGRES_PASSWORD: 'pokemon' + POSTGRES_USER: 'ash' + POSTGRES_DB: 'pokeapi' + volumes: + - pg_data:/var/lib/postgresql/data + + app: + build: + context: . + dockerfile: ./Resources/docker/app/Dockerfile + volumes: + - /code + links: + - db + - cache + + web: + build: + context: ./Resources + dockerfile: ./docker/web/Dockerfile + ports: + - "80:80" + - "443:443" + volumes_from: + - app:ro + links: + - app + +volumes: + pg_data: + external: true + redis_data: + external: true diff --git a/gunicorn.py.ini b/gunicorn.py.ini new file mode 100644 index 00000000..32743cee --- /dev/null +++ b/gunicorn.py.ini @@ -0,0 +1,4 @@ +from multiprocessing import cpu_count + +bind = '0.0.0.0:8000' +workers = cpu_count() * 2 + 1 diff --git a/requirements.txt b/requirements.txt index 9d35c63d..e9b17b91 100755 --- a/requirements.txt +++ b/requirements.txt @@ -13,7 +13,7 @@ django-tastypie==0.12.1 django-markdown-deux==1.0.5 djangorestframework>=3.1.0 drf-ujson==1.2.0 -gunicorn==0.17.0 +gunicorn==19.4.5 markdown2==2.3.0 mimeparse==0.1.3 pilkit==1.1.12