How to create a CI/CD pipeline for your Django application using Github actions

May 1, 2021 - by Themba Mahlangu - 4 min read

Introduction

In this short how-to guide, you will set up a Continuous Integration / Continuous Deployment or Delivery (CI/CD) pipeline using Github actions.

When you’re finished, you’ll be able to set up a CI/CD pipeline for your next project. In this example, we are using a Django app but the concepts can be applied to any other framework or app.


LEVEL - 💻 💻 Intermediate developer

- Basic knowledge of Git & Docker required. We only explain the high-level concepts.

Key Terms

Continuous Integration (CI) - The practice of automating the integration of code changes from one or more contributors into a single repository.

Continuous Delivery (CD) - The practice of automating the deployment of all code changes to a testing and/or production environment.

Continuous Deployment (CD) - Similar to Continuous deployment except that all changes that pass the stages in the production pipeline are released to your end-users. This is done with no human intervention.

Github actions - A workflow automation tool that can be used to build, package, deploy, test a project on Github. Relevant terms would include:

Workflow - Configurable workflow made up of one or more jobs

Runner - is a type of machine that the job runs on.

Prerequisites

To complete this tutorial, you will need:

A Django starter project

Github account

Set up your project

Set up a simple Django project with basic unit tests. You can also

download our starter repo from here

to get you started.

Create the workflow

In your project repository root, create the .github/workflows directory and the workflow file django.yml.

*
Defining the events
*

First, we define the events that will trigger the workflow. In this case, it will be pushing to the main branch or the develop branch. Or pull requests to the same branches.

Code
 text

**

`
name: Django CI

on: # HERE we specify when the action should be performed.
push: # On pushing to the main or dev branch
branches:
- main
- develop
pull_request: # When PRs are made to the develop & main branches
branches:
- develop
- main

jobs: TODO
job_name:
runs_on: TODO..
strategy: TODO..
services: TODO..
steps: TODO..
`

*

Code
Adding our first job

** *

Next, we add the jobs. Our workflow will have one job called build. The workflow will run on a machine referred to as a runner called ubuntu-latest. This machine can be hosted by Github as in our case or self-hosted. See here for more information.

The strategy creates a build matrix for the jobs, here you can define different variations to run each job in. In our case, we want the job to run in both a python 3.8 and 3.7 environment. See the steps section below for more.

In the services section, we add the containers required for a job. Service containers are useful for creating databases or caches.

Code
 text

**

`

on: …
jobs:
build: # Job
runs-on: ubuntu-latest
strategy: # Strategy
max-parallel: 4
matrix:
python-version: [3.7, 3.8]
services:
postgres:
image: postgres
env:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: postgres
POSTGRES_USER: postgres
options: >- # add health check to ensure the db is ready before next step
–health-cmd pg_isready
–health-interval 10s
–health-timeout 70s
–health-retries 5
`

* Creating the steps
* **

Lastly, let’s add the steps to our workflow. Each step needs to have either a run argument that runs command-line programs using the system’s shell or a
uses
argument which references an action or reusable unit of code to be run in the step.

In the example below, we use the

actions/setup-python@v2

action to set up a Python environment. This action is used in the

Set up Python ${{ matrix.python-version }}

step. As defined in our strategy section earlier, this will be set up for two environments for Python 3.7 & 3.8.

The rest of the steps are standard Django steps for installing dependencies, running our tests as well as a code linter.

Code
 text

`

on:…
jobs:
build:
runs_on:…
strategy:…
services:..
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: psycopg2 prerequisites
run: sudo apt-get install libpq-dev
- name: Install dependencies
run: |
python -m pip install –upgrade pip
pip install -r requirements.txt
- name: Run migrations
run: python manage.py migrate
- name: Run tests
run: |
pytest
- name: Run lint with black
run: |
black .
`

Push to Github

That’s it, you can push to Github. If you have done everything correctly your workflow should build successfully.

Troubleshooting

Adding external services like DB and cache service e.g. Redis can complicate the workflow setup process. Check that you have set up the environment variables correctly and have used them consistently in your config files.

Each failed action will (usually) have a detailed stack trace/error message, use that to try and diagnose the error.

Useful links


Github Actions Documentation

Conclusion

You have learnt how to use Github actions to automate your workflows. Automating the workflows within your software development life cycle will save you time and improve the collaboration process for your team. It will also reduce the time it takes to develop and ship new features for your product. For more articles on DevOps visit our articles and resources section.