premik.pl

Jak wdrożyć CI/CD w projektach Node.js

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ć.

EtapCo robiPrzykładowe komendy
Instalacja zależnościPobiera paczki npm zgodnie z package-lock.jsonnpm ci
LintingSprawdza styl i jakość kodunpm run lint
Testy jednostkoweUruchamia testy i sprawdza pokrycie kodunpm test
Testy integracyjneSprawdza współdziałanie modułów i usługnpm run test:integration
BuildKompiluje TypeScript, bundluje assetsnpm run build
Skanowanie bezpieczeństwaWykrywa znane podatności w zależnościachnpm audit
WdrożenieWysyła kod na serwer lub do kontenerazależ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.

ZmiennaGdzie przechowywaćJak używać w pipeline
Klucze APIGitHub Secrets${{ secrets.API_KEY }}
Dane bazy danychGitHub 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żeniaZłożonośćNajlepiej dla
SSH + PM2 na VPSNiskaMałe projekty, szybki start
Docker + rejestr obrazówŚredniaProjekty wymagające powtarzalności środowiska
Kubernetes (k8s)WysokaDuże systemy, skalowanie horyzontalne
Platformy PaaS (Render, Railway)Bardzo niskaSzybkie prototypy, startupy
Serverless (AWS Lambda)ŚredniaFunkcje 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.

Zobacz powiązane wpisy