Deploy your Django app with Docker

TJ Higgins - 01/14/21

Django is an excellent Python Web framework, but it can be tricky to deploy to the cloud. If you’re building in Python, you want the confidence that what you develop and deploy locally will translate to production. This quick-start guide demonstrates how to set up and run a simple Django/PostgreSQL app locally for development and production-ready in the cloud.

Prerequisites

There are many tools out there that provide support for local development OR remote deployment. Architect was built to do both. This tutorial will show how, with one simple architect.yml file, any developer can run their application locally and in the cloud without having to learn/write docker-compose and infrastructure as code templates.

Before you begin, make sure the following are installed on your system:

Architect CLI: The best way to install the CLI is via NPM:

$ npm install -g @architect-io/cli

Alternatively, you can download the binary for your system architecture from Github. Just download the appropriate bundle, extract it, and link the included bin folder to your user home directory.

Docker: This is a software platform for building applications based on containers. Install it according to the docs on their site.

Django, Docker, and more

For this project, you need to create a Dockerfile, a Python dependencies file, and an architect.yml file.

Create an empty project directory. You can name the directory something easy for you to remember. This directory is the context for your application image. The directory should only contain resources to build that image.

You’ll next need to create a new file called Dockerfile in your project directory. The Dockerfile defines an application's image content via one or more build commands that configure that image. Once built, you can run the image in a container.

Add the following content to the Dockerfile:

FROM python:3
ENV PYTHONUNBUFFERED=1
WORKDIR /code
COPY requirements.txt /code/
RUN pip install -r requirements.txt
COPY . /code/

Create a requirements.txt in your project directory. This file is used by the RUN pip install -r requirements.txt command in your Dockerfile. Pip is a package-management system similar to npm except for Python. Each line in the file represents an external dependency and the required version of that software.

Add the required software in the file.

Django>=3.0,<4.0
psycopg2-binary>=2.8
uwsgi>=2.0

Create a file called architect.yml in your project directory. The architect.yml file describes the services that make your app. In this example, those services are a web server and database. Add the following configuration to the file:

name: examples/django
parameters:
  django_secret_key:
    default: warning-override-for-production
  postgres_password:
    default: warning-override-for-production

services:
  db:
    image: postgres
    interfaces:
      main: 5432
    environment:
      POSTGRES_DB: postgres
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: ${{ parameters.postgres_password }}
  web:
    build:
      context: .
    command: |
      sh -c '
        python manage.py collectstatic --noinput
        python manage.py migrate --noinput
        uwsgi --http "0.0.0.0:${{ services.web.interfaces.main.port }}" --module architectexample.wsgi:application --master --processes 4 --threads 2 --static-map /static=/code/static
      '
    interfaces:
      main: 8000
    environment:
      DEBUG: 'False'
      ALLOWED_HOST: .${{ interfaces.web.host }}
      SECRET_KEY: ${{ parameters.django_secret_key }}
      POSTGRES_DB: ${{ services.db.environment.POSTGRES_DB }}
      POSTGRES_USER: ${{ services.db.environment.POSTGRES_USER }}
      POSTGRES_PASSWORD: ${{ services.db.environment.POSTGRES_PASSWORD }}
      POSTGRES_HOST: ${{ services.db.interfaces.main.host }}
      POSTGRES_PORT: ${{ services.db.interfaces.main.port }}
    debug:
      command: |
        sh -c '
          python manage.py migrate --noinput
          python manage.py runserver 0.0.0.0:${{ services.web.interfaces.main.port }}
        '
      environment:
        ALLOWED_HOST: '*'
        DEBUG: 'True'
      volumes:
        code:
          mount_path: /code
          host_path: .

interfaces:
  web: ${{ services.web.interfaces.main.url }}

This manifest file does the following three things:

  • Outlines parameter values which allow you to configure the services per deployment
  • Defines the services to be deployed. In this case db is the postgres database and web is the django application. Each service block defines the interfaces (ports) that are exposed. Along with the environment variables required for the service to run.
  • Defines development specific configuration in service debug blocks. This is powerful because it lets us define different start commands for development and production.

You can check out the architect.yml reference for more information on how this file works.

Create your Django project

Next, you’ll create a Django starter project by building the image from the build context defined in the previous procedure.

Switch to the root of your project directory. Create the Django project by running the command as follows.

```console
docker run --rm -it -v ${PWD}:/code $(docker build -q .) django-admin startproject architectexample .
```

After the command completes, list the contents of your project.

$ ls -l

drwxr-xr-x 2 root   root   architectexample
-rw-rw-r-- 1 user   user   architect.yml
-rw-rw-r-- 1 user   user   Dockerfile
-rwxr-xr-x 1 root   root   manage.py
-rw-rw-r-- 1 user   user   requirements.txt

Configure Django

Now it’s time to set up the database connection for Django along with a few other settings.

In your project directory, edit the architectexample/settings.py file. Replace or add the the following:

# settings.py
import os

STATIC_ROOT =  os.path.join(BASE_DIR, 'static/')

SECRET_KEY = os.environ.get('SECRET_KEY', 'warning-override-for-production')

DEBUG = os.environ.get('DEBUG', 'False') == 'True'

ALLOWED_HOSTS = [os.environ.get('ALLOWED_HOST', '')]

DATABASES = {
  'default': {
      'ENGINE': 'django.db.backends.postgresql',
      'NAME': os.environ.get('POSTGRES_DB', 'postgres'),
      'USER': os.environ.get('POSTGRES_USER', 'postgres'),
      'PASSWORD': os.environ.get('POSTGRES_PASSWORD', 'postgres'),
      'HOST': os.environ.get('POSTGRES_HOST', '0.0.0.0'),
      'PORT': os.environ.get('POSTGRES_PORT', '5432'),
  }
}

Deploy your Django app locally

Run the architect deploy command from the top level directory for your project.

$ architect deploy -l architect.yml -i django:web
http://django.localhost:80/ => examples--django--web--latest--cvkrs58l

http://localhost:50000/ => examples--django--db--latest--cbyiekkg
http://localhost:50001/ => examples--django--web--latest--cvkrs58l
http://localhost:80/ => gateway

. . .

web_1  | July 30, 2020 - 18:35:38
web_1  | Django version 3.0.8, using settings 'architectexample.settings'
web_1  | Starting development server at http://0.0.0.0:8000/
web_1  | Quit the server with CONTROL-C.

Go to http://django.localhost on a web browser to see the Django welcome page.

Django example

If you want to shut down the services, simply stop the application by typing Ctrl-C in the same shell where you started it.

Deploy your Django app remotely

You now know how to run our stack of services locally in a repeatable way, but what about deploying to production-grade environments? How do you deploy all our services to AWS ECS or Kubernetes? How do we deal with the networking and configuration of our services? Fortunately, Architect has this handled too! Since we already described our services as Architect Components, they are primed and ready to be deployed to production-grade container platforms without any additional work.

Before you can deploy components to remote environments, you must create an account with Architect.

Once you've successfully created your account, go ahead and click the button below to deploy it to a sample Kubernetes cluster powered by Architect Cloud:

Deploy Button

Note: Deploying to production disables DEBUG, and the base URL will 404. Confirm it’s working by loading /admin. An empty app is no fun so take a look at the next steps.

Next steps with Django and Docker

Now you’re ready to build your application with the confidence that if you can run it locally, it will also run in the cloud. Django has an excellent polls tutorial, which you should try if this is your first time. The only difference is the command to create the example polls app.

docker run --rm -it -v ${PWD}:/code $(docker build -q .) python manage.py startapp polls

Learn more about how to deploy faster and more securely

Congratulations! That's all it takes to take a locally runnable component and deploy it to a remote cluster with Architect.

Note: You can register your own Kubernetes or ECS cluster on the platforms tab of your account. Then create an environment for that platform and try deploying again!

Note: We skipped the component registration step in this tutorial because we've already published this example component to the registry. If you want to try publishing yourself, simply change the component name to include your account name as the prefix instead of examples and then run architect register architect.yml in the project directory. Docs

View component

If you’d like to read more about how Architect enables safe, fast deployments, we’ve got you covered:

And as always, we’d love to have you follow along as we release new content and features. Check us out on Twitter @architect_team!


Subscribe to our newletter to stay updated with the latest in cloud architecture

By submitting this form, you are accepting our Terms of Service and our Privacy Policy.