Deploy Your Django App with Docker
Tags: docker, python, programming, tutorial
Published: 2022-04-07 16:27:33

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 tools and services 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](https://www.docker.com/get-started).

## 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:8000" --module architectexample.wsgi:application --master --processes 4 --threads 2 --static-map /static=/code/static
      '
    interfaces:
      main: 8000
    environment:
      DEBUG: 'False'
      ALLOWED_HOST: .${{ ingresses.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:

1. Outlines parameter values which allow you to configure the services per deployment
2. 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
3. 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](https://www.architect.io/docs/components/architect-yml) 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](https://www.architect.io/docs/reference/cli#architect-deploy-environment_config_or_component) command from the top level directory for your project.

```
$ architect dev 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.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w15h4xvyk9r2ghos41dh.png)

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](https://cloud.architect.io/signup).

Once you’ve successfully created your account, go ahead and [deploy it to a sample Kubernetes cluster powered by Architect Cloud](https://cloud.architect.io/examples/components/django/deploy?tag=latest&interface=django%3Aweb).

_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](https://docs.djangoproject.com/en/3.1/intro/tutorial01/#creating-the-polls-app), 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](https://www.architect.io/docs/getting-started/introduction#register-a-component)_

_[View component](https://cloud.architect.io/examples/components/django/)_

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

- [Why Distributed Apps Need Dependency Management](https://www.architect.io/blog/2020-09-16/why-distributed-apps-need-dependency-management/)
- [Creating Microservices: Nest.js](https://www.architect.io/blog/creating-microservices-nestjs)
- [Cycling Credentials Without Cycling Containers](https://www.architect.io/blog/cycling-credentials-without-cycling-containers)

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](https://twitter.com/architect_team)!