name: CI/CD Pipeline
on:
push:
branches: [main]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Lint & Test
run: |
npm run lint
npm run test
- name: Build project
run: npm run build
env:
NEXT_PUBLIC_API_URL: ${{ secrets.API_URL }}
- name: Deploy to VPS via SSH
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
key: ${{ secrets.SSH_KEY }}
script: |
cd /var/www/my-app
git pull origin main
npm install --production
npm run build
pm2 restart my-next-appAm trecut prin faza aia în care dădeam ssh în server, un git pull obosit, și apoi mă rugam să nu crape npm run build pentru că RAM-ul era deja la limită. La un proiect recent, un mic SaaS cu vreo 1200 de useri activi, am decis că e momentul să nu mai pierd 10 minute la fiecare deploy și să risc downtime că am uitat să dau install la o dependență nouă.
Să fim realiști: Vercel e mișto până când vezi factura sau când ai nevoie de un VPS pentru că rulezi și alte servicii pe lângă. Dacă ești pe un VPS de 5-10 euro, GitHub Actions e salvarea ta, dar trebuie configurat cu cap ca să nu pierzi ore întregi debuguind YAML-uri.
De ce facem build-ul pe GitHub și nu pe server?
Am pățit-o pe un VPS cu 2GB RAM: când dădeam build la un proiect Next.js mai mărișor, procesul de Webpack/Turbo mânca tot RAM-ul și îmi omora baza de date. E groaznic. Strategia mea e simplă: fac tot ce e greu pe runner-ul de la GitHub (care e moca în limitele de 2000 min/lună) și pe server doar mut fișierele și dau un restart la proces.
În pipeline-ul ăsta am inclus trei etape mari: verificarea codului, build-ul propriu-zis și mutarea fișierelor prin SSH. Am reușit să scad timpul total de la 5 minute la sub 160 de secunde folosind caching-ul de la GitHub pentru node_modules și .next/cache.
Pipeline-ul care nu dă rateuri
Prima parte e plictisitoare dar obligatorie: lint și test. Dacă ai uitat un punct și virgulă sau ai stricat un test de unitate, pipeline-ul crapă imediat. Nu vrei să ajungă cod prost pe producție.
Trade-off-ul aici e timpul de execuție. Dacă ai sute de teste, poate vrei să le rulezi în paralel, dar pentru majoritatea proiectelor noastre, rularea secvențială e ok.
După ce trece testarea, fac build-ul. Aici e un mic truc: trebuie să te asiguri că variabilele de mediu (.env) sunt disponibile și în faza de build dacă ai chestii care se injectează la compile-time. Eu le țin în GitHub Secrets și le scriu într-un fișier .env temporar înainte de npm run build.
Deploy-ul prin SSH: Rsync e sfânt
Am încercat diverse acțiuni de SSH din marketplace, dar appleboy/ssh-action combinat cu rsync mi se pare cea mai stabilă variantă. Ideea e să trimiți doar diferențele, nu tot folderul node_modules de fiecare dată.
Totuși, mare atenție la folderele pe care le trimiți. Dacă trimiți tot folderul .next, asigură-te că serverul știe să facă swap-ul rapid. Eu folosesc PM2 pentru managementul procesului pe VPS. După ce fișierele sunt sus, execut o comandă simplă: pm2 restart app-name.
Un mare minus la abordarea asta? Dacă build-ul tău e uriaș (sute de MB), transferul prin SSH poate dura. La proiectul de care ziceam, artifact-ul de build are cam 45MB arhivat, deci zboară rapid pe o conexiune de 1Gbps.
Ce am învățat pe pielea mea
- Cache is king: Fără
actions/cache, instalezi dependențele de la zero la fiecare push. Am economisit cam 40% din build time doar cu asta. - Security: Nu folosi parola de root. Creează un user separat (ex:
deploy-user), dă-i acces doar în folderul proiectului și folosește o cheie SSH dedicată, fără passphrase, adăugată în GitHub Secrets. - Artifacts: Uneori e mai bine să uploadezi build-ul ca artifact în GitHub și să-l downloadezi pe server, dar pentru simplitate, rsync direct din runner e mult mai rapid de configurat.
La final, ai un flux în care dai git push origin main și în 3 minute site-ul e live, testat și curat. Voi cum faceți? Mergeți pe varianta Dockerized sau rămâneți la deploy-ul clasic pe „fier”?
Deploy-ul pe VPS rămâne varianta mea preferată pentru proiecte medii unde vrei control total fără costurile de „convenience tax” ale platformelor de tip PaaS.