Ręczne wdrażanie kodu to strata czasu i źródło błędów. CI/CD automatyzuje ten proces tak, że każda zmiana w repozytorium trafia na serwer sprawdzona, przetestowana i gotowa do działania.
Czym jest CI/CD i dlaczego warto to wdrożyć?
CI/CD to skrót od Continuous Integration i Continuous Delivery (lub Deployment) – czyli ciągłej integracji i ciągłego dostarczania. To praktyka, w której każda zmiana kodu automatycznie przechodzi przez zdefiniowany potok zadań: instalację zależności, uruchomienie testów, zbudowanie aplikacji i wdrożenie na serwer. Bez klikania, bez ręcznego SSH, bez „u mnie działa”.
W projektach Node.js CI/CD sprawdza się wyjątkowo dobrze – ekosystem npm, powszechność testów jednostkowych i integracyjnych oraz dojrzałość narzędzi takich jak GitHub Actions, GitLab CI czy CircleCI sprawiają, że postawienie pierwszego pipeline’u zajmuje dosłownie kilkadziesiąt minut. Efekt? Każdy push do repozytorium uruchamia automatyczną weryfikację kodu, a na główną gałąź trafia tylko to, co przeszło wszystkie sprawdzenia.
Kluczowe elementy pipeline’u dla Node.js
Zanim zaczniesz konfigurować konkretne narzędzie, warto zrozumieć z czego składa się typowy pipeline CI/CD w projekcie Node.js. Każdy etap ma swój cel i kolejność nie jest przypadkowa – im wcześniej wykryjesz błąd, tym taniej go naprawić.
| Etap | Co robi | Przykładowe komendy |
|---|---|---|
| Instalacja zależności | Pobiera paczki npm zgodnie z package-lock.json | npm ci |
| Linting | Sprawdza styl i jakość kodu | npm run lint |
| Testy jednostkowe | Uruchamia testy i sprawdza pokrycie kodu | npm test |
| Testy integracyjne | Sprawdza współdziałanie modułów i usług | npm run test:integration |
| Build | Kompiluje TypeScript, bundluje assets | npm run build |
| Skanowanie bezpieczeństwa | Wykrywa znane podatności w zależnościach | npm audit |
| Wdrożenie | Wysyła kod na serwer lub do kontenera | zależnie od platformy |
Ważna uwaga: zamiast npm install w pipeline zawsze używaj npm ci. Ta komenda instaluje zależności dokładnie zgodnie z package-lock.json, nie modyfikuje go i jest szybsza w środowisku CI. Eliminuje klasyczny problem „u mnie działa, bo mam inną wersję paczki”.
GitHub Actions – krok po kroku
GitHub Actions to dziś najpopularniejsze narzędzie CI/CD dla projektów hostowanych na GitHubie – i całkowicie bezpłatne dla repozytoriów publicznych oraz z hojnym limitem dla prywatnych. Konfiguracja odbywa się przez plik YAML umieszczony w katalogu .github/workflows/ w repozytorium.
Poniżej kompletny przykład pipeline’u dla aplikacji Node.js, który uruchamia się przy każdym pushu i pull requeście na gałąź main:
name: CI/CD Pipeline
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x, 20.x]
steps:
- name: Checkout kodu
uses: actions/checkout@v4
- name: Konfiguracja Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: Instalacja zależności
run: npm ci
- name: Linting
run: npm run lint
- name: Testy
run: npm test
- name: Build
run: npm run build
deploy:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- name: Wdrożenie na serwer
run: echo "Tu dodaj kroki wdrożenia"
Kilka rzeczy wartych uwagi w tej konfiguracji: sekcja matrix uruchamia testy równolegle na dwóch wersjach Node.js – dzięki temu masz pewność, że kod działa na obu. Parametr cache: 'npm' w kroku setup-node automatycznie cachuje katalog node_modules między uruchomieniami, co znacząco przyspiesza kolejne buildy. Job deploy uruchamia się tylko wtedy, gdy job test zakończył się sukcesem – dzięki dyrektywie needs: test.
Zmienne środowiskowe i sekrety – bezpieczeństwo przede wszystkim
Każda realna aplikacja Node.js korzysta ze zmiennych środowiskowych – kluczy API, danych dostępowych do bazy danych, tokenów. Nigdy nie umieszczaj ich bezpośrednio w plikach konfiguracyjnych pipeline’u. GitHub Actions, GitLab CI i wszystkie inne popularne narzędzia oferują mechanizm przechowywania sekretów – zaszyfrowanych wartości, które są wstrzykiwane do pipeline’u w czasie wykonania.
| Zmienna | Gdzie przechowywać | Jak używać w pipeline |
|---|---|---|
| Klucze API | GitHub Secrets | ${{ secrets.API_KEY }} |
| Dane bazy danych | GitHub Secrets | ${{ secrets.DB_PASSWORD }} |
| Token wdrożenia (SSH) | GitHub Secrets | ${{ secrets.DEPLOY_KEY }} |
| Środowisko (prod/staging) | GitHub Variables | ${{ vars.NODE_ENV }} |
Sekrety ustawiasz w ustawieniach repozytorium na GitHubie: Settings → Secrets and variables → Actions. Raz zapisane nigdy nie są wyświetlane w interfejsie – nawet administratorzy nie mogą ich odczytać, tylko nadpisać. W logach pipeline’u są automatycznie maskowane jako gwiazdki.
Strategie wdrożenia – od prostego do zaawansowanego
Sam pipeline testowy to dopiero połowa sukcesu. Równie ważna jest strategia wdrożenia – czyli to, jak zbudowana aplikacja trafia na serwer produkcyjny. W ekosystemie Node.js masz kilka popularnych podejść, każde z własnym zestawem zalet.
Najprostsze podejście to wdrożenie przez SSH bezpośrednio na serwer VPS. Pipeline łączy się z serwerem, pobiera najnowszy kod z repozytorium, instaluje zależności i restartuje proces przez PM2. Działa świetnie dla mniejszych projektów i jest najłatwiejsze do zrozumienia i debugowania.
Bardziej zaawansowane podejście to wdrożenie przez kontenery Docker. Pipeline buduje obraz Docker, publikuje go do rejestru (Docker Hub, GitHub Container Registry, AWS ECR), a serwer pobiera nowy obraz i uruchamia zaktualizowany kontener. To podejście zapewnia pełną powtarzalność środowiska – kontener na serwerze produkcyjnym jest identyczny z tym, który przeszedł testy.
Przy wdrożeniach na platformy chmurowe takie jak AWS, Google Cloud czy Heroku i Render, każda z nich oferuje własną integrację z popularnymi narzędziami CI/CD. Render na przykład potrafi automatycznie wykryć push na główną gałąź i wdrożyć aplikację bez żadnej dodatkowej konfiguracji pipeline’u.
| Strategia wdrożenia | Złożoność | Najlepiej dla |
|---|---|---|
| SSH + PM2 na VPS | Niska | Małe projekty, szybki start |
| Docker + rejestr obrazów | Średnia | Projekty wymagające powtarzalności środowiska |
| Kubernetes (k8s) | Wysoka | Duże systemy, skalowanie horyzontalne |
| Platformy PaaS (Render, Railway) | Bardzo niska | Szybkie prototypy, startupy |
| Serverless (AWS Lambda) | Średnia | Funkcje bezstanowe, zmienne obciążenie |
Niezależnie od wybranej strategii, warto zadbać o wdrożenia bez przestojów (zero-downtime deployments). W przypadku PM2 służy do tego komenda pm2 reload zamiast pm2 restart – ta pierwsza zastępuje procesy stopniowo, bez chwili niedostępności aplikacji. W środowiskach kontenerowych ten sam efekt daje rolling update w Docker Swarm lub Kubernetes.