From def7f475722db15deaacf2772b759a5c4ceb4f1f Mon Sep 17 00:00:00 2001 From: Jay Date: Thu, 16 Jul 2015 17:43:02 +0200 Subject: [PATCH 1/4] experimental docker-compose support --- {{cookiecutter.repo_name}}/Dockerfile | 28 ++++++++++ .../compose/django/entrypoint.sh | 15 ++++++ .../compose/django/gunicorn.sh | 3 ++ .../compose/nginx/Dockerfile | 2 + .../compose/nginx/nginx.conf | 53 +++++++++++++++++++ {{cookiecutter.repo_name}}/dev.yml | 16 ++++++ {{cookiecutter.repo_name}}/docker-compose.yml | 46 ++++++++++++++++ {{cookiecutter.repo_name}}/env.production | 12 +++++ 8 files changed, 175 insertions(+) create mode 100644 {{cookiecutter.repo_name}}/Dockerfile create mode 100644 {{cookiecutter.repo_name}}/compose/django/entrypoint.sh create mode 100644 {{cookiecutter.repo_name}}/compose/django/gunicorn.sh create mode 100644 {{cookiecutter.repo_name}}/compose/nginx/Dockerfile create mode 100644 {{cookiecutter.repo_name}}/compose/nginx/nginx.conf create mode 100644 {{cookiecutter.repo_name}}/dev.yml create mode 100644 {{cookiecutter.repo_name}}/docker-compose.yml create mode 100644 {{cookiecutter.repo_name}}/env.production diff --git a/{{cookiecutter.repo_name}}/Dockerfile b/{{cookiecutter.repo_name}}/Dockerfile new file mode 100644 index 00000000..bb319026 --- /dev/null +++ b/{{cookiecutter.repo_name}}/Dockerfile @@ -0,0 +1,28 @@ +FROM python:2.7 +ENV PYTHONUNBUFFERED 1 + +RUN groupadd -r django && useradd -r -g django django + +RUN apt-get update +RUN apt-get -y install libmemcached-dev + +# Requirements have to be pulled and installed here, otherwise caching won't work +ADD ./requirements /requirements +ADD ./requirements.txt /requirements.txt + +RUN pip install -r /requirements.txt +RUN pip install -r /requirements/local.txt + +ADD . /app + +ADD ./compose/django/gunicorn.sh /gunicorn.sh +ADD ./compose/django/entrypoint.sh /entrypoint.sh + +RUN chmod +x /entrypoint.sh +RUN chmod +x /gunicorn.sh + +RUN chown -R django /app + +WORKDIR /app + +ENTRYPOINT ["/entrypoint.sh"] \ No newline at end of file diff --git a/{{cookiecutter.repo_name}}/compose/django/entrypoint.sh b/{{cookiecutter.repo_name}}/compose/django/entrypoint.sh new file mode 100644 index 00000000..541083be --- /dev/null +++ b/{{cookiecutter.repo_name}}/compose/django/entrypoint.sh @@ -0,0 +1,15 @@ +#!/bin/bash +set -e + +# setting up environment variables to work with DATABASE_URL and DJANGO_CACHE_URL +export DJANGO_CACHE_URL=memcache://memcached:11211 + +if [ -z "$POSTGRES_ENV_POSTGRES_USER" ]; then + export POSTGRES_ENV_POSTGRES_USER=postgres +fi + +export DATABASE_URL=postgres://$POSTGRES_ENV_POSTGRES_USER:$POSTGRES_ENV_POSTGRES_PASSWORD@postgres:5432/$POSTGRES_ENV_POSTGRES_USER +{% if cookiecutter.use_celery %} +export CELERY_BROKER_URL=amqp://guest:guest@rabbitmq:5672// +{% endif %} +exec "$@" \ No newline at end of file diff --git a/{{cookiecutter.repo_name}}/compose/django/gunicorn.sh b/{{cookiecutter.repo_name}}/compose/django/gunicorn.sh new file mode 100644 index 00000000..3f9f09ec --- /dev/null +++ b/{{cookiecutter.repo_name}}/compose/django/gunicorn.sh @@ -0,0 +1,3 @@ +#!/bin/sh +su -m django -c "python /app/manage.py collectstatic --noinput" +su -m django -c "/usr/local/bin/gunicorn config.wsgi -w 4 -b 0.0.0.0:5000 --chdir=/app" \ No newline at end of file diff --git a/{{cookiecutter.repo_name}}/compose/nginx/Dockerfile b/{{cookiecutter.repo_name}}/compose/nginx/Dockerfile new file mode 100644 index 00000000..19639576 --- /dev/null +++ b/{{cookiecutter.repo_name}}/compose/nginx/Dockerfile @@ -0,0 +1,2 @@ +FROM nginx:latest +ADD nginx.conf /etc/nginx/nginx.conf \ No newline at end of file diff --git a/{{cookiecutter.repo_name}}/compose/nginx/nginx.conf b/{{cookiecutter.repo_name}}/compose/nginx/nginx.conf new file mode 100644 index 00000000..720b22e5 --- /dev/null +++ b/{{cookiecutter.repo_name}}/compose/nginx/nginx.conf @@ -0,0 +1,53 @@ +user nginx; +worker_processes 1; + +error_log /var/log/nginx/error.log warn; +pid /var/run/nginx.pid; + + +events { + worker_connections 1024; +} + + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + 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 /var/log/nginx/access.log main; + + sendfile on; + #tcp_nopush on; + + keepalive_timeout 65; + + #gzip on; + + upstream app { + server django:5000; + } + + server { + listen 80; + charset utf-8; + + + location / { + # checks for static file, if not found proxy to app + try_files $uri @proxy_to_app; + } + + location @proxy_to_app { + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Host $http_host; + proxy_redirect off; + + proxy_pass http://app; + } + + } +} \ No newline at end of file diff --git a/{{cookiecutter.repo_name}}/dev.yml b/{{cookiecutter.repo_name}}/dev.yml new file mode 100644 index 00000000..98146ffe --- /dev/null +++ b/{{cookiecutter.repo_name}}/dev.yml @@ -0,0 +1,16 @@ +postgres: + image: postgres + volumes: + # If you are using boot2docker, postgres data has to live in the VM for now until #581 is fixed + # for more info see here: https://github.com/boot2docker/boot2docker/issues/581 + - /data/{{cookiecutter.repo_name}}/postgres:/var/lib/postgresql/data + +django: + build: . + command: python /app/manage.py runserver_plus 0.0.0.0:8000 + volumes: + - .:/app + ports: + - "8000:8000" + links: + - postgres \ No newline at end of file diff --git a/{{cookiecutter.repo_name}}/docker-compose.yml b/{{cookiecutter.repo_name}}/docker-compose.yml new file mode 100644 index 00000000..e8bc8f40 --- /dev/null +++ b/{{cookiecutter.repo_name}}/docker-compose.yml @@ -0,0 +1,46 @@ +postgres: + image: postgres:9.4 + volumes: + - /data/{{cookiecutter.repo_name}}/postgres:/var/lib/postgresql/data + env_file: env.production + +django: + build: . + links: + - postgres + - memcached + {% if cookiecutter.use_celery %} + - rabbitmq + {% endif %} + command: /gunicorn.sh + env_file: env.production + +nginx: + build: ./compose/nginx + links: + - django + ports: + - "0.0.0.0:80:80" + +memcached: + image: memcached +{% if cookiecutter.use_celery %} +rabbitmq: + image: rabbitmq + +celeryworker: + build: . + env_file: env.production + links: + - rabbitmq + - postgres + command: su -m django -c "celery -A {{cookiecutter.repo_name}}.taskman worker -l INFO" + +celerybeat: + build: . + env_file: env.production + links: + - rabbitmq + - postgres + command: su -m django -c "celery -A {{cookiecutter.repo_name}}.taskman beat -l INFO" +{% endif %} \ No newline at end of file diff --git a/{{cookiecutter.repo_name}}/env.production b/{{cookiecutter.repo_name}}/env.production new file mode 100644 index 00000000..b4375324 --- /dev/null +++ b/{{cookiecutter.repo_name}}/env.production @@ -0,0 +1,12 @@ +POSTGRES_PASSWORD=mysecretpass +POSTGRES_USER=postgresuser + +DJANGO_SETTINGS_MODULE=config.settings.production +DJANGO_SECRET_KEY= +DJANGO_AWS_ACCESS_KEY_ID= +DJANGO_AWS_SECRET_ACCESS_KEY= +DJANGO_AWS_STORAGE_BUCKET_NAME= +DJANGO_MAILGUN_API_KEY= +DJANGO_MAILGUN_SERVER_NAME= +DJANGO_SERVER_EMAIL= +DJANGO_SECURE_SSL_REDIRECT=False \ No newline at end of file From 7690b42c2777d0d7c97e3d4e510dce69cca5a6f5 Mon Sep 17 00:00:00 2001 From: Jay Date: Tue, 21 Jul 2015 10:22:02 +0200 Subject: [PATCH 2/4] switched to redis cache --- {{cookiecutter.repo_name}}/compose/django/entrypoint.sh | 2 +- {{cookiecutter.repo_name}}/docker-compose.yml | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/{{cookiecutter.repo_name}}/compose/django/entrypoint.sh b/{{cookiecutter.repo_name}}/compose/django/entrypoint.sh index 541083be..7b3ae746 100644 --- a/{{cookiecutter.repo_name}}/compose/django/entrypoint.sh +++ b/{{cookiecutter.repo_name}}/compose/django/entrypoint.sh @@ -2,7 +2,7 @@ set -e # setting up environment variables to work with DATABASE_URL and DJANGO_CACHE_URL -export DJANGO_CACHE_URL=memcache://memcached:11211 +export DJANGO_CACHE_URL=redis://redis:6379 if [ -z "$POSTGRES_ENV_POSTGRES_USER" ]; then export POSTGRES_ENV_POSTGRES_USER=postgres diff --git a/{{cookiecutter.repo_name}}/docker-compose.yml b/{{cookiecutter.repo_name}}/docker-compose.yml index e8bc8f40..d7aa1740 100644 --- a/{{cookiecutter.repo_name}}/docker-compose.yml +++ b/{{cookiecutter.repo_name}}/docker-compose.yml @@ -8,7 +8,7 @@ django: build: . links: - postgres - - memcached + - redis {% if cookiecutter.use_celery %} - rabbitmq {% endif %} @@ -22,8 +22,8 @@ nginx: ports: - "0.0.0.0:80:80" -memcached: - image: memcached +redis: + image: redis:3.0 {% if cookiecutter.use_celery %} rabbitmq: image: rabbitmq @@ -34,6 +34,7 @@ celeryworker: links: - rabbitmq - postgres + - redis command: su -m django -c "celery -A {{cookiecutter.repo_name}}.taskman worker -l INFO" celerybeat: @@ -42,5 +43,6 @@ celerybeat: links: - rabbitmq - postgres + - redis command: su -m django -c "celery -A {{cookiecutter.repo_name}}.taskman beat -l INFO" {% endif %} \ No newline at end of file From 35d61c9eee889d6b1e9b84b8d71fb8fcb9fa83de Mon Sep 17 00:00:00 2001 From: Jay Date: Tue, 21 Jul 2015 10:42:31 +0200 Subject: [PATCH 3/4] added docker-compose documentation --- README.rst | 30 +++++++++++++++++++++++++++ {{cookiecutter.repo_name}}/README.rst | 16 +++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 119d801c..2328c5ea 100644 --- a/README.rst +++ b/README.rst @@ -29,6 +29,7 @@ Features * Serve static files from Amazon S3 or Whitenoise_ (optional) * Pre configured Celery_ (optional) * Integration with Maildump_ for local email testing (optional) +* Docker support using docker-compose_ for dev and prod .. _Bootstrap: https://github.com/twbs/bootstrap .. _AngularJS: https://github.com/angular/angular.js @@ -41,6 +42,7 @@ Features .. _Whitenoise: https://whitenoise.readthedocs.org/ .. _Celery: http://www.celeryproject.org/ .. _Maildump: https://github.com/ThiefMaster/maildump +.. _docker-compose: https://www.github.com/docker/compose Constraints @@ -156,6 +158,34 @@ To get live reloading to work you'll probably need to install an `appropriate br It's time to write the code!!! +Getting up and running using docker +---------------------------------- + +The steps below will get you up and running with a local development environment. We assume you have the following installed: + +* docker +* docker-compose + +Open a terminal at the project root and run the following for local development:: + + $ docker-compose -f dev.yml up + +You can also set the environment variable ``COMPOSE_FILE`` pointing to ``dev.yml`` like this:: + + $ export COMPOSE_FILE=dev.yml + +And then run:: + + $ docker-compose up + + +To migrate your app and to create a superuser, run:: + + $ docker-compose run django python manage.py migrate + + $ docker-compose run django python manage.py createsuperuser + + For Readers of Two Scoops of Django 1.8 -------------------------------------------- diff --git a/{{cookiecutter.repo_name}}/README.rst b/{{cookiecutter.repo_name}}/README.rst index 786232f5..1aa533b6 100644 --- a/{{cookiecutter.repo_name}}/README.rst +++ b/{{cookiecutter.repo_name}}/README.rst @@ -155,7 +155,7 @@ It's time to write the code!!! Deployment ------------ -It is possible to deploy to Heroku or to your own server by using Dokku, an open source Heroku clone. +It is possible to deploy to Heroku, to your own server by using Dokku, an open source Heroku clone or using docker-compose. Heroku ^^^^^^ @@ -232,3 +232,17 @@ You can then deploy by running the following commands. ssh -t dokku@yourservername.com dokku run {{cookiecutter.repo_name}} python manage.py createsuperuser When deploying via Dokku make sure you backup your database in some fashion as it is NOT done automatically. + +Docker +^^^^^^ + +You need a working docker and docker-compose installation on your production server. + +To get started, clone the git repo containing your projects code and set all needed environment variables in +``env.production``. + +To start docker-compose in the foreground, run: + +.. code-block:: bash + + docker-compose up From 79dbcc16f8d32f57d25fa7326f6fdd847eecf25a Mon Sep 17 00:00:00 2001 From: Jay Date: Tue, 21 Jul 2015 11:08:29 +0200 Subject: [PATCH 4/4] renaming taskman to taskapp to reflect upstream changes --- {{cookiecutter.repo_name}}/docker-compose.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/{{cookiecutter.repo_name}}/docker-compose.yml b/{{cookiecutter.repo_name}}/docker-compose.yml index d7aa1740..2f8154c9 100644 --- a/{{cookiecutter.repo_name}}/docker-compose.yml +++ b/{{cookiecutter.repo_name}}/docker-compose.yml @@ -35,7 +35,7 @@ celeryworker: - rabbitmq - postgres - redis - command: su -m django -c "celery -A {{cookiecutter.repo_name}}.taskman worker -l INFO" + command: su -m django -c "celery -A {{cookiecutter.repo_name}}.taskapp worker -l INFO" celerybeat: build: . @@ -44,5 +44,5 @@ celerybeat: - rabbitmq - postgres - redis - command: su -m django -c "celery -A {{cookiecutter.repo_name}}.taskman beat -l INFO" + command: su -m django -c "celery -A {{cookiecutter.repo_name}}.taskapp beat -l INFO" {% endif %} \ No newline at end of file