5 months, 1 week ago | 22 min Read | 158
hey folks, if you want to host your website or are already hosted on a virtual machine and are tired to push-pull code every time this blog post is for you where you learn about GitHub actions and how we can use it to automate the process once you push the code that Github action automatically Pull the code on Virtual machine and restart the services.
GitHub Actions is a CI/CD (Continuous Integration and Continuous Deployment) tool offered by GitHub. It enables you to automate your software development workflows directly in your GitHub repository. With Actions, you can create workflows that perform tasks based on specific events—such as pushing code to a repository, creating pull requests, or scheduling tasks at specific times.
In the context of a Django project, GitHub Actions can be used to automate tasks such as running tests, building your application, and deploying code to your virtual machine (VM). This way, you can keep your website or app up-to-date without manually logging into the server and pulling the latest code every time you make a change.
Let’s set up a basic workflow to automate the deployment of your Django project to your virtual machine.
In your Django project repository on GitHub, go to Actions and click on New workflow. GitHub offers several templates, but for now, let’s create a custom workflow. Follow these steps:
.github/workflows
directory in the root of your repository if it doesn't already exist.deploy.yml
(or any name you prefer).The name
defines the workflow’s name, and the on
section specifies when it will run. Here, the workflow runs whenever code is pushed to the main
branch.
name: Django Deployment on VM
on:
push:
branches:
- main # Specify the branch to deploy, e.g., "main"
This part of the workflow listens for pushes to the main
branch, which will automatically trigger the deployment process whenever you update this branch.
The jobs
section specifies what the workflow will do. Here, we define a job named deploy
, which runs on an ubuntu-latest
GitHub-hosted virtual environment.
jobs:
deploy:
runs-on: ubuntu-latest # Runs on a GitHub-hosted Ubuntu server
This line means our job will run on the latest version of Ubuntu, which is often compatible with most Django project requirements.
The checkout step pulls the latest code from the GitHub repository so that we can work with it in the virtual environment.
steps:
- name: Checkout code
uses: actions/checkout@v3 # Checks out your code
Using actions/checkout@v3
, we access the repository files and ensure they’re ready for the next steps.
To securely connect to the VM, we add a private SSH key as an environment variable (SSH_PRIVATE_KEY
). The workflow creates an .ssh
directory, saves the SSH key in ~/.ssh/id_rsa
, and sets the necessary permissions. The StrictHostKeyChecking no
setting bypasses prompts about host authenticity.
- name: Setup SSH key
env:
SSH_PRIVATE_KEY: ${{ secrets.DO_SSH_PRIVATE_KEY }}
run: |
mkdir -p ~/.ssh
echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
echo "StrictHostKeyChecking no" >> ~/.ssh/config
Here, we add the VM’s IP address to the known_hosts
file, allowing the GitHub Actions runner to verify the host's authenticity on SSH.
- name: Add Known Hosts
run: |
ssh-keyscan -H ${{ secrets.DO_SERVER_IP }} >> ~/.ssh/known_hosts
This step tests the SSH connection to ensure the VM is accessible before deployment. It uses the SSH command to print "SSH connection successful" if the connection is valid.
- name: Test SSH Connection
run: |
echo "Testing SSH connection..."
ssh -v root@${{ secrets.DO_SERVER_IP }} 'echo "SSH connection successful"'
env:
DO_SERVER_IP: ${{ secrets.DO_SERVER_IP }}
This step initiates the actual deployment. It runs commands on the VM using SSH, updating the project and restarting services as needed.
- name: Deploy to VM
env:
DO_SERVER_IP: ${{ secrets.DO_SERVER_IP }}
Let’s break down each part inside this Deploy to VM
step:
/path/to/your/project
doesn’t exist, it creates it.YOUR_USERNAME
and YOUR_REPO
with your GitHub information).
ssh root@$DO_SERVER_IP << 'ENDSSH'
set -e
echo "Starting deployment..."
# Check if directory exists
if [ ! -d "/path/to/your/project" ]; then
echo "Creating directory..."
mkdir -p /path/to/your/project
cd /path/to/your/project
git init
git remote add origin <https://github.com/YOUR_USERNAME/YOUR_REPO.git>
else
cd /path/to/your/project
fi
main
branch.
# Fetch latest changes
echo "Fetching latest changes..."
git fetch origin main || {
echo "Failed to fetch from origin"
exit 1
}
if ! git diff --quiet HEAD..origin/main 2>/dev/null; then
echo "Changes detected, updating code..."
git pull origin main
venv
) exists and activates it.requirements.txt
.
# Activate virtual environment if it exists
if [ -f "venv/bin/activate" ]; then
source venv/bin/activate
pip install -r requirements.txt
fi
manage.py
exists, runs Django migrations to update the database.
# Run Django commands if manage.py exists
if [ -f "manage.py" ]; then
python manage.py migrate --noinput
python manage.py collectstatic --noinput
fi
echo "Restarting services..."
# Restart Gunicorn
if systemctl is-active --quiet gunicorn; then
sudo systemctl restart gunicorn || {
echo "Failed to restart Gunicorn"
exit 1
}
echo "Gunicorn restarted successfully"
else
echo "Warning: Gunicorn service not active"
fi
# Restart Nginx
if systemctl is-active --quiet nginx; then
sudo systemctl restart nginx || {
echo "Failed to restart Nginx"
exit 1
}
echo "Nginx restarted successfully"
else
echo "Warning: Nginx service not active"
fi
echo "Deployment completed successfully"
else
echo "No changes detected. Skipping deployment."
fi
ENDSSH
If no changes are detected, the script skips the deployment, saving time and resources.
name: Django Deployment on VM
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v3
- name: Setup SSH key
env:
SSH_PRIVATE_KEY: ${{ secrets.DO_SSH_PRIVATE_KEY }}
run: |
mkdir -p ~/.ssh
echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
echo "StrictHostKeyChecking no" >> ~/.ssh/config
- name: Add Known Hosts
run: |
ssh-keyscan -H ${{ secrets.DO_SERVER_IP }} >> ~/.ssh/known_hosts
- name: Test SSH Connection
run: |
echo "Testing SSH connection..."
ssh -v root@${{ secrets.DO_SERVER_IP }} 'echo "SSH connection successful"'
env:
DO_SERVER_IP: ${{ secrets.DO_SERVER_IP }}
- name: Deploy to VM
env:
DO_SERVER_IP: ${{ secrets.DO_SERVER_IP }}
run: |
ssh root@$DO_SERVER_IP << 'ENDSSH'
set -e
echo "Starting deployment..."
# Check if directory exists
if [ ! -d "/path/to/your/projectz" ]; then
echo "Creating directory..."
mkdir -p /path/to/your/project
cd /path/to/your/project
git init
git remote add origin <https://github.com/YOUR_USERNAME/YOUR_REPO.git>
else
cd /path/to/your/project
fi
# Fetch latest changes
echo "Fetching latest changes..."
git fetch origin main || {
echo "Failed to fetch from origin"
exit 1
}
if ! git diff --quiet HEAD..origin/main 2>/dev/null; then
echo "Changes detected, updating code..."
git pull origin main
# Activate virtual environment if it exists
if [ -f "venv/bin/activate" ]; then
source venv/bin/activate
pip install -r requirements.txt
fi
# Run Django commands if manage.py exists
if [ -f "manage.py" ]; then
python manage.py migrate --noinput
python manage.py collectstatic --noinput
fi
echo "Restarting services..."
# Restart Gunicorn
if systemctl is-active --quiet gunicorn; then
sudo systemctl restart gunicorn || {
echo "Failed to restart Gunicorn"
exit 1
}
echo "Gunicorn restarted successfully"
else
echo "Warning: Gunicorn service not active"
fi
# Restart Nginx
if systemctl is-active --quiet nginx; then
sudo systemctl restart nginx || {
echo "Failed to restart Nginx"
exit 1
}
echo "Nginx restarted successfully"
else
echo "Warning: Nginx service not active"
fi
echo "Deployment completed successfully"
else
echo "No changes detected. Skipping deployment."
fi
ENDSSH
To securely connect to your virtual machine, add an SSH key to your repository secrets:
SSH_KEY
) and paste the content of your private SSH key.like here I use do_server_ip and do_ssh_private_key (make sure you want to copy the complete private key )
-----BEGIN OPENSSH PRIVATE KEY-----
[key content]
-----END OPENSSH PRIVATE KEY-----
The "server_ip" refers to your virtual machine's IP address. It's similar to when you run the SSH command locally using "ssh username@host" — in this case, we use the host (IP address) for the connection.
Push a change to your main
branch (or whichever branch you specify). GitHub Actions should now trigger the workflow, deploy your changes, and restart your Django services on your virtual machine!
Hello! My name is Jatin Yadav and I enjoy creating websites I completed my graduation on june ,2018 and I want to be a professional web developer. The word which
Read More >