Django Portfolio Journal

Automating CI/CD with GitHub Actions for a Docker-Based Django Application


In the ever-evolving world of software development, Continuous Integration and Continuous Delivery (CI/CD) are pivotal for ensuring rapid, reliable, and resilient application development and deployment processes. GitHub Actions provides an awesome platform to automate these workflows. This article will break down a GitHub Actions configuration file designed to build and push Docker images to Docker Hub whenever changes are pushed to the main branch or pull requests are made against it.

Preparation:

Setting up secrets on GitHub is a straightforward process and is essential for securely storing sensitive information like API keys, tokens, or other credentials.

    1. Navigate to your repository on GitHub.
    2. Click on the "Settings" tab.
    3. In the left sidebar, click on "Secrets and variables" > "Actions".
    4. Click the "New repository secret" button.
    5. Add the SECRET_KEY secret:
      • Name: SECRET_KEY
      • Value: (Your secret key value)
      • Click "Add secret".

Repeat the steps to add ALLOWED_HOSTS, DEBUG, DOCKERHUB_TOKEN and USERNAME secrets. (If you have different usernames for Docker Hub and GitHub, then create several secrets)

Overview of the GitHub Actions Workflow

Let's take a look at the provided config.yml file, which is located in .github/workflows/ directory:

name: Continuous Integration and Delivery

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main
jobs:
  build:
    name: Django Project
    runs-on: ubuntu-latest
    env:
      SECRET_KEY: ${{ secrets.SECRET_KEY }}
      ALLOWED_HOSTS: ${{ secrets.ALLOWED_HOSTS }}
      CSRF_TRUSTED_ORIGINS: ${{ secrets.CSRF_TRUSTED_ORIGINS }}
      DEBUG: ${{ secrets.DEBUG }}
      SENTRY_DSN: ${{ secrets.SENTRY_DSN }}

    steps:
    - name: Checkout code
      uses: actions/checkout@v3

    - name: Set up Python
      uses: actions/setup-python@v2
      with:
        python-version: '3.11'

    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install -r requirements.txt

    - name: Lint with flake8
      run: flake8

    - name: Run Django migrations
      run: |
        python manage.py migrate

    - name: Run Django tests
      run: |
        python manage.py test

  docker:
    name: Docker
    runs-on: ubuntu-latest
    env:
      SECRET_KEY: ${{ secrets.SECRET_KEY }}
      ALLOWED_HOSTS: ${{ secrets.ALLOWED_HOSTS }}
      CSRF_TRUSTED_ORIGINS: ${{ secrets.CSRF_TRUSTED_ORIGINS }}
      DEBUG: ${{ secrets.DEBUG }}
      SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
      COMMIT_HASH: ${{ github.sha }}

    steps:
      - name: Checkout repository
        uses: actions/checkout@v3

      - name: Build the Docker image
        run: |
          docker build -t django-portfolio .
          docker images

      - name: Tag the Docker image
        run: docker tag django-portfolio:latest doridoro/django-portfolio:latest

      - name: Login to DockerHub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Push Docker image to Docker Hub
        run: docker push doridoro/django-portfolio:latest

Breakdown of the Workflow

This GitHub Actions configuration file, named Continuous Integration and Delivery, automates the workflow for testing, building, and deploying a Django application on pushes and pull requests to the main branch. The workflow is split into two main jobs: build and docker, each serving distinct roles in the CI/CD pipeline.

Workflow Name and Triggers

name: Continuous Integration and Delivery

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main
    • Workflow Name: This is set to "Continuous Integration and Delivery".

    • Triggers: The workflow triggers on two events:

      • push to the main branch.
      • pull_request events targeting the main branch.

This ensures that the workflow runs whenever code is pushed to the main branch or when a pull request is created or updated against the main branch.

Job 1: build

This job, labeled Django Project, is dedicated to setting up the environment, installing dependencies, running code linting, applying database migrations, and executing tests to ensure code quality and correctness.

Job Environment

    • It runs on ubuntu-latest and sets environment variables using GitHub secrets for sensitive data:
      • SECRET_KEY: Django’s secret key, critical for cryptographic operations.
      • ALLOWED_HOSTS: A list of hosts/domains for CSRF validation.
      • CSRF_TRUSTED_ORIGINS: Trusted origins for Cross-Site Request Forgery protection.
      • DEBUG: A flag to enable or disable debug mode.
      • SENTRY_DSN: The DSN for Sentry, used for monitoring errors.

Steps in build

    1. Checkout code: Uses actions/checkout@v3 to pull the code from the repository into the runner.

    2. Set up Python: Configures Python 3.11 using actions/setup-python@v2, ensuring the specified Python version is available.

    3. Install dependencies: Upgrades pip and installs packages from requirements.txt, ensuring the project has all necessary dependencies.

    4. Lint with flake8: Runs flake8 to check code for PEP8 compliance, helping maintain code quality by catching syntax errors and style issues.

    5. Run Django migrations: Executes python manage.py migrate to apply any new or modified database migrations, ensuring the database schema is up-to-date.

    6. Run Django tests: Executes python manage.py test to run unit tests and validate that the code functions as expected without breaking changes.

Job 2: docker

This job, labeled Docker, focuses on building and pushing a Docker image of the Django project to Docker Hub, preparing it for deployment.

Job Environment

    • It also runs on ubuntu-latest and includes the same environment variables as the build job, plus:
      • COMMIT_HASH: A unique identifier for the specific commit (github.sha), used for tagging and versioning the Docker image.

Steps in docker

    1. Checkout repository: Similar to the build job, it pulls the latest code from the repository.

    2. Build the Docker image: Uses docker build to create a Docker image named django-portfolio based on the Dockerfile. After building, it lists the images to confirm success and view image details.

    3. Tag the Docker image: Adds a tag latest to the Docker image (django-portfolio:latest) to distinguish it as the most recent build.

    4. Login to DockerHub: Uses docker/login-action@v3 to authenticate with Docker Hub. GitHub secrets store the Docker Hub username (USERNAME) and access token (DOCKERHUB_TOKEN), providing secure credentials without exposing them in the workflow.

    5. Push Docker image to Docker Hub: Pushes the tagged Docker image to Docker Hub under the repository doridoro/django-portfolio:latest, making it available for deployment.

This GitHub Actions configuration thus ensures that every commit or pull request to the main branch is automatically linted, tested, and, if successful, the updated application is containerized and pushed to Docker Hub. This setup streamlines the CI/CD process, providing a robust system for consistent, reliable application deployment.

 

This GitHub Actions configuration automates the CI/CD pipeline for a Django project containerized with Docker. The process ensures that the Docker image is built and pushed to Docker Hub every time code is pushed or updated on the main branch, making sure that your deployments are up-to-date and reliable.

    • Automated Builds: You no longer need to manually build and push Docker images, ensuring consistency and saving time.
    • Secure and Efficient: Using encrypted secrets for Docker Hub credentials ensures security, while automated workflows enhance efficiency and reliability.
    • Multi-platform Support: The setup steps including QEMU and Buildx ensure that you can build images for multiple architectures if necessary.

By integrating this workflow into your project, you bring the power of continuous integration and delivery to your development pipeline, fostering a healthier, faster, and more reliable deployment cycle.


Designed by BootstrapMade and modified by DoriDoro