Skip to content

Sample Django Deployment

Ritesh Chitlangi edited this page May 29, 2021 · 6 revisions

Here is a step-by-step demonstration of how to use deploy-scripts with a brand new Django project.

If you already have an existing project, you can skip to step 4 to see how to add deployment support to it.

  1. Installing python virtual env
  2. Create a fresh Django project
  3. Push the project to your repo
  4. Install deploy scripts
  5. Add deploy scripts to project
  6. Set deploy-scripts variables
  7. Execute the deployment
  8. Dockerization (optional)

Installing python venv

First, we need to install python virtualenv. On Debian or Ubuntu Linux, we start by installing the python3-venv package

$ sudo apt install python3-venv

Create a fresh Django project

Then we create a virtual environment and initialize a basic Django project. We also add our SSH key to our own authorized_keys file since we are doing the demo deployment on our local machine instead of a remote server

# Add your SSH public key to allow access to your own user account
$ cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
# We start by creating a directory for the demo
$ cd ~ && mkdir ds_test && cd ds_test
# Following which we initialize a pyvenv environment in the directory
$ python3 -m venv venv
# Activate the virtual environment
$ source venv/bin/activate
# Update pip and install django in the virtual env
(venv) ~/ds_test $ pip install -U pip && pip install "django<3"
# Now we can create a fresh Django project which we will attempt to deploy
(venv) ~/ds_test $ django-admin startproject django_project
(venv) ~/ds_test $ cd django_project/
(venv) ~/ds_test $ python manage.py migrate
# Run the project and see that it is properly accessible through the browser at http://127.0.0.1:8000/
(venv) ~/ds_test $ python manage.py runserver
# Stop the server and add a requirements.txt file listing the dependencies that will be needed by the deployment.
# We will use uwsgi to serve the app on the server side
(venv) ~/ds_test/django_project $ printf "uwsgi\ndjango<3" > requirements.txt

Here is a screenshot of the above steps being executed:

Push the project to your repo

Push the newly created project to your repo on github or another git host. If you don't want to create a new repository online, you can just create a local one in /tmp with these following steps:

(venv) ~/ds_test/django_project $ mkdir /tmp/django_project.git && cd /tmp/django_project.git && git init --bare && cd ~/ds_test/django_project/
(venv) ~/ds_test/django_project $ git init && git add . && git commit . -m "demo project commit"
(venv) ~/ds_test/django_project $ git remote add origin ssh://$USER@localhost/tmp/django_project.git
(venv) ~/ds_test/django_project $ git push -u origin master

Here is a screenshot of a push to a locally created repo using the above steps:

Install deploy scripts

Install the stable version of deploy-scripts to your home directory

(venv) ~/ds_test/django_project $ git clone --single-branch --branch 0.6.0 https://github.com/loanstreet/loanstreet/deploy-scripts.git $HOME/.deploy-scripts/0.6.0

Here is a screenshot of deploy-scripts being downloaded to the home directory

Add deploy scripts to project

Add deploy scripts to your project

# Run the command to install deploy scripts to the project. The usage is 
# sh install.sh [project-type] [project-root]
(venv) ~/ds_test/django_project $ sh ~/.deploy-scripts/0.6.0/installer/install.sh python ~/ds_test/django_project

Here is a screenshot showing the addition of deploy-scripts file to your project. By default, it's installed under a directory called deploy/ in the root of the project

Set deploy-scripts variables

Deployment is configured mainly through editing project-wide variables in deploy/app-config.sh, and environment-specific variables in deploy/environments/[environment name]/config.sh.

In our case we will use 'development' as the environment name.

Any other project specific configuration may be done in files placed in the assets/ directory in deploy/environments/[environment name]/assets/. In this example, we are using uwsgi to serve the app, and we configure the relevant uwsgi.ini in the assets directory that will be used for it.

# Set the variables in deploy/app-config.sh
TYPE=python
SERVICE_NAME=example.com
# Use either your own project repo on github, or for this example, the local repo you configured in step 3
#[email protected]:user/django_project.git
REPO="ssh://$USER@localhost/tmp/django_project.git"
# The server where your application is to be deployed
DEPLOYMENT_SERVER=localhost
# The ssh user to use when accessing the server to send your deployment to
DEPLOYMENT_SERVER_USER=$USER
RESTART_COMMAND="sh deploy/run.sh restart"
FORMAT=django
LINKED_FILES=""
LINKED_DIRS="venv uploads logs public tmp/sockets tmp/pids"


# Set the variables in deploy/environments/[environment name]/config.sh
# In this case we are using 'development' as the [environment name]
GIT_BRANCH=master
# Let uwsgi run the app on port 9000 instead of a unix socket, so we can check after deployment at the url http://127.0.0.1:9000/
SERVICE_PORT=9000

# Setup deploy/environments/<environment name>/assets/uwsgi.ini with the proper details. In our case, we only need to edit the 'module' value for our project
[uwsgi]
module = django_project.wsgi:application

master = true
processes = 5

chmod-socket = 666
vacuum = true

die-on-term = true

Here is a screenshot of the variables and uwsgi.ini being configured for the demo project

Execute the deployment

Finally, execute the deployment for the environment we have configured and it should deploy to your server and start the uwsgi process to serve the app.

In our example, we may verify that the app has been deployed and is being served by going to http://127.0.0.1:9000/

# Execute the deployment
# The usage is to execute the deploy.sh script with the environment name as the argument
# sh deploy/deploy.sh [environment name]
(venv) ~/ds_test/django_project $ sh deploy/deploy.sh development

Here are the screenshots that show the demo project being deployed.

  1. The deploy-scripts project is updated and the branch to be deployed is checked out and prepared for the push to the server

  1. The files to be sent to the server are pushed to a bare repo on the server and a post-receive hook is triggered on the server to configure the deployment

  1. Finally, the app server is started to serve the app (using uswgi in this case)

You can verify that the app is being served by going to http://127.0.0.1:9000/

Dockerization

If you wish to dockerize the project on the server, you need to install the docker and docker-compose command line tools on the server and configure 2 files in the project

  • deploy/docker/Dockerfile

  • deploy/docker/docker-compose.yml

and add a variable DOCKERIZE=true to deploy/environments/development/config.sh

Set Dockerfile and docker-compose.yml to dockerize the project and serve it with docker-compose on the server. For the demo project we are working with, the files would look something like this:

deploy/docker/Dockerfile

FROM python:3.8-alpine

ENV APP_HOME /app
RUN mkdir $APP_HOME
WORKDIR $APP_HOME

COPY requirements.txt ${APP_HOME}/
RUN apk update && apk add --no-cache libpq libstdc++ \
        && apk add --no-cache --virtual .build-deps \
        postgresql-dev \
        gcc \
        musl-dev \
        linux-headers \
        alpine-sdk \
        && pip install -U pip \
        && pip install --no-cache-dir -r requirements.txt \
        && apk del --no-cache .build-deps

ADD . $APP_HOME

RUN rm -rf Dockerfile docker-compose.yml && echo $'cd /app\npython manage.py runserver 0.0.0.0:80' > start.sh

EXPOSE 80

CMD ["sh", "start.sh"]

deploy/docker/docker-compose.yml

version: '2'

services:
  default:
    image: django_project:latest
    restart: always
    build:
      context: .
      dockerfile: Dockerfile
    volumes:
      - ./../../shared:/shared
    ports:
      - 8000:80
    env_file:
      - ./deploy/config.sh

deploy/environments/development/config.sh

GIT_BRANCH=master
SERVICE_PORT=9000
# Dockerize the project on the server after deployment
DOCKERIZE=true

Once the files have been configured, we can execute the deployment again and see that it dockerizes the app after deployment, and can be accessed at http://127.0.0.1:8000 (or whichever relevant port you configured in docker-compose.yml)

$ sh deploy/deploy.sh development

Here are the screenshots that show the app being dockerized on the server during deployment: