The background
Recently after I finished buiding an appointment scheduler in PHP1 without a framework (result: assignment-grade product), I’ve decided to learn Django for many reasons, being an SRE intern one of them. Going through a brilliant module on MDN2 gave me an awesome head start toward that end. Then I though of building an appointment scheduler again, but this time with Django in Python. While the experience so far has been great, in this post let’s only discuss about what’s in the title : )
The configuration
After setting up a server and getting our Django project onto a repo in GH (with a seperate prod branch), we can start automating the deployments right out from our repo. A workflow as follows shall get the job done without much hassle.
# This is a basic workflow to help you get started with Actions
name: Django site Deployment
# Controls when the action will run.
on:
# Triggers the workflow on push or pull request events but only for the prod branch
push:
branches: [ prod ]
pull_request:
branches: [ prod ]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "deploy"
deploy:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Saves SSH key to a file to be used by SSH
- name: Save SSH key
run: |
mkdir -p ~/.ssh/
echo "$SSH_KEY" > ~/.ssh/ssh_key
chmod 600 ~/.ssh/ssh_key
cat >>~/.ssh/config <<END
Host django-server
HostName $SERVER_IP
User $SERVER_USERNAME
IdentityFile ~/.ssh/ssh_key
END
echo $SSH_KNOWN_HOSTS > ~/.ssh/known_hosts
shell: bash
env:
SSH_KEY: ${{ secrets.SSH_KEY }}
SSH_KNOWN_HOSTS: ${{ secrets.SSH_KNOWN_HOSTS }}
SERVER_USERNAME: ${{ secrets.SERVER_USERNAME }}
SERVER_IP: ${{ secrets.SERVER_IP }}
# Runs a set of commands using the runners shell
- name: Update source at server
run: |
ssh django-server /bin/bash << EOF
cd $PROJECT_PATH/
ssh-agent bash
ssh-add /home/$SERVER_USERNAME/.ssh/deploy_key
git checkout prod
git pull --ff-only
EOF
shell: bash
env:
PROJECT_PATH: ${{ secrets.PROJECT_PATH }}
SERVER_USERNAME: ${{ secrets.SERVER_USERNAME }}
Above workflow assumes that we’ve already met the following requirements,
Stored as GitHub repository secrets:
- Private key $SSH_KEY
- Django server’s ip $SERVER_IP
- Django server’s username $SERVER_USERNAME
- Django server’s public ssh identity in $SSH_KNOWN_HOSTS (StrictHostKeyChecking yes—IPs may float)
- Path (i.e. absolute) of the repo clone directory in server
Public key of deploy_key added in GitHub repository deploy keys.
On Django Sever:
- /home/$SERVER_USERNAME/.ssh/known_hosts has the public key of $SSH_KEY.
- Public key of $SSH_KEY in /home/$SERVER_USERNAME/.ssh/authorized_hosts (perm: 640)
- deploy_key in /home/$SERVER_USERNAME/.ssh/ (perm: 600)
It is worth noting that methods exist which require different configurations from the above, and pleasent surprises are waiting to be met with while exploring on one’s own.