How to deploy a Django application on Patr

Aditi Shah
The Patr-onus Deployment Blog
11 min readJul 4, 2022

--

Django is a free and open-source python-based web framework. It is maintained by Django Software Foundation. Django includes many features such as authentication, a custom database ORM (Object Relationship Mapper) and an extensible plugin architecture. Django takes care of all the hassles faced during web development so that you can keep your sole focus on writing and improving your code.

In this tutorial, we will deploy a Django-based project on Patr, by dockerizing the code.

Pre-Requisites

To complete this tutorial, we will need:

1. Code Editor (It can be VS Code, Notepad++, Sublime, Pycharm, Idle etc.)

2. You need to have the latest version of Python installed on your device, in case you don’t have it, you can refer to this link.

3. A good internet connection.

4. Patr of course.

Step 1: Getting your Repo and Code ready:

For this tutorial, I’m assuming you already have a Django code ready for production, if you don’t have it in production mode you can refer to this link. If you don’t have a code, then you can use this fork of this repository.

Step 2: Dockerizing your code:

You now have a ready-to-deploy web application. You’ve been working with Django’s built-in development web server thus far. It’s time to build up the project to run the app in Docker with a more powerful web server capable of handling production traffic.

The bundled flask development server is usually used for testing purposes on your local PC. In contrast, the Python HTTP server Gunicorn is more powerful and made to handle production-level traffic. All dynamic files will be handled by it. We’ll use Nginx as a reverse proxy to serve static files, as it’s a general-purpose HTTP server.

Setting up the programme on a standard server would be difficult; as we’d have to install and set up Python and Nginx, then open the proper firewall ports. Docker eliminates all of this effort by generating a single image that contains all of the necessary files and services. The image we’ll make is compatible with any Docker-enabled system.

Installing Docker

Docker’s portability is one of its main goals, and it can be installed on a wide range of operating systems.

Install Docker Desktop on Windows and OSX.

Docker is available on all major Linux distributions.

Writing the Dockerfile

The following steps are for including a Dockerfile in your project. This allows Docker to produce the image that will run on the Docker Machine you just made.

To brush up, a Dockerfile is simple to create and contains many elements that can be reused and/or obtained online. Docker comes with a lot of tools which you can use to create your image. Dockerfiles offer the flexibility to personalise your project. A Dockerfile’s structure can be thought of as a set of instructions for creating your container/image. The majority of Dockerfiles, for example, will start by referencing a Docker base image. This is usually a pure vanilla image of the most recent Ubuntu release or other Linux OS of choice. You can configure directory structures, environment variables, download dependencies, and a variety of other basic system activities before eventually running the process that will operate your web application.

1. Create an empty file named Dockerfile at the root of your project to begin the Dockerfile.

2. Then, in the Dockerfile, add the first line that specifies which base image to use. You may make your own base image and use it for your containers, which can come in handy if you work in a department with many teams who would need to deploy their apps in the same way.

3. We’ll create the Dockerfile in the root of our project, and move one directory up.

$ cd . .

4. Make a new file with the name nginx.default. This will be our Nginx setup.

5. On port 8020, we’ll listen for connections, serve static files from the /opt/app/martor demo/static directory, and redirect the remainder to port 8010, where Gunicorn will be listening:

$ nginx.deaultserver { 
Listen 8020;
server_name example.org;
location / {
Proxy_pass http://127.0.0.1.8010;
Proxy_set_header Host $host;
Proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
Location /static {
Root /opt/app/martor_demo;
}
}

6. Create a server start-up script called start-server.sh. This is a Bash script that starts Gunicorn and Ngnix:

#!/usr/bin/env bash 
# start-server.sh
If [ -n"$DJANGO_SUPERUSER_USERNAME"] && [-n"$DJANGO_SUPERUSER_PASSWORD"] ; then
(cd martor_demo; python mansge.py createsuperuser - -no-input)
fi
(cd martor_demo; gunicorn martor_demo.wsig - - user www-data - - bind 0.0.0.0:8010 - - workers 3)
Nginx - g "daemon off;

The gunicorn command is then passed as the first argument of martor demo.wsgi. This is a reference to the wsgi file that Django created for us, which is the Python standard for web applications and servers. The file just declares the application variable, and Gunicorn understands how to communicate with the object to start the webserver.

7. The programme is then performed with two flags: bind to connect the running server to port 8020, which will be used to communicate with the operating web server over HTTP. Finally, you define the number of workers, which are the threads that will process the requests that come into your application. Gunicorn suggests setting this value to (2 x num. of cores) + 1. More information about Gunicorn setup can be found in their documentation.

8. Make the script executable:

$ chmod 755 start-server.sh

9. Create the Dockerfile:

FROM python:3.9-buster 
. . .

It’s worth mentioning that we’re utilising a base image designed particularly for Python 3.9 apps, as well as a set of instructions that execute before the rest of your Dockerfile.

10. Next, add the Nginx installation commands and COPY the configuration file inside the container:

. . . 
RUN apt get update && apt-get install nginx vim -y -- no-install recommends
COPY nginx.default /etc/nginx/sites-available/default
RUN ln - sf/dev/stdout/var/log/nginx/access.log \
&& ln -sf /dev/stdeer/var/log/nginx/error.log
. . .

The source files and scripts must now be copied inside the container. On build time, we may use the COPY command to copy files and the RUN command to run programmes.

11. You also need to copy and install the Python packages. Finally, we have to double-check whether each file has the right owner:

RUN mkdir  -p/opt/app 
RUN mkdir -p/opt/app/pip_cache
RUN mkdir -p/opt/app/martor_demo
COPY requirements.txt start-server.sh /opt/app/
COPY .pip_cache /opt/app/martor_demo/
WORKDIR /opt/app
RUN pip install -r requirements.txt - - cahce-dir /opt/app/pip_cache
RUN chown -R www-data-www-data/opt/app
. . .

12. The server will be accessible on port 8020. As a result, you must configure your container to enable access to this port in order to connect with your operating server through HTTP. To do this, use the EXPOSE command to open the port.

. . . 
EXPOSE 8020
STOPSIGNAL SIGTERM
CMD ["/opt/app/start-server.sh"]

13. The final step in your Dockerfile is to run the start script you added earlier, which will start your web server on port 8020 and listen for HTTP requests. The CMD directive can be used to run this script.

After you’ve set everything up, your final Dockerfile should look like this:

# Dockerfile 
FROM python : 3.9-buster

# install nginx
RUN apt-get update && apt-get install nginx vim -y - - no-install-recommends
COPY nginx.deault /etc/nginx/sites-available/default
RUN ln -sf/dev/stdout /var/log/nginx/access.log \
&& ln -sf/dev/stderr/var/log/nginx/error.log

# copy source and install dependencies
RUN mkdir -p/opt/app
RUN mkdir -p/opt/app/pip_cache
RUN mkdir -p/opt/app/martor_demo
COPY requirements.txt start-server.sh/opt/app/
COPY .pip_cache/opt/app/pip_cache/
COPY martor_demo/opt/app/martor_demo/
WORKDIR /opt/app
RUN pip install -r requirements.txt - - cache.dir/opt/app/pip_cache
RUN chown - R www-data:www-data/opt/app

# start server
EXPOSE 8020
STOPSIGNAL SIGTERM
CMD ["/opt/app/start-server.sh"]

You are now ready to build the container image, and run it, to see it all working together.

Building and Running the Container

Once you have Docker installed on your PC, creating the container is quite simple. The command below will seek your Dockerfile and download all the layers required to execute your container image. It will then execute the commands in the Dockerfile, leaving you with a container that is ready to use.

Use the docker build command to create your container and give it a name or tag so you can refer to it later when you want to start it. The command’s final component informs Docker which directory to build in.

$ mkdir -p .pip_cache 
$ docker build -t Django-markdown-editor .

In the output, you can see Docker processing each one of your commands before showcasing the complete of the build. It will give you a unique ID for the container, which can also be used in commands alongside the tag.

The final step is to run the container you have built using Docker:

$ docker run -it -p 8020:8020 \ 
-e DJANGO_SUPERUSER_USERNAME=admin\
-e DJANGO_SUPERUSER_PASSWORD=sekret1\
-e DJANGO_SUPERUSER_EMAIL -admin@example.com\
Django-markdown-editor
Superuser created successfully.
[2022-05-04 17:49:43 +0000] [11] [INFO] Starting gunicorn 20.1.0
[2022-05-04 17:49:43 +0000] [11] [INFO] Listening at: http://0.0.0.0:8010 (11)
[2022-05-04 17:49:43 +0000] [11] [INFO] Using worker: sync
[2022-05-04 17:49:43 +0000] [11] [INFO] Booting worker with pid: 16
[2022-05-04 17:49:43 +0000] [11] [INFO] Booting worker with pid: 17
[2022-05-04 17:49:43 +0000] [11] [INFO] Booting worker with pid: 18

The command tells Docker to run the container and forward the exposed port 8020 to port 8020 on your local machine. With -e we set environment variables that automatically create an admin user.

After you run this command, visit http://localhost:8020 and http://localhost:8020/admin in your browser to access the application.

Step 3: Signing up on PATR:

This is a fairly easy step, just head on the app.patr.cloud, create a new account.

Fill in your details on the sign-up form. A mail will be sent to your registered email address with an OTP. Use that password to complete the sign-up process.

Step 4: Create a Docker Repository:

When you create an account on PATR, you automatically get a secure, private docker registry by default. All you need to do is create a repository.

After signing in navigate to the Docker Registry tab:

Assign your new Docker repository a name of your choice, once you are done, hit Create Repository.

Your new docker repository will show up on your list of repositories.

You can click on each repository to get information about it:

Step 5: Create a Deployment

Let’s start creating a deployment on PATR; you’ll soon realise how easy it is to deploy on PATR. A deployment is merely a container running on a server. All you need to do is provide the docker image, and mention where you want to run it. The rest will be taken care of by PATR. Your container will be up and running in no time.

Navigate to the Deployments tab on PATR and click on New Deployment:

Fill in the following details accordingly:

· Name: The name of your deployment. You would use this to identify the deployment for your internal purposes.

· Registry: Specify which registry you want to pull the image from. Currently, we only allow pulling the image from our internal registry, meanwhile we working on allowing other registries as well.

· Repository: This is the docker repository containing the image you want to deploy. From the dropdown select the repository that you just created.

· Image Tag: Mention the tag of the image to be deployed from the repository that you chose. As a default, pick latest, unless you want to push an image with a different name.

· Region: Choose a region which is closest to your users. This will determine the latency of your application.

Click on Next Step:

· Ports: the port you want your app to be exposed to, in this case, it’s 8020.

· Environment Variables: Give environment variables that are been used in your application with a proper Key and a value, in this case, it should look like the image below.

Click on Next Step:

● Deploy Options: You can tick one or both of the options in the checkbox

● Deploy on push means the deployment will be created as soon as you push to the Docker repository.

● Deploy on create will deploy as soon as the deployment is created.

● If you don’t check either you have to do it by clicking on the start button manually.

● Horizontal Scale: This specifies the number of instances of your image you want running. These will be automatically load-balanced.

● Machine Type and Cloud Providers: This specifies the RAM and CPU specifications of the machine that’s going to run your docker container. PATR supports AWS as well as Digital Ocean. We’re working on adding support for more cloud providers in the future.

Click on Create Deployment.

Your new deployment will now be created with the image and tag you had mentioned but will have the status as created. This is because you actually haven’t pushed any image to the registry, for it to deploy.

Step 6: Pushing an Image

Now that we have a deployment, let’s push an image to it to run it.

You need to install the Docker CLI from this link.

Once you have docker installed, from your terminal, type the following:

“docker login registry.patr.cloud”

You will be asked for a username and password. Use the same credentials you used to sign up for Patr.

Now, let’s take an image you have locally and push it (this tutorial assumes your local image is tagged as (demo: latest).

On the website, you’ll find a button to copy the full image details of the deployment you just created, next to the delete button. This button will copy the full image name, plus the tag of the repository to push to, which will trigger the deployment.

Now that you have the full image details copied, let’s retag your local image:

Docker tag {your repository name} {part repository URL}

Now that your image is retagged, you can now push it:

Docker push {part repository URL}

Now the deployment will automatically get deployed.

Once the image is pushed, Patr will detect the push, recognize the deployment that corresponds to the given image name and tag, and will automatically deploy it. The status will change from created, to pushed, deploying and finally to running. You can click on the Manage Deployment button to view more details of your deployment.

By default, your deployment will be assigned a randomly-generated URL that you can use to access it. You can access your deployment by using the following URL format — {your-port}-{deployment-id}.patr.cloud where your-port is the one that you mentioned while creating deployment and the deployment-id is the randomly generated unique id that will be in your address bar.

You can also view the deployment logs, change the environment variables, update the domain, etc. You can also push another image to the same image name and tag and the deployment will automatically get updated.

Ant that’s it, you’re done deploying your Django application!

--

--