15 β Avtomatik deploy¶
β¬ οΈ Oldingi: 14 β Docker image CI va GHCR Β· π README Β· Keyingi: 16 β Nginx asoslari β‘οΈ
Bu bobda: CI/CD zanjirini oxirigacha yopamiz β 14-bobda image GHCR'ga push bo'lgan edi, endi uni serverga avtomatik deploy qilamiz. Asosiy usul β push-based SSH deploy: GitHub Actions job serverga
sshbilan kiradi vadocker compose pull && docker compose up -dqiladi (SSH kalit, host, usersecrets'da). Buni ikki yo'l bilan ko'rsatamiz: tayyorappleboy/ssh-action@v1.2.5va sofssh+known_hosts. So'ngenvironments(staging va production) bilan deployni boshqaramiz:push main'da staging avtomatik, production esa qo'lda APPROVAL (protection rules, required reviewers, environment secrets) ortida; triggerlar βon push,on release/tag,workflow_dispatch. Rollback'ni o'rganamiz β oldingi immutable tag'ga (sha/semver) qaytib qaytaup; zero-downtime kirish (up -dyangi konteyner ko'taradi, healthcheck o'tgach eskisini o'chiradi); pull-based alternativa (Watchtower / GitOps β 24-bobga ishora) va deploy xavfsizligi (alohida cheklangan SSH user, secrets'ni logda ko'rsatmaslik).
Muammo: image tayyor, lekin serverda hali eski versiya¶
14-bobda chiroyli ish qildik: har git pushda GitHub Actions namuna ilovamizning (vazifalar-api) Docker image'ini quradi va ghcr.io/foydalanuvchi/vazifalar-api ga push qiladi. Registry'da :latest, :main, :sha-abc1234 teglari yaltirab turibdi.
Lekin... serverda nima o'zgardi? Hech nima. Server hali ham eski image bilan ishlayapti. Yangi versiyani ko'rsatish uchun kimdir hali ham ssh qilib kirib, docker compose pull va docker compose up -d qilishi kerak. Ya'ni 5-bobdagi 5-og'riq β "har yangilashda yana qo'lda" β to'liq yo'qolmadi: biz faqat build'ni avtomatlashtirib, deploy'ni qo'lda qoldirdik.
Bu bobda zanjirning oxirgi bo'g'inini ulaymiz: push qildingiz -> sekundlar ichida server yangi versiyada. Odam aralashuvisiz (production'da β bitta tasdiq tugmasi bilan).
π Bu bobning ilovasi β kitob bo'ylab kelayotgan o'sha
vazifalar-api. Serverda u allaqachoncompose.yamlbilan ishlamoqda (11-bob) va image GHCR'da (14-bob). Bizga faqat "yangi image'ni tortib qo'yadigan" deploy bosqichi qoldi.
Deploy oqimi: build'dan serverga¶
Avtomatik deployning to'liq manzarasi quyidagicha. Build job image quradi va GHCR'ga push qiladi; deploy job esa serverga ssh bilan kirib, o'sha yangi image'ni tortib oladi va konteynerni qayta ko'taradi.
E'tibor bering: deploy job build job tugagach ishlaydi (needs: build), chunki tortib oladigan image avval registry'da paydo bo'lishi kerak. Server tomonida hech qanday build yo'q β server faqat tayyor image'ni pull qiladi. Bu push-based deployning go'zalligi: server "ohist" qoladi, og'ir build ishi CI'da bo'ladi.
π‘ "Push-based" nomi shundan: CI server tomon itaradi (push qiladi). Buning aksi β "pull-based": server o'zi registry/Git'ni kuzatib, o'zgarishni tortib oladi (bob oxirida Watchtower/GitOps). Boshlash uchun push-based soddaroq va tushunarliroq.
Server tomoni: deploy nima qiladi¶
Avval serverda nima sodir bo'lishini aniq tushunaylik β workflow shunchaki shu buyruqlarni masofadan chaqiradi. Serverda loyiha papkasida (masalan /srv/vazifalar-api) compose.yaml turadi va u image'ni GHCR'dan oladi:
services:
api:
image: ghcr.io/foydalanuvchi/vazifalar-api:latest
restart: unless-stopped
ports:
- "127.0.0.1:3000:3000"
healthcheck:
test: ["CMD", "node", "-e", "fetch('http://localhost:3000/tasks').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
interval: 10s
timeout: 3s
retries: 3
start_period: 5s
βΉοΈ
127.0.0.1:3000:3000β port faqat serverning o'ziga ochiq (tashqariga emas); oldida Nginx turadi (16-17-boblar).healthcheckβ Docker ilova "tirik"ligini tekshiradi; zero-downtime uchun keyin asqotadi.
Deploy paytida serverda bajariladigan skript β deploy.sh:
#!/usr/bin/env bash
set -euo pipefail
cd /srv/vazifalar-api
# Yangi image'ni GHCR'dan tortib olish
docker compose pull
# Yangi konteynerni ko'tarish, eskisini almashtirish, yetim konteynerlarni tozalash
docker compose up -d --remove-orphans
# Ishlatilmayotgan eski image'larni tozalash (disk to'lib qolmasin)
docker image prune -f
Bu skriptdagi har bir buyruq aniq vazifa bajaradi:
docker compose pullβcompose.yaml'dagiimage:tegiga mos yangi image'ni registry'dan tortadi. Agar registry private bo'lsa, oldindocker login ghcr.ioqilingan bo'lishi kerak (pastda).docker compose up -d --remove-orphansβ o'zgargan servislar uchun yangi konteyner yaratadi, eskisini to'xtatib o'rniga qo'yadi (-dβ fonda).--remove-orphansβcompose.yaml'dan olib tashlangan servislarning eski konteynerlarini tozalaydi.docker image prune -fβ endi hech qaysi konteyner ishlatmaydigan "osilib qolgan" (dangling) image'larni o'chiradi; aks holda har deployda disk to'lib boradi.
β οΈ Bu server qadamlari illustrativ β ular haqiqiy VPSda bajariladi. Lokal mashinada bu skriptning sintaksisini tekshirish mumkin (
bash -n deploy.sh), lekindocker compose pullreal serverda, GHCR'ga ulanish bilan ishlaydi. Buyruqlar to'g'ri yozilgan β o'z serveringizda sinab ko'ring.
Push-based deploy: GitHub Actions serverga SSH bilan kiradi¶
Endi workflow yozamiz. G'oya oddiy: build job image'ni push qilgach, deploy job serverga ssh orqali kirib yuqoridagi buyruqlarni bajaradi. Buning uchun GitHub'ga serverga kirish ma'lumotlari kerak β ularni hech qachon kodga yozmaymiz, balki repository secrets'da saqlaymiz.
Kerakli secrets (repo Settings -> Secrets and variables -> Actions):
| Secret | Nima | Misol |
|---|---|---|
DEPLOY_HOST |
server IP yoki domen | 203.0.113.10 |
DEPLOY_USER |
deploy uchun SSH user | deploy |
DEPLOY_SSH_KEY |
maxfiy SSH kalit (private key) | -----BEGIN OPENSSH PRIVATE KEY-----... |
DEPLOY_PORT |
SSH port (ixtiyoriy) | 22 |
π
DEPLOY_SSH_KEYβ bu serverga kiruvchi maxfiy kalitning (private key) to'liq matni. Uni alohida, faqat deploy uchun yaratilgan kalit juftligidan oling (pastda "Xavfsizlik" bo'limi). Hech qachon shaxsiy kalitingizni ishlatmang.
Variant A: appleboy/ssh-action (soddaroq)¶
Eng keng tarqalgan yo'l β tayyor appleboy/ssh-action. U SSH ulanishini, kalit va known_hosts bilan bog'liq mayda-chuydani o'zi hal qiladi; siz faqat serverda bajariladigan script'ni berasiz.
name: Deploy
on:
push:
branches: [main]
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v6
- uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v7
with:
context: .
push: true
tags: ghcr.io/${{ github.repository }}:latest,ghcr.io/${{ github.repository }}:sha-${{ github.sha }}
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- name: Serverga SSH bilan deploy
uses: appleboy/ssh-action@v1.2.5
with:
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_SSH_KEY }}
port: ${{ secrets.DEPLOY_PORT }}
script: |
set -e
cd /srv/vazifalar-api
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
docker compose pull
docker compose up -d --remove-orphans
docker image prune -f
Bu yerda muhim joylar:
needs: buildβ deploy faqat build muvaffaqiyatli tugagach ishlaydi. Image yo'q bo'lsa, deploy qilishdan ma'no yo'q.appleboy/ssh-action@v1.2.5β versiyani aniq qotirdik (tasdiqlangan: bu actionning joriy barqaror relizi).@v1kabi "harakatlanuvchi" teg ham bor, lekin qotirilgan versiya β takrorlanadigan (reproducible) deploy.set -e(script birinchi qatori) βscriptichidagi biror buyruq xato qaytarsa, qolganlari bajarilmaydi va job qulaydi. Buni albatta qo'ying, aks holdapullmuvaffaqiyatsiz bo'lsa hamupishlab, yarim-buzuq deploy chiqadi. (Eslatma:appleboy/ssh-actionning eskiscript_stopinputi v1.2.5 da olib tashlangan β uning o'rniga skript boshigaset -eqo'yiladi.)docker login ... --password-stdinβ image private bo'lsa kerak.GITHUB_TOKENfaqat shu workflow ishlayotgan paytda amal qiladi (vaqtinchalik), shuning uchun serverda doimiy parol qoldirmaydi.
π‘
--password-stdinparolni argument sifatida bermaydi (process ro'yxatida ko'rinmaydi),stdinorqali uzatadi. Parolnidocker login -p PAROLbilan to'g'ridan-to'g'ri yozish β yomon odat.
Variant B: sof ssh + known_hosts¶
Tashqi action'ga bog'lanmaslik istasangiz (yoki uning ichida nima ketayotganini to'liq nazorat qilmoqchi bo'lsangiz), sof ssh bilan ham bo'ladi. Bu yerda muhim narsa β known_hosts: server kalitini oldindan ishonchli ro'yxatga qo'shmasak, ssh interaktiv "yes/no" so'raydi va job qotib qoladi.
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- name: SSH kalit va known_hosts ni tayyorlash
run: |
mkdir -p ~/.ssh
echo "${{ secrets.DEPLOY_SSH_KEY }}" > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
ssh-keyscan -H "${{ secrets.DEPLOY_HOST }}" >> ~/.ssh/known_hosts
- name: Serverga deploy
run: |
ssh -i ~/.ssh/id_ed25519 \
"${{ secrets.DEPLOY_USER }}@${{ secrets.DEPLOY_HOST }}" \
'cd /srv/vazifalar-api && docker compose pull && docker compose up -d --remove-orphans && docker image prune -f'
β οΈ
ssh-keyscanserverning kalitini avtomatik oladi β bu qulay, lekin "ishonish-birinchi-ulanishda" (TOFU) prinsipiga tayanadi: agar deploy paytida o'rtada hujum (MITM) bo'lsa, soxta kalit yozilishi mumkin. Yuqori xavfsizlik kerak bo'lsa, server kalitini bir marta o'zingiz olib,secrets.DEPLOY_KNOWN_HOSTS'ga qo'ying vassh-keyscano'rniga uni yozing.
Ikkala variant bir xil natija beradi. Boshlash uchun Variant A soddaroq; Variant B esa nima sodir bo'layotganini ochiq ko'rsatadi va keraksiz bog'liqlikni yo'qotadi.
Environments: staging va production, qo'lda tasdiq bilan¶
To'g'ridan-to'g'ri production'ga deploy qilish β qo'rqinchli. Agar yangi versiya buzuq bo'lsa-chi? Shuning uchun jiddiy loyihalar ikki muhit ishlatadi:
- staging β production'ning nusxasi; bu yerga avtomatik deploy bo'ladi, sinab ko'rasiz.
- production β haqiqiy foydalanuvchilar; bu yerga deploy qo'lda tasdiq (approval) ortida.
GitHub'da buni Environments mexanizmi bilan qilamiz. Har bir environment'ning o'z secrets'i (har muhit o'z serveri), o'z protection rules'i (kim/qachon deploy qila oladi) bo'ladi.
Avval GitHub'da environment yaratasiz: repo Settings -> Environments -> New environment. production uchun Required reviewers yoqib, o'zingizni (yoki jamoa a'zosini) qo'shasiz β endi shu environment'ga tegadigan job tasdiqsiz ishlamaydi.
Workflow'da environment: kalitini job'ga qo'shamiz:
name: Deploy
on:
push:
branches: [main]
release:
types: [published]
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v6
- uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v7
with:
context: .
push: true
tags: ghcr.io/${{ github.repository }}:sha-${{ github.sha }}
deploy-staging:
needs: build
if: github.event_name == 'push'
runs-on: ubuntu-latest
environment:
name: staging
url: https://staging.vazifalar.uz
steps:
- uses: appleboy/ssh-action@v1.2.5
with:
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_SSH_KEY }}
envs: IMAGE_TAG
script: |
set -e
cd /srv/vazifalar-api
export IMAGE_TAG=sha-${{ github.sha }}
docker compose pull
docker compose up -d --remove-orphans
deploy-production:
needs: build
if: github.event_name == 'release'
runs-on: ubuntu-latest
environment:
name: production
url: https://vazifalar.uz
steps:
- uses: appleboy/ssh-action@v1.2.5
with:
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_SSH_KEY }}
script: |
set -e
cd /srv/vazifalar-api
docker compose pull
docker compose up -d --remove-orphans
Diqqat qiling:
- Triggerlar uchta:
push: main(staging avto),release: published(production),workflow_dispatch(qo'lda "Run workflow" tugmasi β favqulodda holatda). deploy-stagingfaqatpush'da (if: github.event_name == 'push'),deploy-productionfaqatrelease'da ishlaydi.environment: name: productionjob'ga protection rules'ni bog'laydi. GitHub'daproductionuchun required reviewer qo'yilgani uchun, bu job "Waiting for approval" holatida kutib turadi β kimdir tasdiqlamaguncha SSH ham qilmaydi.url:esa Actions UI'da "View deployment" havolasini ko'rsatadi.- Secrets
${{ secrets.DEPLOY_HOST }}β agarproductionvastagingenvironment'larida bir xil nomli environment secret belgilangan bo'lsa, har job o'z muhitining qiymatini oladi (har muhit β boshqa server). Bu environment secrets'ning asosiy foydasi.
π
environmentdarvozasi β CD'dagi eng muhim xavfsizlik chizig'i. U "bitta noto'g'ri push butun production'ni yiqitishi"ni to'xtatadi: production'ga har deploy ongli, qo'lda tasdiqlangan harakat bo'ladi.π‘
releasetrigger semantik versiyalash bilan tabiiy yuradi: GitHub'dav1.4.0teg bilan release chiqarasiz -> production deploy ishga tushadi -> reviewer tasdiqlaydi -> server o'sha versiyaga o'tadi. Tag β deployning "manzili".
Zero-downtime: foydalanuvchi uzilishni sezmaydi¶
docker compose up -d aytilganda Docker o'zgargan servis uchun yangi konteyner yaratadi, u tayyor bo'lgach eskisini to'xtatadi. Ya'ni qisqa vaqt ichida ikkala konteyner ham yashashi mumkin β bu zero-downtime deployning poydevori. Lekin sodda holatda baribir kichik uzilish bo'ladi: eski konteyner o'lib, yangisi hali so'rovga tayyor bo'lmagan oniy.
Bu yerda healthcheck asqotadi. Agar compose.yaml'da healthcheck bo'lsa, Docker yangi konteyner sog'lom (healthy) bo'lgunicha kutadi. Oldida Nginx/reverse-proxy turgan to'liq production'da (20-bobda chuqur ko'ramiz) bu β foydalanuvchi hech narsani sezmaydigan, silliq almashinuvga aylanadi: proxy faqat sog'lom konteynerga trafik yuboradi.
Hozircha shuni bilish kifoya: healthcheck'siz "deploy bo'ldi" yolg'on bo'lishi mumkin β konteyner ko'tarilgan, lekin ilova ichida xato bilan qulagan. Healthcheck bilan Docker "haqiqatan tayyor"ligini biladi. To'liq zero-downtime strategiyasi (blue-green, rolling) β 20 va 22-boblarda.
π Deploy job "yashil" bo'lishi β ilova ishlayapti degani EMAS. Har deploydan keyin healthcheck yoki kichik
curl"smoke test" bilan haqiqatan javob berayotganini tasdiqlang. Aks holda buzuq versiya jimgina production'da turadi.
Rollback: oldingi versiyaga qaytish¶
Deploy qildingiz β va sayt qulab tushdi. Birinchi qoida: panika qilma, orqaga qayt. Buni "fixni topib, yangi deploy qilaman" emas, balki avval rollback (oldingi ishlaydigan versiyaga qaytish) qilib, keyin sokin holatda fixni o'ylash kerak.
Rollback shuning uchun ham oson bo'ladiki, biz immutable (o'zgarmas) teglardan foydalanamiz. sha-abc1234 yoki v1.4.0 kabi teg har doim aynan bitta image'ni bildiradi va u hech qachon o'zgarmaydi. Demak "oldingi versiya"ga qaytish β shunchaki oldingi tegni qayta ishga tushirish:
# Serverda: hozir qaysi image ishlayotganini ko'rish
docker compose ps
# compose.yaml'da image tegini oldingi sog'lom versiyaga o'zgartirish
# image: ghcr.io/foydalanuvchi/vazifalar-api:sha-abc1234 (eski, ishlaydigan)
# yoki teg'ni muhit o'zgaruvchisi bilan boshqarsangiz:
IMAGE_TAG=sha-abc1234 docker compose up -d
β οΈ Nega
:latestrollback uchun yomon. Agar serverda har doim:latestishlatilsa, "oldingi versiya" degan tushuncha yo'qoladi βlatestdoim eng yangini bildiradi.docker compose pullbaribir buzuq versiyani tortadi. Shuning uchun production'da immutable teg (sha yoki semver) ishlating,latest'ni faqat qulaylik uchun qo'shimcha teg sifatida qoldiring.
Eng toza yo'l β compose.yaml'da image tegini muhit o'zgaruvchisidan olish:
Endi deploy IMAGE_TAG=sha-<yangi> docker compose up -d, rollback esa IMAGE_TAG=sha-<eski> docker compose up -d β bitta o'zgaruvchi. Hatto rollbackni ham workflow_dispatch input'i bilan tugma orqali qilish mumkin (mashqlar bo'limida).
π‘ Rollback strategiyasi β image-versiyalash strategiyangizning bevosita natijasi (9-bob, teglash). Immutable teglar -> bir soniyalik rollback.
latest-only -> rollback uchun qayta build kutish. Shuning uchun "har deploygashategi" β bekorga emas.
Pull-based alternativa: Watchtower va GitOps (qisqacha)¶
Biz ko'rgan usul β push-based: CI server tomon "itaradi". Muqobil falsafa β pull-based: server (yoki klaster) o'zi registry/Git'ni kuzatib turadi va o'zgarishni o'zi tortib oladi. Ikki keng tarqalgan yo'l:
- Watchtower β serverda ishlaydigan kichik konteyner; registry'dagi image yangilanganini sezsa, sizning konteyneringizni avtomatik yangilaydi. Kichik loyihalar uchun juda qulay: CI faqat push qiladi, qolganini Watchtower hal qiladi. Kamchiligi β yangilanish ustidan aniq nazorat va approval kamayadi.
- GitOps (Argo CD / Flux) β "haqiqat manbai" β Git repozitoriy. Siz Git'da kerakli holatni (qaysi versiya ishlashi kerakligini) yozasiz, klasterdagi agent doimo Git'ni real holat bilan solishtirib, farqni o'zi to'g'rilaydi. Bu β Kubernetes dunyosining standart deploy yondashuvi.
βΉοΈ GitOps'ni Kubernetes kontekstida 24-bobda batafsil ko'ramiz. Hozir shuni bilish kifoya: push-based β boshlash uchun eng sodda va ko'rinarli; ko'lam o'sgani sayin pull-based/GitOps ishonchliroq va auditga qulayroq bo'ladi.
Xavfsizlik: deploy kalitini ehtiyot qiling¶
Avtomatik deploy serverga doimiy kalit beradi β bu qulaylik, lekin xavf ham. Bir nechta qat'iy qoida:
- Alohida, cheklangan deploy user. Serverda faqat deploy uchun maxsus user (masalan
deploy) yarating; ungarootbermang. U faqat loyiha papkasiga vadockerbuyrug'iga ega bo'lsin. Eng yaxshisi β bu user faqat keraklidocker composebuyruqlarini bajara olsin. - Alohida SSH kalit juftligi. Deploy uchun shaxsiy kalitingizni emas, faqat shu maqsadda yaratilgan kalitni ishlating:
# Lokal mashinada deploy uchun kalit juftligi yaratish
ssh-keygen -t ed25519 -C "deploy-vazifalar-api" -f ./deploy_key
# Ochiq kalitni (public) serverdagi deploy user authorized_keys ga qo'shing:
# cat deploy_key.pub >> /home/deploy/.ssh/authorized_keys
# Maxfiy kalitni (private) deploy_key faylidan oling va GitHub secret DEPLOY_SSH_KEY ga joylang.
- Secrets β faqat secrets'da. Host, user, kalit β hech qachon workflow YAML'iga, kodga yoki commit'ga yozilmaydi. GitHub
secretsqiymatlarni loglarda avtomatik maskalaydi (***bilan yashiradi), lekin siz ham ularniechoqilmang. - Kalit chiqib ketsa β darhol bekor qiling. Serverdagi
authorized_keys'dan o'sha ochiq kalitni o'chiring va GitHub secret'ni yangilang. Immutable, alohida kalit shuning uchun ham yaxshi: bittasini bekor qilish boshqalariga ta'sir qilmaydi.
β οΈ Deploy job loglarini commit/PR ochiq bo'lsa hamma ko'radi.
set -x(bash debug) yoqib, kalit yoki tokenni echo qilib qo'ymang β bir marta loglarga tushgan maxfiy ma'lumot "chiqib ketgan" hisoblanadi. Shubha bo'lsa β kalitni almashtiring.π Production'ga deploy uchun ideal: alohida
deployuser + alohida SSH kalit +environment: productionapproval darvozasi + immutable teg. Bu to'rt qatlam birgalikda "tasodifan yoki yomon niyatda production'ni buzish"ni juda qiyinlashtiradi.
Yakun: zanjir yopildi¶
Endi to'liq CI/CD zanjiri ishlaydi: kod yozasiz -> git push -> test (13-bob) -> image build + GHCR push (14-bob) -> staging'ga avto-deploy -> tag/release bilan production'ga tasdiqli deploy (shu bob). 5-bobdagi 5-og'riq β "har yangilash qo'lda + downtime" β nihoyat yo'qoldi.
Hali serverda ilova :3000 portda, oldida hech nima yo'q β foydalanuvchiga http://203.0.113.10:3000 deb aytib bo'lmaydi. Keyingi bo'lim (16-18-boblar) shuni hal qiladi: Nginx reverse proxy, domen va HTTPS. 20-bob esa hamma narsani β Docker, CI/CD, Nginx, HTTPS, zero-downtime β bitta to'liq production deploy'ga birlashtiradi.
15-bob mashqlari¶
Oson¶
- Avtomatik deployda build va deploy j'oblari nega alohida bo'lib, deploy
needs: buildbilan bog'lanadi? Agarneeds'ni olib tashlasangiz qanday muammo bo'lishi mumkin? - Quyidagi to'rt secret'ning har biri nima uchun kerak:
DEPLOY_HOST,DEPLOY_USER,DEPLOY_SSH_KEY,DEPLOY_PORT. Qaysi biri eng maxfiy va nega? - Deploy triggeri sifatida
push: main,release: published,workflow_dispatchβ har birining vazifasini bir jumlada ayting. docker compose up -d --remove-orphansbuyrug'idagi-dva--remove-orphansnima qiladi?-dsiz deploy job'da nima bo'lardi?- Nega production deploy uchun
:latestemas,:sha-...yoki:v1.4.0kabi immutable teg afzal? Bitta jumlada javob bering.
O'rta¶
appleboy/ssh-action(Variant A) va sofssh+known_hosts(Variant B) ni solishtiring: har birining bittadan afzalligi va bittadan kamchiligini ayting. Variant B'daknown_hostsnega kerak?- GitHub Environments'da
productionuchun Required reviewers qo'yilgan. Reviewer tasdiqlamagunchaenvironment: productionbo'lgan job qaysi holatda turadi va SSH qiladi-mi? Tushuntiring. - Deploy job "yashil" (muvaffaqiyatli) bo'lsa-yu, ilova ichida xato bilan qulagan bo'lsa β buni qanday aniqlaysiz?
healthcheckva "smoke test" rollarini ayting. set -e(script boshida) nima uchun deploy skriptida muhim?docker compose pullxato bersa, usiz nima sodir bo'lishini izohlang.- Pull-based deploy (Watchtower/GitOps) push-based'dan nimasi bilan farq qiladi? Har biri qaysi holatda afzalroq?
Qiyin¶
- To'liq
Deployworkflow yozing:buildjob image'nighcr.io/.../vazifalar-api:sha-<sha>tegi bilan push qilsin;deploy-stagingfaqatpush: main'da,deploy-productionfaqatrelease'da ishlasin; productionenvironment: productionortida bo'lsin. SSH uchunappleboy/ssh-action@v1.2.5ishlating. - Serverda bajariladigan
deploy.shskript yozing: loyiha papkasiga o'tsin,docker compose pull,docker compose up -d --remove-orphans, so'ngdocker image prune -fqilsin; xato bo'lsa darhol to'xtasin.bash -nbilan sintaksisini tekshiring. compose.yaml'da image tegini muhit o'zgaruvchisidan oladigan qilib yozing (${IMAGE_TAG:-latest}) va shu asosda rollback ssenariysini tasvirlang: v2 qulasa, v1'ga qanday qaytasiz (aniq buyruqlar bilan)?workflow_dispatchinput bilan qo'lda rollback workflow'i loyihalashtiring: foydalanuvchi qaytmoqchi bo'lgan teg (image_tag) ni kiritsin, job serverga SSH qilib o'sha teg bilanup -dqilsin. Bu nega "ehtiyot tugmasi" sifatida foydali?- Deploy xavfsizligi bo'yicha alohida
deployuser va alohida SSH kalit yaratish qadamlarini yozing (ssh-keygen,authorized_keys, GitHub secret). Nega shaxsiy kalitingizni emas, alohida kalit ishlatish kerak?
Yechim β 11
name: Deploy
on:
push:
branches: [main]
release:
types: [published]
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v6
- uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v7
with:
context: .
push: true
tags: ghcr.io/${{ github.repository }}:sha-${{ github.sha }}
deploy-staging:
needs: build
if: github.event_name == 'push'
runs-on: ubuntu-latest
environment:
name: staging
url: https://staging.vazifalar.uz
steps:
- uses: appleboy/ssh-action@v1.2.5
with:
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_SSH_KEY }}
script: |
set -e
cd /srv/vazifalar-api
docker compose pull
docker compose up -d --remove-orphans
deploy-production:
needs: build
if: github.event_name == 'release'
runs-on: ubuntu-latest
environment:
name: production
url: https://vazifalar.uz
steps:
- uses: appleboy/ssh-action@v1.2.5
with:
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_SSH_KEY }}
script: |
set -e
cd /srv/vazifalar-api
docker compose pull
docker compose up -d --remove-orphans
production uchun GitHub'da (Settings -> Environments -> production) Required reviewers yoqilgan bo'lishi shart β shunda deploy-production job tasdiq kutib turadi. Build bir marta ishlaydi, ikkala deploy ham o'sha sha-<sha> tegidan foydalanadi (immutable, takrorlanadigan).
Yechim β 12
#!/usr/bin/env bash
set -euo pipefail
cd /srv/vazifalar-api
echo "1/3 Yangi image'ni tortish..."
docker compose pull
echo "2/3 Konteynerni qayta ko'tarish..."
docker compose up -d --remove-orphans
echo "3/3 Eski image'larni tozalash..."
docker image prune -f
echo "Deploy tugadi."
set -euo pipefail β xato (-e), e'lon qilinmagan o'zgaruvchi (-u) yoki pipe ichidagi xato (pipefail) bo'lsa skript darhol to'xtaydi; demak pull muvaffaqiyatsiz bo'lsa up umuman ishlamaydi. Sintaksis tekshiruvi: bash -n deploy.sh β xato bo'lmasa hech narsa chiqmaydi (toza chiqish = to'g'ri sintaksis).
Yechim β 13
compose.yaml:
services:
api:
image: ghcr.io/foydalanuvchi/vazifalar-api:${IMAGE_TAG:-latest}
restart: unless-stopped
ports:
- "127.0.0.1:3000:3000"
${IMAGE_TAG:-latest} β IMAGE_TAG muhit o'zgaruvchisi berilsa o'sha, aks holda latest.
Rollback ssenariysi: v2 (sha-bbb2222) deploy qildingiz, sayt qulaydi. Oldingi sog'lom versiya β v1 (sha-aaa1111). Serverda:
cd /srv/vazifalar-api
IMAGE_TAG=sha-aaa1111 docker compose pull
IMAGE_TAG=sha-aaa1111 docker compose up -d
Konteyner v1 image bilan qayta ko'tariladi, ilova tiklanadi. Bu bir necha soniyada bo'ladi, chunki sha-aaa1111 image hali serverning lokal keshida (yoki registry'da o'zgarmasdan) turibdi β qayta build kutilmaydi. Keyin sokin holatda v2'dagi xatoni topib tuzatasiz.
Yechim β 14
name: Rollback
on:
workflow_dispatch:
inputs:
image_tag:
description: "Qaytariladigan image teg (masalan sha-aaa1111 yoki v1.3.0)"
required: true
jobs:
rollback:
runs-on: ubuntu-latest
environment:
name: production
steps:
- uses: appleboy/ssh-action@v1.2.5
with:
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_SSH_KEY }}
envs: TAG
script: |
set -e
cd /srv/vazifalar-api
export TAG="${{ github.event.inputs.image_tag }}"
IMAGE_TAG="$TAG" docker compose pull
IMAGE_TAG="$TAG" docker compose up -d --remove-orphans
Foydalanuvchi Actions UI'da "Run workflow" bosib, qaytmoqchi bo'lgan tegni kiritadi. environment: production tufayli bu ham approval ortida bo'lishi mumkin. Bu β "ehtyot tugmasi": yangi build yoki kod o'zgartirmasdan, ma'lum, ishlaydigan versiyaga bir necha bosishda qaytaradi. Immutable teglar tufayli har bir eski versiya hali ham aniq, o'zgarmas image bo'lib registry'da turadi.
Yechim β 15
1. Serverda alohida deploy user yaratish (root sifatida, bir marta):
sudo adduser --disabled-password --gecos "" deploy
sudo usermod -aG docker deploy # docker buyrug'iga ruxsat
sudo mkdir -p /home/deploy/.ssh
sudo chmod 700 /home/deploy/.ssh
2. Lokal mashinada alohida kalit juftligi:
ssh-keygen -t ed25519 -C "deploy-vazifalar-api" -f ./deploy_key
# Ikki fayl: deploy_key (maxfiy) va deploy_key.pub (ochiq)
3. Ochiq kalitni serverga qo'shish:
# deploy_key.pub matnini serverdagi /home/deploy/.ssh/authorized_keys ga qo'shing
sudo tee -a /home/deploy/.ssh/authorized_keys < deploy_key.pub
sudo chown -R deploy:deploy /home/deploy/.ssh
sudo chmod 600 /home/deploy/.ssh/authorized_keys
4. Maxfiy kalitni GitHub secret'ga: deploy_key faylining to'liq matnini DEPLOY_SSH_KEY secret'iga joylang, deploy_key faylini lokaldan xavfsiz o'chiring.
Nega shaxsiy kalit emas: shaxsiy kalitingiz barcha serverlaringizga, GitHub'ga, boshqa joylarga kirish beradi β uni GitHub secret'iga qo'yish "hamma tuxumni bitta savatga" solishdir. Agar secret chiqib ketsa yoki workflow buzilsa, butun hayotingiz xavf ostida. Alohida deploy kalit esa faqat bitta serverdagi cheklangan userga kirish beradi; chiqib ketsa, faqat o'shani bekor qilasiz, boshqa hech narsaga ta'sir qilmaydi (zarar chegaralanadi).
β¬ οΈ Oldingi: 14 β Docker image CI va GHCR Β· π README Β· Keyingi: 16 β Nginx asoslari β‘οΈ