Darslik · 2026-08-16 · ~6 daqiqa o‘qiladi · o'rta
push → test → deploy: shu saytning o'zi qanday chiqib turibdi
Mundarija
Bu maqolaning o'zi — mavzuning jonli isboti. Men uni yozib git push
qildim, keyin hech narsa qilmadim: GitHub Actions testlarni o'tkazdi,
serverga yukladi, xizmatni yangiladi va Telegram kanalimga e'lonni ham
o'zi yuborib qo'ydi. Qo'lda deploy degan tushuncha bu loyihada birinchi
haftadan keyin yo'qolgan. Bugun shu zanjirni boshidan oxirigacha, haqiqiy
fayllar bilan ko'rsataman — bularning hammasi
saytning ochiq repositoriysida
turibdi, solishtirib borishingiz mumkin.
Umumiy manzara#
git push (main)
│
▼
[checks] ruff → format → migratsiya tekshiruvi → pytest
│ hammasi yashil bo'lsa
▼
[deploy] rsync bilan serverga → uv sync → collectstatic → migrate
│ → systemctl restart → yangi maqolalarni kanalga e'lon qilish
▼
sayt jonli, kanalda post
Eng muhim tamoyil shu chizmaning o'zida: deploy testlardan keyin turadi. Buzuq kod serverga yetib bora olmaydi, chunki unga yo'l testlar orqali o'tadi.
checks: qo'riqchi job#
Workflow fayli .github/workflows/ci.ymlda yashaydi. Birinchi job to'rt
qatlamli tekshiruv:
# .github/workflows/ci.yml (qisqartirilgan, mohiyati saqlangan)
name: CI
on: push
jobs:
checks:
runs-on: ubuntu-latest
services:
postgres: # testlar haqiqiy Postgres bilan yuradi
image: postgres:16
env:
POSTGRES_PASSWORD: test
ports: ["5432:5432"]
steps:
- uses: actions/checkout@v7
- uses: astral-sh/setup-uv@v10.0.1
- run: uv sync
- run: uv run ruff check . # lint xatolari
- run: uv run ruff format --check . # formatlash buzilmaganmi
- run: uv run python manage.py makemigrations --check --dry-run
- run: uv run pytest -W error # testlar, warning ham xato
Ikkita qadam alohida izohga arziydi. makemigrations --check — modelni
o'zgartirib, migratsiya yaratishni unutgan holatni ushlaydi; bu xato lokalda
sezilmaydi-yu, production'da birinchi so'rovda portlaydi. pytest -W error
esa har warning'ni xatoga aylantiradi — kutubxonalar "bu funksiya keyingi
versiyada o'chadi" deb ogohlantirsa, siz buni deploy'dan oldin eshitasiz,
yarim yildan keyin sinib emas.
deploy: faqat main, faqat yashildan keyin#
deploy:
needs: checks # checks yiqilsa, bu job boshlanmaydi
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: SSH kalitni tayyorlash
run: |
mkdir -p ~/.ssh
echo "${{ secrets.DEPLOY_SSH_KEY }}" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
ssh-keyscan SERVER_IP >> ~/.ssh/known_hosts
- name: Deploy
run: DEPLOY_KEY=~/.ssh/deploy_key ./scripts/deploy.sh deploy@SERVER_IP
needs: checks va if: sharti birga ishlaydi: pull request'lar va boshqa
branch'lar faqat tekshiruvdan o'tadi, serverga esa faqat main'dagi yashil
push boradi.
Deploy kaliti: alohida va faqat shu ish uchun#
Serverga kirish uchun Actions'ga SSH kalit kerak. Bu yerda bitta qat'iy qoida bor: shaxsiy kalitingizni bermang — deploy uchun alohida kalit yasaladi:
# o'z kompyuteringizda:
ssh-keygen -t ed25519 -f deploy_key -C "github-actions deploy" -N ""
# ochiq qismini serverdagi deploy foydalanuvchisiga qo'shamiz:
ssh-copy-id -i deploy_key.pub deploy@SERVER_IP
# maxfiy qismini GitHub'ga: repo → Settings → Secrets → DEPLOY_SSH_KEY
cat deploy_key # shu matnni secret qilib saqlaysiz, faylni o'chirasiz
Secret — repo'ga emas, Secrets'ga
Kalit, token, parol — bular hech qachon repositoriy ichiga tushmasligi kerak, hatto private repo bo'lsa ham. GitHub Secrets aynan shu uchun: workflow o'qiy oladi, loglarda avtomatik yashiriladi, tarixda qolmaydi. Kalit tasodifan commit bo'lib ketsa, uni "o'chirish" yetmaydi — tarixda qoladi, almashtirish shart.
scripts/deploy.sh: serverda nima bo'ladi#
Deploy skripti — pipeline'ning serverga tegadigan qo'li. Mohiyati o'n qator:
#!/usr/bin/env bash
# scripts/deploy.sh (soddalashtirilgan)
set -euo pipefail
HOST=$1
# kodni serverga ko'chiramiz — .git, .venv, .env va var/ tegilmaydi
rsync -az --delete \
--exclude .git --exclude .venv --exclude .env --exclude var \
-e "ssh -i $DEPLOY_KEY" ./ "$HOST":/opt/mysite/
ssh -i "$DEPLOY_KEY" "$HOST" bash -s <<'REMOTE'
cd /opt/mysite
uv sync --frozen # bog'liqliklar lock fayl bo'yicha
.venv/bin/python manage.py collectstatic --noinput
.venv/bin/python manage.py migrate --noinput
sudo systemctl restart mysite-web # yoki reload — 2-qismda farqini ko'rgandik
.venv/bin/python manage.py announce_posts || true # yangi maqola bo'lsa kanalga
REMOTE
Oxirgi qatordagi || truega e'tibor bering: kanalga e'lon yuborish —
qo'shimcha qulaylik, deploy'ning sharti emas. Telegram API yotgan bo'lsa
ham sayt yangilanishi to'xtamasligi kerak.
Env drift: .env'ni rsync ko'chirmaydi
Skript .envni ataylab chetlab o'tadi — serverdagi sirlar repo'dan
kelmaydi. Buning teskari tomoni ham bor: kodga yangi muhit o'zgaruvchisi
qo'shsangiz, serverdagi .envga uni qo'lda yozib qo'yish kerak.
Men buni bir marta unutib, "lokalda ishlaydi, jonlida ishlamaydi" degan
klassik holatga tushganman — o'shandan beri yangi o'zgaruvchi qo'shish
checklist'imda alohida band turadi.
Ishlayotganini qanday bilaman#
Push'dan keyin ikki daqiqa ichida hammasi tugaydi. Kuzatish uchun terminaldan chiqish shart emas:
gh run watch # joriy run'ni jonli ko'rsatadi
gh run list --limit 5 # oxirgi natijalar
Yiqilgan deploy qo'rqinchli emas — u serverga yetmagan deploy. needs: checks
tufayli xato har doim serverdan oldin, GitHub'ning o'zida to'xtaydi. Mening
tajribamda eng ko'p yiqiladigan qadam — ruff format --check: lokalda
formatlashni unutib push qilasiz, CI eslatib qo'yadi.
Yakun#
CI/CD sirli narsa emas: bitta YAML fayl, bitta bash skript, bitta maxsus SSH kalit. Lekin bergan narsasi katta — har push serverga yetguncha to'rt tekshiruvdan o'tadi, deploy esa odamning kayfiyatiga emas, testlarning rangiga bog'liq bo'lib qoladi. Shu maqolani o'qib turganingizning o'zi pipeline ishlayotganining isboti.
Keyingi qismda muammo qidirish tomoniga o'tamiz: journalctl bilan loglarni o'qish — xizmat yiqilganda qayerdan boshlash va nimalarga qarash.