Architektury nasazení a životní cyklus aplikace Node.js
Nasazení aplikací Node.js na server zahrnuje volbu architektury (single host, kontejnery, orchestrátor), způsobu běhu procesu, reverzní proxy, škálování, observability a automatizace. Typický životní cyklus zahrnuje build (transpilaci/kompilaci TypeScriptu), přípravu prostředí (proměnné, tajemství), rollout (bez výpadku), monitoring a rollback. Správná volba cíle (VPS, bare metal, PaaS, Kubernetes) se řídí požadavky na SLA, propustnost, rozpočet a dovednosti týmu.
Volba runtime a správa verzí Node.js
- LTS vs. Current – v produkci upřednostňujte LTS kvůli stabilitě knihoven a bezpečnostním aktualizacím.
- Správa verzí – pro vývoj používejte nástroje nvm, fnm nebo asdf; v produkci verzi fixujte pomocí systémových balíčků, základního obrazu v
Dockerfilenebo binární distribuce (např.node:20-alpine). - ESM vs. CommonJS – sjednoťte modulový systém; pro ESM nastavte
"type": "module"a používejte kompatibilní bundlery.
Příprava aplikace: build, bundling a artefakty
- TypeScript – transpilujte do
dist/a nasazujte pouze artefakty (nikolinode_modulesz vývojového prostředí). Zvažte tsup/esbuild pro rychlý bundling. - Ořezání závislostí – v CI používejte
npm ci --omit=devnebopnpm install --prod, abyste minimalizovali velikost obrazu či balíčku. - Determinismus – verzujte soubory
package-lock.json/pnpm-lock.yamla podle potřeby používejteNODE_OPTIONS=--conditions=production.
Procesní model: systemd, PM2 a cluster
Node.js běží jako jednovláknová smyčka událostí. Pro využití více jader použijte procesní model (více instancí) nebo cluster v kombinaci se správcem procesů.
- systemd – standardní správce služeb v Linuxu; nabízí restartování, protokolování (journald), watchdog a izolaci.
- PM2 – pohodlný správce procesů s režimem cluster mode, rotací protokolů a jednoduchým opětovným načtením (reload) bez výpadku.
- Node cluster – vytváří pracovní procesy sdílející port; přednostně jej používejte prostřednictvím nástroje (PM2), který zajišťuje správu životního cyklu.
Ukázka jednotky systemd:
[Unit] Description=My Node.js API After=network.target [Service] Environment=NODE_ENV=production EnvironmentFile=/etc/myapi.env WorkingDirectory=/srv/myapi ExecStart=/usr/bin/node dist/server.js Restart=always RestartSec=3 User=node Group=node # Bezpečnostní omezení NoNewPrivileges=true ProtectSystem=full ProtectHome=true PrivateTmp=true AmbientCapabilities= [Install] WantedBy=multi-user.target
Reverzní proxy: Nginx / Caddy jako terminátor TLS a nástroj pro vyvažování zátěže
Server Node.js (např. Fastify/Express) obvykle běží na interním portu (např. 3000). Reverzní proxy:
- ukončuje TLS (Let’s Encrypt),
- zajišťuje bezpečnost hlaviček (HSTS, CSP, CORS),
- provádí omezení rychlosti požadavků a kompresi,
- rozděluje zátěž mezi více instancí (fond upstream serverů).
Ukázka konfigurace Nginx:
upstream myapi { server 127.0.0.1:3001; server 127.0.0.1:3002; keepalive 64; } server { listen 80; server_name api.example.com; return 301 https://$host$request_uri; } server { listen 443 ssl http2; server_name api.example.com; ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem; add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always; add_header X-Content-Type-Options nosniff; add_header X-Frame-Options DENY; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Host $host; location / { proxy_pass http://myapi; proxy_http_version 1.1; proxy_set_header Connection ""; proxy_read_timeout 60s; } }
Dockerizace a neměnné nasazení
Kontejnerové nasazení zjednodušuje správu závislostí a zajišťuje reprodukovatelnost. Doporučení:
- Vícefázový build – oddělte obraz pro sestavení od obrazu pro běh; pro malé obrazy používejte Alpine/Distroless.
- Neprivilegovaný uživatel – nastavte
USER nodea používejte port >1024 (např. 3000). - Kontrola stavu – definujte HTTP endpoint pro liveness/readiness.
Příklad Dockerfile:
# Build stage FROM node:20-alpine AS build WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build && npm prune --omit=dev # Runtime stage FROM node:20-alpine ENV NODE_ENV=production WORKDIR /app COPY --from=build /app/package*.json ./ COPY --from=build /app/node_modules ./node_modules COPY --from=build /app/dist ./dist USER node EXPOSE 3000 HEALTHCHECK --interval=30s --timeout=3s CMD wget -qO- http://127.0.0.1:3000/health || exit 1 CMD ["node", "dist/server.js"]
CI/CD: build, testování, audit a rollout
Pipeline by měla obsahovat:
- Lint/testy (unit, e2e), SCA (
npm audit,osv), SAST. - Sestavení artefaktu (tarball/obraz Dockeru) a jeho podepsání (Sigstore/cosign).
- Nasazení na staging, smoke testy a následně nasazení do produkce (blue-green/canary).
Ukázka GitHub Actions (zkráceně):
name: ci on: [push] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: { node-version: 20, cache: 'npm' } - run: npm ci - run: npm run lint && npm test - run: npm run build - run: npm prune --omit=dev - name: Build image run: docker build -t ghcr.io/org/myapi:${{ github.sha }} .
Vydání bez výpadku: blue-green a canary
- Blue-green – provozují se dvě identické verze (blue a green). Po ověření přesměrujte provoz (Nginx upstream, load balancer) a starou verzi ukončete.
- Canary – nasadíte novou verzi malému procentu uživatelů, sledujete metriky a postupně zvyšujete podíl.
- PM2 reload – umožňuje plynulé přepnutí pracovních procesů bez výpadku (graceful).
Řízené ukončení aplikace a zpracování signálů
Správné zpracování signálu SIGTERM zabrání přerušení rozpracovaných požadavků a poškození transakcí.
import http from 'node:http'; import { pool } from './db.js'; // příklad: pg/pool const server = http.createServer(app); const PORT = process.env.PORT ?? 3000; server.listen(PORT, () => console.log(`Listening on ${PORT}`)); let shuttingDown = false; process.on('SIGTERM', async () => { if (shuttingDown) return; shuttingDown = true; console.log('SIGTERM received. Starting graceful shutdown...'); server.close(async () => { try { await pool.end(); // uzavřít DB pool console.log('Shutdown complete.'); process.exit(0); } catch (e) { console.error('Error during shutdown', e); process.exit(1); } }); // volitelně: po X sekundách vynutit exit setTimeout(() => process.exit(1), 10000).unref(); });
Konfigurace, tajemství a prostředí
- 12-factor – konfiguraci uchovávejte v proměnných prostředí (
DATABASE_URL,REDIS_URL, …). Citlivá data nepřidávejte do repozitáře. - Správa tajemství – úložiště operačního systému (např.
systemdEnvironmentFile s nastavenými oprávněními), Vault, SOPS + KMS, Docker/K8s Secrets. - Ověření konfigurace – při spuštění ověřte konfiguraci podle schématu (Zod/TypeBox) a při chybě aplikaci ihned ukončete.
Databáze a migrace schématu
Nasazení do produkce vyžaduje bezpečný postup migrací:
- Bez výpadku – upravujte schéma kompatibilně (přidání sloupců s výchozí hodnotou, doplnění dat, následné přepnutí kódu).
- Nástroje – Prisma Migrate, Knex, TypeORM, Flyway. Zaznamenávejte verze migrací a zajistěte, aby byly idempotentní.
- Správa připojení v poolu – správně nastavte velikost poolu, timeouty a exponenciální prodlevy (např. pg, mysql2).
Mezipaměť, CDN a výkon
- HTTP cache – používejte
ETag,Cache-Control,Vary. Reverzní proxy může ukládat do mezipaměti idempotentní požadavky GET. - Aplikační mezipaměť – Redis/Memcached pro nákladné dotazy; při změně dat zajistěte invalidaci (události, TTL).
- Profilování –
clinic.js,0x,node --prof; sledujte GC, prodlevu smyčky událostí a alokace.
WebSockety, SSE a trvalé směrování
Pro aplikace v reálném čase je nutná správná konfigurace proxy a škálování:
- Hlavičky Upgrade – Nginx musí povolit
Connection: upgradeaUpgrade: websocket. - Trvalé směrování – u WebSocketů je často vyžadováno; jinak sdílejte stav prostřednictvím Redis (adaptér Socket.IO) nebo použijte pub/sub.
- SSE – jednodušší než WebSockety, ale dávejte pozor na limity souběžných spojení a timeouty.
Observability: logování, metriky a trasování
- Strukturované logy – JSON (pino/winston), jedinečné request-id, korelace prostřednictvím
X-Request-ID. - Metriky – endpoint Prometheus (latence p95, míra chybovosti, propustnost), sběr metrik a dashboardy (Grafana).
- Trasování – OpenTelemetry pro distribuované trasování; export do Jaeger/Tempo/OTLP.
- Upozorňování – SLO/SLI (např. dostupnost 99,9 %), upozornění na chybovost a vyčerpání zdrojů.
Zabezpečení produkčního prostředí
- Závislosti – pravidelně je aktualizujte a auditujte, blokujte známé CVE (npm
audit-level), používejte Dependabot. - HTTP hlavičky –
Helmet(CSP, HSTS, ochrana proti XSS, no-sniff), omezení metod a velikosti payloadů. - Omezení rychlosti požadavků – nastavte je v proxy i aplikaci; zajistěte ochranu proti útokům hrubou silou a DoS.
- Tajemství – nikdy je nezapisujte do protokolů; klíče pravidelně obměňujte a používejte krátkodobé tokeny (OIDC).
- Izolace – omezení pomocí
systemd, seccomp v Dockeru, souborový systém pouze pro čtení, odebrání oprávnění.
Škálování: vertikální, horizontální a Kubernetes
- Vertikální – navýšení výkonu CPU/RAM; rychlé, ale omezené.
- Horizontální – více instancí za nástrojem pro vyvažování zátěže; bezestavový návrh (relace do Redis/DB, soubory do objektového úložiště).
- Kubernetes – automatické zotavení, automatické škálování (HPA), průběžné aktualizace; vyžaduje vyšší provozní vyspělost.
Ekosystém PM2 a opětovné načtení bez výpadku
Příklad ecosystem.config.js:
module.exports = { apps: [{ name: "myapi", script: "dist/server.js", instances: "max", exec_mode: "cluster", env: { NODE_ENV: "production" }, watch: false, max_memory_restart: "512M" }] };
Nasazení: pm2 start ecosystem.config.js, rollout: pm2 reload myapi pro plynulé restartování pracovních procesů.
Migrace bez výpadku a správa verzí API
- Zpětná kompatibilita – nasazujte kód, který rozumí starým i novým polím. Teprve poté proveďte změny databáze, které nejsou zpětně kompatibilní.
- Verzování API –
/v1,/v2nebo pomocí vyjednávání obsahu; API dokumentujte prostřednictvím OpenAPI.
Zálohování, obnova a zotavení po havárii
- Provozní příručky – zdokumentovaný postup pro řešení incidentů, rollback a obnovu.
- Zálohy – pravidelné snapshoty databáze a objektového úložiště, testování obnovy (nácvik havarijní situace).
- Více regionů – u kritických služeb replikace dat a přesměrování provozu při výpadku.
Řízení nákladů a efektivita
- Profilování – odhalte úzká místa dříve, než navýšíte kapacitu clusteru.
- Automatické škálování a plánování – přizpůsobte kapacitu denním špičkám a mimo špičku vypínejte přebytečné instance.
- Efektivní logování – využívejte vzorkování a nastavte dobu uchovávání; velké objemy protokolů jsou nákladné.
Kontrolní seznam pro nasazení do produkce
- Artefakt buildu je reprodukovatelný a obsahuje pouze závislosti potřebné za běhu.
- Proces je spravován (systemd/PM2/K8s), má kontrolu stavu a podporuje řízené ukončení.
- Reverzní proxy ukončuje TLS, aplikuje bezpečnostní hlavičky a omezuje rychlost požadavků.
- Konfigurace se předává prostřednictvím proměnných prostředí, tajemství jsou mimo repozitář a konfigurace se ověřuje při spuštění.
- Migrace schématu jsou automatizované a kompatibilní, postup návratu k předchozí verzi je nacvičený.
- Monitoring zahrnuje logy, metriky a trasování; upozornění vycházejí z SLO.
- Strategie nasazení (blue-green/canary) a automatizovaný rollback.
- Zdokumentované provozní příručky a otestované zálohy.
Závěr
Robustní nasazení aplikací Node.js na server kombinuje opakovatelné buildy, bezpečný běh procesu, správnou síťovou vrstvu, automatizované postupy vydávání a bohatou observabilitu. Zavedením standardizované pipeline a ekosystému provozních pojistek dosáhnete předvídatelného výkonu, snížíte riziko incidentů a získáte možnost škálovat od jednoho serveru až po distribuovaný víceregionální cluster.
