Beginners Guide to GitHub Actions, Django and Docker
My submission as part of #actionshackathon21
My Workflow
I have recently been working on several Django projects some for school, some as side projects and others as par of freelance work.
Overtime, I realized the importance of having a basic Devops workflow in place. This enables to tweak according to the project needs and to have a clear and consistent workflow. This workflow can be thought of as a set of steps that are executed in order to ensure a project is built and deployed successfully.
I have also included alternative steps for docker and docker-compose files, however these are optional and can be removed if not needed.
This repository contains a skeleton Django App that can be used as a starting point for a Django project, Dockerfile, Docker compose file and workflow file. Installation instructions can be found in the README.md file.
Submission Category:
DIY Deployments
Yaml File or Link to Code
Overview of workflow
Let's start with a quick overview of the workflow. Our workflow is as follows:
- Once code is pushed to the main branch of the repository, we run 4 parallel jobs against 4 different python versions.
- Python 3.7, 3.8, 3.9, 3.10
- We then install the requirements using pip3.
- We run black to format the code.
- We run flake8 to check for errors and warnings.
- We run isort to sort the imports.
- We set up a PostgreSQL database.
- We run the migrations.
- We run the tests(if any).
- Finally, we run the docker-compose file to ensure no errors in container creation.
Enough Words Show Me the YAML
Let's take a look at the YAML file.
name: Zoo Django Actions
on: [push]
jobs:
build:
runs-on: ubuntu-latest
strategy:
max-parallel: 4
matrix:
python-version: [ 3.6, 3.7, 3.8, 3.9]
database-name:
- zoo_django_actions
database-password:
- postgres
database-user:
- postgres
database-host:
- 127.0.0.1
database-port:
- 5432
services:
postgres:
image: postgres:latest
env:
POSTGRES_DB: ${{ matrix.database-name }}
POSTGRES_USER: ${{ matrix.database-user }}
POSTGRES_PASSWORD: ${{ matrix.database-password }}
ports:
- 5432:5432
# Set health checks to wait until postgres has started
options:
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v2.4.0
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2.3.1
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Format with black
run: |
pip install black
# format the files with black
black .
- name: Lint with flake8
run: |
pip install flake8
# stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Sort imports
run: |
pip install isort
# stop the build if there are Python syntax errors or undefined names
isort .
isort --check --diff .
- name: Setup test database
env:
POSTGRES_DB_NAME: ${{ matrix.database-name }}
POSTGRES_USER: ${{ matrix.database-user }}
POSTGRES_PASSWORD: ${{ matrix.database-password }}
POSTGRES_DB_HOST: ${{ matrix.database-host }}
POSTGRES_DB_PORT: ${{ matrix.database-port }}
POSTGRES_DB: ${{ matrix.database-name }}
run: |
export DATABASE_URL=postgres://${{ matrix.database-user }}:${{ matrix.database-password }}@${{ matrix.database-host }}:${{ matrix.database-port }}/${{ matrix.database-name }}
export SECRET_KEY=test-secret-key
export DEBUG=1
- name: Run migrations
run: |
export DATABASE_URL=postgres://${{ matrix.database-user }}:${{ matrix.database-password }}@${{ matrix.database-host }}:${{ matrix.database-port }}/${{ matrix.database-name }}
export SECRET_KEY=test-secret-key
export DEBUG=1
export ALLOWED_HOSTS=localhost
export GITHUB_WORKFLOW=True
export MODE=workflow
python manage.py makemigrations
python manage.py migrate
python manage.py migrate --run-syncdb
python manage.py check
- name: Run tests
run: |
python manage.py test
env:
DATABASE_URL: postgres://${{ matrix.database-user }}:${{ matrix.database-password }}@${{ matrix.database-host }}:${{ matrix.database-port }}/${{ matrix.database-name }}
SECRET_KEY: test-secret-key
DEBUG: 1
ALLOWED_HOSTS: localhost
GITHUB_WORKFLOW: True
MODE: workflow
- uses: actions/checkout@v2.4.0
- name: Build the images and start the containers
run: |
export GITHUB_WORKFLOW=True
export MODE="Test"
docker-compose -f docker-compose.yml build
docker-compose -f docker-compose.yml up -d
# run: docker-compose up -d --build
- name: Stop containers
if: always()
run: docker-compose -f "docker-compose.yml" down
Each step is labelled with a name and a run block. The name is used to identify the step in the output. Also provides context for the step. It might seem daunting to understand all of this, but it's really simple. I recommend the GiHub Action documentation to get started.
First thing to note is workflow files are written in YAML. This is a simple way to structure your workflow. The YAML syntax is very similar to JSON. It's beyond the scope of this guide to explain the YAML syntax. However, to get started you can use the YAML Cheatsheet.
Now let's do a walk-through on adding this workflow to your project/repository:
- Create a new directory called
.github/
. Note the.
in the beginning. - Create a new directory called
workflows
inside the.github/
directory. - Create a new file called
main.yml
inside theworkflows
directory. This is the main workflow file. However, you can name it anything you want. - Copy the above code into the
main.yml
file. - Add and commit the
.github/workflows/main.yml
file to your project. This will allow you to run the workflow from the GitHub UI. $ git add .github/workflows/main.yml $ git commit -m "Add workflow" $ git push
- Now you can view your workflow on GitHub. You can also run the workflow from the GitHub UI.
Example workflow runs from the GitHub UI:
Bonus Points
GitHub Actions have a great feature, badges - which are small images that show up on your GitHub repository. You can use badges to show the status of your workflow. To add a badge to your README file:
- Go to your repository.
- Click on the Actions tab.
- Select the specific workflow you want to add a badge to.
- Click on the Create status badge button.
- Click on the Copy status badge Markdown button.
- Paste the markdown into your README file.
- Commit your changes.
- Push your changes to GitHub.
- View your badge on GitHub.
Additional Resources / Info
Tools and resources I used to create this workflow:
Wrap Up
You've now have simple workflow that can be used to run tests, build images, run migrations, and run tests. This is a great way to get started with GitHub Actions. Allows for so much extensibility. Go forth and automate your workflows!
This is the end of the guide. If you have any questions or comments, please feel free to reach out to me on Twitter @Ken_Mwaura1.
Happy Coding! ✨