Django, Jenkins, and GitHub Actions Deployment on AWS: Step-by-Step Detailed Guide

Django, Jenkins, and GitHub Actions Deployment on AWS: Step-by-Step Detailed Guide
07 October, 2024

In this guide, we will walk you through the entire process of deploying a Django application to AWS using Jenkins and GitHub Actions. By following these steps, you will be able to automate CI/CD pipelines, manage infrastructure using Jenkins and GitHub Actions, and ensure a scalable and reliable deployment for your Django applications.

Introduction

Deploying web applications has evolved significantly with the introduction of cloud platforms and DevOps tools. Combining Django, Jenkins, and GitHub Actions allows developers to leverage the benefits of Continuous Integration and Continuous Deployment (CI/CD), automated testing, and consistent delivery pipelines.

AWS (Amazon Web Services) offers a scalable and secure environment to deploy and host Django applications. With services like EC2 for compute power, S3 for storage, and RDS for databases, AWS simplifies infrastructure management for large-scale applications.

What You Will Learn:

  • Setting up an AWS EC2 instance for hosting Django applications.
  • Installing Jenkins on AWS EC2 for automated CI/CD.
  • Using Jenkins and GitHub Actions to automate the deployment process.
  • Configuring AWS services like S3 and RDS to support Django applications.

Prerequisites and Initial Setup

Before starting, ensure you have the following prerequisites:

  1. AWS Account: You need an active AWS account to create resources such as EC2, S3, and RDS.
  2. Django Application: Prepare a Django project with a requirements.txt file and a Dockerfile if you are using Docker.
  3. EC2 Key Pair: Create an EC2 key pair to enable SSH access to your EC2 instances.
  4. IAM User: Set up an IAM user with permissions to manage AWS resources like EC2, S3, and RDS.

Initial Setup:

  1. Create an S3 Bucket: Go to the AWS S3 console and create a new bucket for storing static and media files. Configure bucket permissions to allow access only to specific IAM roles.
  2. Create an RDS Instance: Set up a new PostgreSQL RDS database. Note down the endpoint, username, and password for configuring your Django application.
  3. Set Up a Virtual Environment: Create a Python virtual environment for your Django project and install dependencies using pip.
# Create a virtual environment
python3 -m venv venv

# Activate the virtual environment
source venv/bin/activate

# Install dependencies
pip install -r requirements.txt

Setting Up AWS EC2 for Django Deployment

Create an EC2 Instance:

- Go to the EC2 dashboard and click "Launch Instance."
- Choose the Amazon Linux 2 AMI (or Ubuntu 22.04 LTS if you prefer).
- Select the instance type, such as `t2.micro` for small-scale applications.
- Configure instance details, such as VPC, subnet, and IAM role if needed.
- Add storage and configure a security group to allow HTTP (port 80), HTTPS (port 443), and SSH (port 22) traffic.

Connect to the EC2 Instance:

After launching the instance, connect using SSH from your local machine:

ssh -i "your-key.pem" ec2-user@ec2-xx-xxx-xxx-xx.compute.amazonaws.com

Replace your-key.pem with the path to your key pair file, and ec2-xx-xxx-xxx-xx.compute.amazonaws.com with your EC2 public IP or DNS.

Install Required Software:

  • Update the package list and install Python, pip, Git, and Docker.
sudo yum update -y
sudo yum install -y python3 python3-pip git docker
  • Start Docker and add the EC2 user to the Docker group to avoid permission issues:
sudo service docker start
sudo usermod -aG docker ec2-user
  • Install other necessary tools like nginx if you plan to use it as a reverse proxy.

Installing and Configuring Jenkins on AWS EC2

Jenkins is a popular automation server used for building, testing, and deploying code. We'll install Jenkins on the EC2 instance and set up a basic pipeline for deploying Django applications.

Install Jenkins:

  • Add the Jenkins repository and import the GPG key:
sudo wget -O /etc/yum.repos.d/jenkins.repo \
       https://pkg.jenkins.io/redhat-stable/jenkins.repo
sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io.key
  • Install Jenkins and Java:
sudo yum install jenkins java-11-openjdk-devel -y
  • Start the Jenkins service and enable it to run on boot:
sudo systemctl start jenkins
sudo systemctl enable jenkins

Configure Jenkins:

  • Open Jenkins in a browser using http://<EC2_Public_IP>:8080.
  • Retrieve the initial admin password:
sudo cat /var/lib/jenkins/secrets/initialAdminPassword
  • Complete the Jenkins setup wizard and install recommended plugins.

Install Jenkins Plugins:

  • Install the following plugins for Django projects: Git, GitHub, Docker, SSH Agent, and Ansible.
  • Create a new Jenkins pipeline and integrate it with your GitHub repository.

Creating a Jenkins Pipeline for Django Deployment

  1. Create a Jenkinsfile:

The Jenkinsfile defines the steps Jenkins will take to build, test, and deploy your application. Place the file in the root of your Django project.

pipeline {
    agent any
    environment {
        AWS_ACCESS_KEY_ID = credentials('AWS_ACCESS_KEY')
        AWS_SECRET_ACCESS_KEY = credentials('AWS_SECRET_KEY')
    }
    stages {
        stage('Build') {
            steps {
                echo 'Building the project...'
                sh 'pip install -r requirements.txt'
            }
        }
        stage('Test') {
            steps {
                echo 'Running tests...'
                sh 'python manage.py test'
            }
        }
        stage('Deploy') {
            steps {
                echo 'Deploying the application...'
                sshagent (credentials: ['ec2-ssh-key']) {
                    sh '''
                    ssh -o StrictHostKeyChecking=no ec2-user@ec2-xx-xxx-xxx-xx.compute.amazonaws.com << EOF
                    cd /var/www/myapp
                    git pull origin main
                    source venv/bin/activate
                    pip install -r requirements.txt
                    python manage.py migrate
                    sudo systemctl restart gunicorn
                    EOF
                    '''
                }
            }
        }
    }
}

In this Jenkinsfile, replace the placeholders like AWS_ACCESS_KEY and ec2-ssh-key with your actual Jenkins credentials. This pipeline will install dependencies, run tests, and deploy the code to your EC2 instance using SSH.

Setting Up GitHub Actions for CI/CD

GitHub Actions is a powerful CI/CD tool that integrates seamlessly with GitHub repositories. It allows you to automate workflows for testing, building, and deploying applications.

  1. Create a GitHub Actions Workflow:

Create a .github/workflows/deploy.yml file in your GitHub repository:

name: Django CI/CD

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout code
      uses: actions/checkout@v2

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

    - name: Install dependencies
      run: pip install -r requirements.txt

    - name: Run Tests
      run: python manage.py test

    - name: Deploy to EC2
      env:
        AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
        AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        EC2_INSTANCE: 'ec2-user@ec2-xx-xxx-xxx-xx.compute.amazonaws.com'
        SSH_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
      run: |
        echo "$SSH_KEY" > deploy_key.pem
        chmod 400 deploy_key.pem
        scp -i deploy_key.pem -o StrictHostKeyChecking=no -r * $EC2_INSTANCE:/var/www/myapp/
        ssh -i deploy_key.pem $EC2_INSTANCE 'cd /var/www/myapp && source venv/bin/activate && pip install -r requirements.txt && python manage.py migrate && sudo systemctl restart myapp'

Configuring AWS S3 and RDS for Django Storage and Database

Configure S3 for Static and Media Files:

  • Install boto3 and django-storages:
pip install boto3 django-storages
  • Update settings.py:
AWS_ACCESS_KEY_ID = os.getenv('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = os.getenv('AWS_SECRET_ACCESS_KEY')
AWS_STORAGE_BUCKET_NAME = 'my-django-bucket'
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
  1. Configure RDS: Update the DATABASES configuration in settings.py to point to your RDS PostgreSQL instance:
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'mydatabase',
        'USER': 'myuser',
        'PASSWORD': 'mypassword',
        'HOST': 'mydbinstance.cxyzzzzzz.us-east-1.rds.amazonaws.com',
        'PORT': '5432',
    }
}

Deploying Django Application to AWS Using Jenkins

  1. Set Up Gunicorn and Nginx:
  2. Install Gunicorn and Nginx on your EC2 instance:
sudo yum install nginx
sudo pip install gunicorn
  1. Create a Gunicorn Service:

  2. Create a Gunicorn service file at /etc/systemd/system/gunicorn.service:

   [Unit]
   Description=gunicorn daemon for Django project
   After=network.target

   [Service]
   User=ec2-user
   Group=nginx
   WorkingDirectory=/var/www/myapp
   ExecStart=/var/www/myapp/venv/bin/gunicorn --workers 3 --bind unix:/var/www/myapp/myapp.sock myapp.wsgi:application

   [Install]
   WantedBy=multi-user.target
  1. Configure Nginx:

  2. Set up Nginx as a reverse proxy:

   server {
       listen 80;
       server_name mydomain.com;

       location / {
           proxy_pass http://unix:/var/www/myapp/myapp.sock;
           proxy_set_header Host $host;
           proxy_set_header X-Real-IP $remote_addr;
           proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
           proxy_set_header X-Forwarded-Proto $scheme;
       }

       location /static/ {
           alias /var/www/myapp/static/;
       }

       location /media/ {
           alias /var/www/myapp/media/;
       }
   }
  1. Restart Services:
  2. Restart Gunicorn and Nginx:
   sudo systemctl start gunicorn
   sudo systemctl enable gunicorn
   sudo systemctl restart nginx

Deploying Django Application Using GitHub Actions

GitHub Actions can also be used to deploy your Django application to AWS. Set up secrets in your GitHub repository, such as AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and SSH_PRIVATE_KEY.

The GitHub Actions workflow will build the Docker image, push it to an AWS ECR (Elastic Container Registry), and deploy it to an ECS (Elastic Container Service) cluster or directly to EC2.

  1. Build and Push Docker Image to ECR:
  2. Add a Dockerfile in your Django project root and define the environment.
  3. Use GitHub Actions to build and push the image:
- name: Build Docker Image
  run: docker build -t my-django-app .

- name: Login to AWS ECR
  run: $(aws ecr get-login --no-include-email --region us-east-1)

- name: Push Docker Image to ECR
  run: docker push <AWS_ACCOUNT_ID>.dkr.ecr.us-east-1.amazonaws.com/my-django-app:latest
  1. Deploy Docker Container to ECS:
  2. Create a task definition in ECS and deploy the Docker container.

Configuring Domain and SSL for Django Application

  1. Set Up Route 53:
  2. Create a hosted zone and add a record set pointing to your EC2 instance.

  3. Use AWS Certificate Manager:

  4. Request an SSL certificate and configure Nginx to use the certificate.
server {
    listen 443 ssl;
    server_name mydomain.com;

    ssl_certificate /etc/letsencrypt/live/mydomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/mydomain.com/privkey.pem;

    location / {
        proxy_pass http://unix:/var/www/myapp/myapp.sock;
    }
}

Monitoring and Logging Django Applications on AWS

  • Use CloudWatch for logs and set up alarms.
  • Install watchtower to ship logs to CloudWatch from your Django application.

Troubleshooting Common Issues

  • SSH Connection Issues: Check security group rules and SSH key permissions.
  • Jenkins Pipeline Failures: Review logs for syntax errors and permission issues.
  • GitHub Actions Workflow Failures: Check deploy_key.pem permissions and ssh command syntax.

Security Best Practices

  • Use IAM roles instead of hardcoding credentials.
  • Enable multi-factor authentication (MFA) for IAM users.
  • Restrict access to sensitive resources using security groups.

Cost Optimization

  • Use t2.micro instances for testing and t3.medium for production.
  • Utilize S3 lifecycle policies to transition infrequently accessed objects.

Future Enhancements

  • Implement load balancing with an AWS ALB.
  • Set up auto-scaling groups for EC2 instances.
  • Explore AWS Lambda for serverless functions and microservices.
line

Looking for an enthusiastic team?