Beginners Guide to Deploying Django Apps
Day 333 / 366
CI / CD can be intimidating. Docker, Kubernetes, and Jenkins are all terms that used to go over my head when I started working as a freelancer. So I always resorted to manually deploying my Django applications.
This is the easiest way I used to deploy my Django apps
- I would get a Linux server from AWS, Linode, or something similar
- I would clone my app on the server and set it up with Virtualenv and a SQLite DB just like I would do locally.
- I would start a screen session on the server and run the app in it. This way the app will keep running even if I close my terminal.
With this setup done, on every code change, I would ssh into the server, do a git pull to get the latest changes, run any migrations or installations if needed and restart the server.
This is a good enough setup for prototypes and MVPs, and if you replace
screen” with tmux
runserver” with gunicorn
sqlite” with postgresql
Then it becomes a good enough staging deployment for most Django projects.
Automating the process with GitHub Actions
While the manual deployment takes a few minutes at max, there are still things to be gained by automating it.
- You eliminate the possibility of human errors. What if you forgot to run migrations when deploying?
- When you know that your commits and PR merges are going to always get deployed, you tend to be more careful about them and pay more attention to testing locally.
- Once you have a basic CI / CD pipeline in place, you can keep adding steps to it like running unit tests or static code analysis.
GitHub Actions are a great way to do this.
Step 1 — Register your server as a self-hosted runner on GitHub
You can do this by going to settings > actions > runners and clicking on the “New self-hosted runner” button. There you will find all the commands that you need to run on your server in order to register it as a runner.
This allows us to run commands on our server automatically whenever any new code is pushed.
Step 2 — Add a workflow file to your repo
The workflow file contains the list of commands that we want to run when we need to deploy any code changes. This would essentially be the same steps we take when deploying manually.
Here’s what the file would look like
name: Django Build
on:
push:
branches:
- staging
jobs:
build:
runs-on: self-hosted
steps:
- name: Pull latest code
working-directory: /home/ubuntu/my-backend
run: git pull
- name: Install dependencies
working-directory: /home/ubuntu/my-backend
run: /home/ubuntu/my-backend/venv/bin/pip install -r requirements.txt
- name: Run migrations
working-directory: /home/ubuntu/my-backend
run: /home/ubuntu/my-backend/venv/bin/python manage.py migrate
Here “self-hosted” is the label added to our runner. This tells GitHub where to run these commands. All we are doing is pulling the latest code, making installations and running migrations.
Note that this works if you are using “runserver” in your deployment since it restarts automatically when you change your code. If you used something different, then you will need to add a step to restart your Django app as well.
And that is pretty much it. I’m not claiming that this setup would work for an app with a million users as well. All I am saying is that this is an easy and less intimidating starting point for beginner devs who want to learn some DevOps as well.