Code Monkey home page Code Monkey logo

django-docker's Introduction

Develop and deploy Django applications with Docker

Build Status codecov PRs Welcome

This repository is used to test a new project layout to develop Django applications within Docker containers. To be very fancy, we're also using poetry.toml instead of requirements.txt for our Python dependencies. Deployment to production is handled by a remote Dokku instance.

Details

We're using Python 3.7-slim for the base image as a trade-off of container size and build time. Further we utilize poetry to try out a new approach of Python requirement management.

Features

  • Develop inside of Docker containers! (Both Django and PostgreSQL run inside of their own containers)
  • Django runserver_plus is sequentially restarted, if the application crashes for any reason.
  • Use Makefile for common commands (docker-compose build, python manage.py makemessages, ...).
  • Uses WhiteNoise to manage static files.
  • Run continuous integration of Travis-CI.
  • Deploy to Dokku for production.
  • Use Sentry for error reporting on your production instance.

Note: In the current layout, with the Dockerfile residing under ./docker/dokku/Dockerfile, you will need to install the dokku-dockerfile plugin and set the path accordingly.**

Planned

  • It would be neat to get Celery to work.

Usage

Local development

Running make build will download all required images (python:3.7-slim and postgresql:9.6-alpine) and build the app. Next you need to run make migrate to run all database migrations, after which you can actually start using this project. Running docker-compose up will collect all staticfiles and start both services. The app will be available via localhost:8000.

Deployment to production (via Dokku)

Prepare app on Dokku host

Before deployment, one needs to set up the app and PostgreSQL database on the Dokku host. For the sake of simplicity we're going to name the Dokku app djangodocker in this example.

# Create app
$ dokku apps:create djangodocker

# Create PostgreSQL database and link it to the app
$ dokku postgres:create djangodocker-postgres
$ dokku postgres:link djangodocker-postgres djangodocker

# Set the bare minimum configuration
$ dokku config:set --no-restart djangodocker DJANGO_ADMIN_URL="/admin"
$ dokku config:set --no-restart djangodocker DJANGO_ALLOWED_HOSTS=djangodocker.example.com
$ dokku config:set --no-restart djangodocker DJANGO_SECRET_KEY=$(echo `openssl rand -base64 100` | tr -d \=+ | cut -c 1-64)
$ dokku config:set --no-restart djangodocker DJANGO_SETTINGS_MODULE=config.settings.production
$ dokku config:set --no-restart djangodocker DJANGO_SENTRY_DSN=https://your:[email protected]/1234
# Make sure the plugin `dokku-dockerfile` is installed
$ dokku dockerfile:set djangodocker docker/dokku/Dockerfile

You may also need to set the domain using dokku domains:set djangodocker djangodocker.example.com.

Setup Dokku server as git remote

To successfully push your app to the Dokku host, you need to set up the server as a git remote:

git remote add dokku [email protected]:djangodocker

Deployment

Deploying the master branch of the app is straightforward:

git push dokku master

If you want to deploy another branch (e.g. newfeature), you need to use this syntax:

git push dokku newfeature:master

More information can be found in the official Dokku documentation.

django-docker's People

Contributors

chgad avatar dependabot[bot] avatar mimischi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

django-docker's Issues

pg_isready not found

When starting the local docker container via docker-compose up we get the error

/entrypoint.sh: 4: /entrypoint.sh: pg_isready: not found

This can be fixed with using the scripts as shown here and here

Travis

Is there a reason why #3 isn't merged yet ?

Run django Tests predeploy

It might be usefull to run project tests, if provided, in the predeploy state and if any of them fails reject the changes. This should only be used for detecting wether there are failing tests or not. So we should keep it simple just, eventually echo the number of failed, and stop the deploy when not passing all tests.

I know that nowadays there are services like Travis CI which do that for you, even Github integrated, but why not double check it ?

Fresh run : django.db.utils.ProgrammingError: relation "main_visits" does not exist error

Got the following error fresh from baking. Am I missing something?

django.db.utils.ProgrammingError
django.db.utils.ProgrammingError: relation "main_visits" does not exist
LINE 1: ...CT "main_visits"."id", "main_visits"."count" FROM "main_visi...
                                                             ^

Trace:

web_1  | 10.0.2.2 - - [24/Feb/2018 04:52:44] "GET / HTTP/1.1" 500 -
web_1  | Traceback (most recent call last):
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/contrib/staticfiles/handlers.py", line 66, in __call__
web_1  |     return self.application(environ, start_response)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/wsgi.py", line 146, in __call__
web_1  |     response = self.get_response(request)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 81, in get_response
web_1  |     response = self._middleware_chain(request)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 37, in inner
web_1  |     response = response_for_exception(request, exc)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 87, in response_for_exception
web_1  |     response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 122, in handle_uncaught_exception
web_1  |     return debug.technical_500_response(request, *exc_info)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django_extensions/management/technical_response.py", line 6, in null_technical_500_response
web_1  |     six.reraise(exc_type, exc_value, tb)
web_1  |   File "/usr/local/lib/python3.6/site-packages/six.py", line 693, in reraise
web_1  |     raise value
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 35, in inner
web_1  |     response = get_response(request)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/utils/deprecation.py", line 95, in __call__
web_1  |     response = self.get_response(request)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 37, in inner
web_1  |     response = response_for_exception(request, exc)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 87, in response_for_exception
web_1  |     response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 122, in handle_uncaught_exception
web_1  |     return debug.technical_500_response(request, *exc_info)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django_extensions/management/technical_response.py", line 6, in null_technical_500_response
web_1  |     six.reraise(exc_type, exc_value, tb)
web_1  |   File "/usr/local/lib/python3.6/site-packages/six.py", line 693, in reraise
web_1  |     raise value
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 35, in inner
web_1  |     response = get_response(request)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/utils/deprecation.py", line 95, in __call__
web_1  |     response = self.get_response(request)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 37, in inner
web_1  |     response = response_for_exception(request, exc)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 87, in response_for_exception
web_1  |     response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 122, in handle_uncaught_exception
web_1  |     return debug.technical_500_response(request, *exc_info)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django_extensions/management/technical_response.py", line 6, in null_technical_500_response
web_1  |     six.reraise(exc_type, exc_value, tb)
web_1  |   File "/usr/local/lib/python3.6/site-packages/six.py", line 693, in reraise
web_1  |     raise value
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 35, in inner
web_1  |     response = get_response(request)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/utils/deprecation.py", line 95, in __call__
web_1  |     response = self.get_response(request)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 37, in inner
web_1  |     response = response_for_exception(request, exc)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 87, in response_for_exception
web_1  |     response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 122, in handle_uncaught_exception
web_1  |     return debug.technical_500_response(request, *exc_info)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django_extensions/management/technical_response.py", line 6, in null_technical_500_response
web_1  |     six.reraise(exc_type, exc_value, tb)
web_1  |   File "/usr/local/lib/python3.6/site-packages/six.py", line 693, in reraise
web_1  |     raise value
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 35, in inner
web_1  |     response = get_response(request)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/utils/deprecation.py", line 95, in __call__
web_1  |     response = self.get_response(request)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 37, in inner
web_1  |     response = response_for_exception(request, exc)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 87, in response_for_exception
web_1  |     response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 122, in handle_uncaught_exception
web_1  |     return debug.technical_500_response(request, *exc_info)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django_extensions/management/technical_response.py", line 6, in null_technical_500_response
web_1  |     six.reraise(exc_type, exc_value, tb)
web_1  |   File "/usr/local/lib/python3.6/site-packages/six.py", line 693, in reraise
web_1  |     raise value
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 35, in inner
web_1  |     response = get_response(request)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/utils/deprecation.py", line 95, in __call__
web_1  |     response = self.get_response(request)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 37, in inner
web_1  |     response = response_for_exception(request, exc)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 87, in response_for_exception
web_1  |     response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 122, in handle_uncaught_exception
web_1  |     return debug.technical_500_response(request, *exc_info)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django_extensions/management/technical_response.py", line 6, in null_technical_500_response
web_1  |     six.reraise(exc_type, exc_value, tb)
web_1  |   File "/usr/local/lib/python3.6/site-packages/six.py", line 693, in reraise
web_1  |     raise value
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 35, in inner
web_1  |     response = get_response(request)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/utils/deprecation.py", line 95, in __call__
web_1  |     response = self.get_response(request)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 37, in inner
web_1  |     response = response_for_exception(request, exc)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 87, in response_for_exception
web_1  |     response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 122, in handle_uncaught_exception
web_1  |     return debug.technical_500_response(request, *exc_info)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django_extensions/management/technical_response.py", line 6, in null_technical_500_response
web_1  |     six.reraise(exc_type, exc_value, tb)
web_1  |   File "/usr/local/lib/python3.6/site-packages/six.py", line 693, in reraise
web_1  |     raise value
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 35, in inner
web_1  |     response = get_response(request)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/utils/deprecation.py", line 95, in __call__
web_1  |     response = self.get_response(request)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 37, in inner
web_1  |     response = response_for_exception(request, exc)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 87, in response_for_exception
web_1  |     response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 122, in handle_uncaught_exception
web_1  |     return debug.technical_500_response(request, *exc_info)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django_extensions/management/technical_response.py", line 6, in null_technical_500_response
web_1  |     six.reraise(exc_type, exc_value, tb)
web_1  |   File "/usr/local/lib/python3.6/site-packages/six.py", line 693, in reraise
web_1  |     raise value
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 35, in inner
web_1  |     response = get_response(request)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 128, in _get_response
web_1  |     response = self.process_exception_by_middleware(e, request)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 126, in _get_response
web_1  |     response = wrapped_callback(request, *callback_args, **callback_kwargs)
web_1  |   File "/app/main/views.py", line 11, in home
web_1  |     c = Visits.objects.get(pk=1)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/db/models/manager.py", line 82, in manager_method
web_1  |     return getattr(self.get_queryset(), name)(*args, **kwargs)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/db/models/query.py", line 397, in get
web_1  |     num = len(clone)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/db/models/query.py", line 254, in __len__
web_1  |     self._fetch_all()
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/db/models/query.py", line 1179, in _fetch_all
web_1  |     self._result_cache = list(self._iterable_class(self))
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/db/models/query.py", line 53, in __iter__
web_1  |     results = compiler.execute_sql(chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1064, in execute_sql
web_1  |     cursor.execute(sql, params)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/db/backends/utils.py", line 100, in execute
web_1  |     return super().execute(sql, params)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/db/backends/utils.py", line 68, in execute
web_1  |     return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/db/backends/utils.py", line 77, in _execute_with_wrappers
web_1  |     return executor(sql, params, many, context)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/db/backends/utils.py", line 85, in _execute
web_1  |     return self.cursor.execute(sql, params)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/db/utils.py", line 89, in __exit__
web_1  |     raise dj_exc_value.with_traceback(traceback) from exc_value
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/db/backends/utils.py", line 85, in _execute
web_1  |     return self.cursor.execute(sql, params)
web_1  | django.db.utils.ProgrammingError: relation "main_visits" does not exist
web_1  | LINE 1: ...CT "main_visits"."id", "main_visits"."count" FROM "main_visi...
web_1  |              

Cookiecutter Template

Wouldn't it be greate to have this project as cookiecutter template?

With this one can avoid the trouble of cloneing and carrying all the previous commits and also avoid renaming stuff.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.