Skip to main content

CI/CD Deployment Guide

ScannerSky uses an automated continuous integration and continuous deployment (CI/CD) pipeline built on GitHub Actions and Docker Compose. Every push to the main branch triggers an automated deployment over SSH to the production server.


1. Architecture Overview

The CI/CD workflow ensures zero-downtime rolling updates, automated database schema migrations, static file collection, security checks, and live health verification.

graph LR
Dev["Developer Push (main)"] --> GA["GitHub Actions Runner"]
GA -->|"SSH (appleboy/ssh-action)"| Server["Production Ubuntu Server"]
Server --> GitPull["git pull --ff-only"]
GitPull --> Build["docker compose build django"]
Build --> Up["docker compose up -d --remove-orphans"]
Up --> Migrate["python manage.py migrate"]
Migrate --> Collect["python manage.py collectstatic"]
Collect --> Check["python manage.py check --deploy"]
Check --> Health["curl http://127.0.0.1/ (Healthcheck)"]

2. GitHub Actions Workflow

The deployment workflow is defined in .github/workflows/deploy.yml.

Workflow Triggers & Concurrency

  • Push Triggers: Automatically runs whenever commits are pushed to the main branch.
  • Manual Dispatch: Can be triggered manually from the GitHub Actions tab via workflow_dispatch.
  • Concurrency Locking: Uses the scannersky-production-deploy concurrency group with cancel-in-progress: false to ensure deployments queue safely and never collide.
name: Deploy to Ubuntu

on:
push:
branches:
- main
workflow_dispatch:

concurrency:
group: scannersky-production-deploy
cancel-in-progress: false

3. Required GitHub Secrets

Configure the following deployment secrets in your GitHub repository (Settings > Secrets and variables > Actions):

Secret NameDescriptionExample / Notes
DEPLOY_HOSTProduction server IP address or domain192.0.2.1 or scannersky.example.edu
DEPLOY_USERSSH user with sudo/docker privilegesubuntu or deploy
DEPLOY_SSH_KEYPrivate SSH key (ED25519 or RSA)-----BEGIN OPENSSH PRIVATE KEY-----...
DEPLOY_PORTSSH port on target server22

4. Production Deployment Execution Steps

When triggered, the pipeline executes the following automated shell script on the production host:

  1. Safety Snapshot: Records the current commit SHA (PREV_COMMIT) for easy rollback if needed.
  2. Repository Sync: Performs git fetch and git pull --ff-only to pull the latest codebase as the service user (scannersky).
  3. Container Build: Builds the Django container image (docker compose build django) to refresh dependencies and application code.
  4. Stack Launch: Starts all containerized services (web, db, nginx, minio) in detached mode with --remove-orphans.
  5. Database Migrations: Runs Django migrations automatically inside the container:
    docker compose exec -T django python manage.py migrate --noinput
  6. Static File Collection: Compiles and hashes static assets:
    docker compose exec -T django python manage.py collectstatic --noinput
  7. Production Security Check: Verifies security settings:
    docker compose exec -T django python manage.py check --deploy
  8. Healthcheck Probe: Queries the local endpoint (http://127.0.0.1/) to confirm the web server is actively responding.

5. Rollback Strategy

If a deployment fails the healthcheck or introduces an unexpected bug, roll back to the previous commit:

# SSH into production server
ssh deploy@scannersky.example.edu

# Switch to app directory
cd /srv/scannersky-django

# Checkout previous stable commit
sudo -u scannersky git checkout <PREV_COMMIT_SHA>

# Rebuild and restart containers
sudo -u scannersky docker compose up -d --build

# Run migrations if necessary
sudo -u scannersky docker compose exec -T django python manage.py migrate --noinput

6. Troubleshooting & Diagnostics

:::tip IT Operations Quick Commands

# View live container logs
docker compose logs -f --tail=100 django

# Check Nginx reverse proxy logs
docker compose logs -f nginx

# Inspect database connectivity
docker compose exec django python manage.py health_check

:::