Używamy cookies, żeby zwiększyć Twoje doświadczenia na stronie
CodeWorlds

Projekt główny - konteneryzacja i CI/CD Pipeline

Cały moduł składał się z osobnych narzędzi: obraz, Compose, pipeline, sekrety, metryki, tracing, plan infrastruktury. Teraz zbierzemy je w jedną konfigurację - i przy okazji przypomnimy sobie, dlaczego każda decyzja wygląda tak, a nie inaczej. Bo to właśnie te uzasadnienia odróżniają konfigurację skopiowaną od zrozumianej.

Obraz - dwa etapy

1FROM node:20-alpine AS builder
2WORKDIR /app
3COPY package.json yarn.lock ./
4RUN yarn install --frozen-lockfile
5COPY . .
6RUN yarn build
7
8FROM node:20-alpine AS production
9WORKDIR /app
10RUN addgroup -g 1001 -S nodejs && adduser -S nestjs -u 1001
11COPY --from=builder /app/dist ./dist
12COPY --from=builder /app/node_modules ./node_modules
13USER nestjs
14EXPOSE 4000
15HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
16  CMD curl -f http://localhost:4000/health || exit 1
17CMD ["node", "dist/main"]

Trzy decyzje w tym pliku warto umieć uzasadnić.

COPY --from=builder
przenosi wynik z pierwszego etapu do drugiego. Kolejność członów jest stała:
COPY
,
--from=builder
,
/app/dist
(skąd),
./dist
(dokąd). Dzięki temu w obrazie produkcyjnym nie ma kompilatora, źródeł ani zależności deweloperskich - zostaje sam wynik.

USER nestjs
- użytkownika bez uprawnień root tworzymy, aby ograniczyć potencjalne szkody w przypadku włamania. Nie po to, żeby kontener startował szybciej, żeby obraz był mniejszy ani żeby umożliwić wielowątkowość. Proces działający jako root wewnątrz kontenera, po wyrwaniu się z izolacji, jest rootem także na hoście.

HEALTHCHECK
mówi Dockerowi, jak sprawdzić, czy aplikacja żyje naprawdę, a nie tylko czy proces istnieje. Kolejność:
healthcheck:
,
test: curl -f http://localhost:4000/health
,
interval: 30s
,
retries: 3
.

Compose - trzy serwisy

W pliku Compose sprawdź dwie rzeczy, które najczęściej się myli.

Kontener

api
łączy się z bazą przez nazwę serwisu:
mongodb:27017
- nie przez adres IP kontenera, nie przez
localhost:27017
i nie przez zewnętrzny DNS.
localhost
wewnątrz kontenera to ten sam kontener, więc wskazywałby na API, nie na bazę.

Flaga

-v
w
docker compose down -v
usuwa wolumeny wraz z danymi.
Nie włącza trybu szczegółowych logów, nie waliduje pliku i nie wypisuje wersji. To polecenie kasuje bazę - używaj go świadomie.

Wdrożenie - kolejność

Pełna droga zmiany na produkcję ma cztery etapy:

  1. Push kodu do gałęzi main.
  2. CI: lint, test, build.
  3. Docker build & push image.
  4. Smoke tests i monitoring po wdrożeniu.

Czwarty etap bywa pomijany, a jest tym, który odróżnia „wdrożone" od „działa". Smoke tests to garść sprawdzeń najważniejszych ścieżek zaraz po wdrożeniu - czy strona się otwiera, czy logowanie przechodzi, czy zdrowie odpowiada. Pipeline mógł przejść na zielono, a aplikacja i tak nie wstać, bo zabrakło zmiennej środowiskowej, której na CI nikt nie potrzebował.

Kubernetes - dwa polecenia

Gdy obraz jest gotowy, klaster przyjmuje opis zasobów z pliku:

1kubectl apply -f deployment.yaml

Kolejność członów:

kubectl
,
apply
,
-f
,
deployment.yaml
. Flaga
-f
wskazuje plik z opisem;
apply
doprowadza klaster do stanu w nim zapisanego - tworzy, czego brakuje, i zmienia, co się różni.

Skalowanie to osobne polecenie:

1kubectl scale deployment roman-api --replicas=5

Tu kolejność brzmi:

kubectl scale
,
deployment roman-api
,
--replicas=5
. Pięć replik znaczy pięć równoległych kopii aplikacji, między które klaster rozdzieli ruch.

Terraform - moduły

Ostatnia rzecz z warstwy infrastruktury. Moduły w Terraform to reużywalne bloki infrastruktury, które można parametryzować - nie pluginy do komunikacji z chmurą (tym są providery), nie testy jednostkowe i nie pliki logów.

Sens jest ten sam co przy funkcji w kodzie: opisujesz raz „serwer aplikacyjny z bazą i siecią", a potem wywołujesz to trzy razy dla środowiska testowego, przedprodukcyjnego i produkcyjnego, zmieniając tylko parametry.

Checklista projektu

Zbierz komplet i sprawdź każdy punkt:

  • Docker - obraz wieloetapowy, użytkownik bez roota,
    HEALTHCHECK
    ,
  • Docker Compose - trzy serwisy, łączenie po nazwach, wolumen na dane bazy,
    depends_on
    z
    service_healthy
    ,
  • CI/CD - workflow na
    push
    i
    pull_request
    , joby w kolejności lint → build → test → docker, sekrety w ustawieniach repozytorium,
  • Sekrety - żadnego hasła w repozytorium;
    .env
    tylko lokalnie,
  • Observability - endpoint
    /metrics
    , metryki RED, tracing z
    span.end()
    w
    finally
    ,
  • Infrastructure as Code - plan w plikach
    .tf
    , stan w backendzie zdalnym, nie w Gicie.

Podsumowanie

Kampania gotowa do wymarszu:

  • COPY --from=builder
    przenosi wynik budowania:
    COPY
    ,
    --from=builder
    , źródło, cel,
  • użytkownika bez roota tworzymy, aby ograniczyć szkody przy włamaniu - nie dla szybkości ani rozmiaru obrazu,
  • HEALTHCHECK
    w kolejności:
    healthcheck:
    ,
    test:
    ,
    interval:
    ,
    retries:
    ,
  • kontenery łączą się przez nazwę serwisu (
    mongodb:27017
    ), nie przez IP ani
    localhost
    ,
  • docker compose down -v
    usuwa wolumeny wraz z danymi
    ,
  • kolejność wdrożenia: push → CI (lint, test, build) → docker build & push → smoke tests i monitoring,
  • kubectl
    apply
    -f
    deployment.yaml
    wprowadza opis do klastra,
  • kubectl scale
    deployment nazwa
    --replicas=5
    zmienia liczbę kopii,
  • moduły Terraform to reużywalne, parametryzowalne bloki infrastruktury - nie providery, nie testy, nie logi.

To ostatnia lekcja modułu. Umiesz teraz zbudować obraz, opisać środowisko, przepuścić zmianę przez pipeline, ukryć sekrety, zobaczyć, co dzieje się na produkcji, i odtworzyć całą infrastrukturę z pliku. A na razie zapamiętaj: każdy element tej konfiguracji ma uzasadnienie - i to jego znajomość, a nie sam plik, przenosi się na następny projekt.

Przejdź do CodeWorlds