Cilj CI/CD-a za Django nije automatizacija radi automatizacije, nego ponovljiv put od commita do testiranog artefakta i, kad ste spremni, do deploya. GitHub Actions dovoljan je za većinu malih i srednjih Django projekata ako pipeline držite tankim, tajne van logova, a actione pinane.
Deploy target često je VPS s Compose stackom (Docker Compose u produkciji). Infrastrukturni dio (DNS, firewall, cloud resursi) bolje držati u IaC-u (Terraform i OpenTofu) nego u ad-hoc SSH skriptama.
Što pipeline treba raditi
Prvo lint i format check (ruff, black --check, ili što već koristite u repou). Zatim testovi: python manage.py test ili pytest uz Postgres/Redis service containere. Kad testovi prođu, build Docker imagea aplikacije i push u GHCR ili drugi registry, samo s main/taga. Deploy ostavite opcionalnim i eksplicitnim (environment protection, ručni approve).
Osnovni workflow (lint + test)
name: ci
on:
pull_request:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-24.04
services:
postgres:
image: postgres:16.6-alpine
env:
POSTGRES_USER: app
POSTGRES_PASSWORD: app
POSTGRES_DB: app
ports: ["5432:5432"]
options: >-
--health-cmd "pg_isready -U app"
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
DATABASE_URL: postgres://app:app@localhost:5432/app
DJANGO_SETTINGS_MODULE: config.settings.test
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
with:
python-version: "3.12"
cache: pip
- run: pip install -r requirements.txt -r requirements-dev.txt
- run: ruff check .
- run: python manage.py test
SHA pin (komentar s human tagom) smanjuje rizik supply-chain napada na floating tag @v4. Prije kopiranja provjerite aktualni commit SHA na releases stranici actiona. Tag se može pomaknuti, SHA ne.
Build i push imagea
build:
needs: test
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-24.04
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3.8.0
- uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@48aba3b46d1b1fec4febb7c5d0c644b249a11355 # v6.10.0
with:
context: .
push: true
tags: |
ghcr.io/${{ github.repository }}:${{ github.sha }}
ghcr.io/${{ github.repository }}:main
cache-from: type=gha
cache-to: type=gha,mode=max
Tagirajte image commit SHA-om. Deploy onda vuče točno isti artefakt koji je prošao CI. SHA-ove actiona gore možete zamijeniti novijim pinom kad bumpate verzije; bitan je princip pinanja na commit, ne floating tag.
Environments i tajne
Koristite GitHub Environments (staging, production) s required reviewers za production. Tajne držite u Environment secrets, ne u repou.
DJANGO_SECRET_KEY, DB URL i SSH ključ idu samo kao secrets. Nikad echo "${{ secrets.X }}" u stepovima "radi debuga". set -x u bashu može ispisati ekspandirane tajne, pa ga izbjegavajte uz secrets. Maskiranje u Actions nije savršeno; tretirajte logove kao polu-javne.
OIDC ukratko
Umjesto dugovječnih cloud access keyeva u secrets, GitHub Actions može dobiti kratkotrajni token preko OpenID Connect (OIDC) prema AWS/GCP/Azure. Postavite trust policy na cloud strani na repo:ORG/REPO:environment:production (ili sličan subject). Manje rotacije statičnih ključeva, uži blast radius. Za čisti VPS+SSH deploy OIDC nije obavezan, ali vrijedi čim pushate u cloud registry ili S3.
Deploy na VPS preko SSH (oprezno)
deploy:
needs: build
runs-on: ubuntu-24.04
environment: production
steps:
- name: Deploy over SSH
env:
HOST: ${{ secrets.VPS_HOST }}
KEY: ${{ secrets.VPS_SSH_KEY }}
IMAGE: ghcr.io/${{ github.repository }}:${{ github.sha }}
run: |
install -m 600 /dev/null key
printf '%s\n' "$KEY" > key
ssh -i key -o StrictHostKeyChecking=yes deploy@"$HOST" "cd /opt/app && IMAGE=$IMAGE docker compose pull web && docker compose up -d web"
Deploy korisnik treba ograničeni sudo (samo compose/systemctl za app), ne root login. Koristite StrictHostKeyChecking=yes i poznati known_hosts, ne StrictHostKeyChecking=no. Pullajte točan SHA tag, ne :latest. Migracije držite kao eksplicitni korak (docker compose run --rm web python manage.py migrate), ne skrivene u entrypointu bez kontrole. Nakon deploya healthcheck; rollback je prethodni SHA tag.
Kada su Actions dovoljni, a kada self-hosted runner
GitHub-hosted dovoljan je za lint/test/build većine Django appova. Plaćate minute i nemate održavanja runnera. Self-hosted ima smisla kad trebate pristup privatnoj mreži, GPU, veliki cache ili stroge compliance granice. Runner je dio vašeg napadnog površja: izolirajte VM, ne držite cloud root credentiale na njemu bez potrebe, koristite ephemeral runners gdje možete.
Česte greške
Nepinani actioni (uses: actions/checkout@v4 bez SHA) ostavljaju floating tag koji se može pomaknuti. Tajne u logovima i u artefactima (upload .env kao artifact) su klasična greška. Deploy s latest umjesto immutable SHA, jedan workflow koji radi CI i produkcijski deploy bez environment protection, široki permissions: write-all umjesto least privilege po jobu, i testovi protiv SQLite dok produkcija koristi Postgres (hvataju se drugačiji bugovi).
Django-specifični koraci u CI
Uz unit testove u CI-ju pokrenite i jeftine statičke provjere koje love produkcijske greške rano:
python manage.py check --deploy
python manage.py makemigrations --check --dry-run
check --deploy upozorava na nesigurne defaultne postavke. U test settingsima prilagodite očekivanja ili pokrenite check na jobu s produkcijski-like settingsima bez stvarnih tajni. makemigrations --check hvata izmjene modela bez migracijske datoteke prije mergea.
Collectstatic u CI-ju ili u Docker buildu ima smisla ako koristite WhiteNoise/manifest. Bolje failati u pipelineu nego na VPS-u. Ne commitajte lokalni staticfiles/ ako collectstatic ide u image build.
Branch protection i required checks
Pipeline vrijedi malo ako se main može mergeati bez zelenog CI-ja. Uključite branch protection: required status checks (test/build jobovi), bez force pusha na main, po mogućnosti required review. Environments za production dodaju još jedan approve prije SSH deploya.
Za monorepo ili sporije testove razdvojite brzi lint job od težeg test joba da PR feedback stigne brže. Required checks neka čekaju oba.
Zaključak
Actions pokrivaju većinu SMB Django deploya ako pipeline držite tankim i pinanim, s deployom odvojenim od CI-ja. Self-hosted tek kad hosted ne može dohvatiti mrežu ili performanse. Za postavljanje pipelinea i VPS deploja, DevOps usluge.