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

Projekt Główny — Kompletna Konfiguracja Deployment

Legioniście, nadszedł czas na wielką kampanię — stworzenie kompletnej konfiguracji deployment dla naszej aplikacji NestJS! W tym projekcie połączysz całą wiedzę z tego modułu: Docker, Docker Compose, CI/CD, health checks, logging i bezpieczeństwo.

Cel projektu

Stworzymy pełny pipeline wdrożeniowy składający się z:

  1. Dockerfile z multi-stage build
  2. docker-compose.yml z API + MongoDB + Redis
  3. GitHub Actions workflow z CI/CD
  4. Health check endpoint
  5. Konfiguracja loggera
  6. Zabezpieczenia produkcyjne

1. Dockerfile produkcyjny

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

2. Docker Compose

1version: '3.8'
2services:
3  api:
4    build:
5      context: .
6      target: production
7    ports:
8      - '4000:4000'
9    environment:
10      - NODE_ENV=production
11      - DATABASE=mongodb://imperator:roma2024@mongodb:27017/roman-imperium?authSource=admin
12      - REDIS_HOST=redis
13      - PORT=4000
14    depends_on:
15      mongodb:
16        condition: service_healthy
17      redis:
18        condition: service_started
19    networks:
20      - imperium-net
21    restart: unless-stopped
22
23  mongodb:
24    image: mongo:7.0
25    environment:
26      - MONGO_INITDB_ROOT_USERNAME=imperator
27      - MONGO_INITDB_ROOT_PASSWORD=roma2024
28    volumes:
29      - mongo-data:/data/db
30    networks:
31      - imperium-net
32    healthcheck:
33      test: echo 'db.runCommand("ping").ok' | mongosh --quiet
34      interval: 10s
35      timeout: 5s
36      retries: 5
37
38  redis:
39    image: redis:7-alpine
40    command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru
41    volumes:
42      - redis-data:/data
43    networks:
44      - imperium-net
45
46volumes:
47  mongo-data:
48  redis-data:
49
50networks:
51  imperium-net:
52    driver: bridge

3. GitHub Actions CI/CD

1name: Deploy Imperium
2on:
3  push:
4    branches: [main]
5  pull_request:
6    branches: [main]
7
8jobs:
9  test:
10    runs-on: ubuntu-latest
11    steps:
12      - uses: actions/checkout@v4
13      - uses: actions/setup-node@v4
14        with:
15          node-version: 20
16          cache: 'yarn'
17      - run: yarn install --frozen-lockfile
18      - run: yarn lint
19      - run: yarn test --coverage
20      - run: yarn build
21
22  deploy:
23    needs: test
24    runs-on: ubuntu-latest
25    if: github.ref == 'refs/heads/main'
26    steps:
27      - uses: actions/checkout@v4
28      - uses: docker/build-push-action@v5
29        with:
30          context: .
31          push: true
32          tags: imperator/roman-imperium:latest

4. Health Check moduł

1// health/health.controller.ts
2@Controller('health')
3export class HealthController {
4  constructor(
5    private health: HealthCheckService,
6    private mongoose: MongooseHealthIndicator,
7    private memory: MemoryHealthIndicator,
8  ) {}
9
10  @Get()
11  @HealthCheck()
12  check() {
13    return this.health.check([
14      () => this.mongoose.pingCheck('mongodb'),
15      () => this.memory.checkHeap('memory', 300 * 1024 * 1024),
16    ]);
17  }
18}

5. Logger produkcyjny

1// main.ts
2import { WinstonModule } from 'nest-winston';
3import * as winston from 'winston';
4
5const app = await NestFactory.create(AppModule, {
6  logger: WinstonModule.createLogger({
7    transports: [
8      new winston.transports.Console({
9        format: winston.format.combine(
10          winston.format.timestamp(),
11          winston.format.json(),
12        ),
13      }),
14    ],
15  }),
16});

6. Bezpieczeństwo

1// main.ts
2import helmet from 'helmet';
3import compression from 'compression';
4
5app.use(helmet());
6app.use(compression());
7app.enableCors({
8  origin: process.env.ALLOWED_ORIGINS?.split(','),
9  credentials: true,
10});
11app.useGlobalPipes(new ValidationPipe({
12  whitelist: true,
13  forbidNonWhitelisted: true,
14  transform: true,
15}));

Checklist wdrożeniowy

1const deploymentChecklist = {
2  docker: [
3    'Multi-stage Dockerfile',
4    'Non-root user',
5    '.dockerignore',
6    'Health check w Dockerfile',
7  ],
8  compose: [
9    'API + MongoDB + Redis',
10    'Health checks na serwisach',
11    'Wolumeny dla trwałych danych',
12    'Izolowana sieć',
13  ],
14  cicd: [
15    'Lint + Test + Build',
16    'Docker build i push',
17    'Sekrety w GitHub Secrets',
18  ],
19  security: [
20    'Helmet headers',
21    'CORS konfiguracja',
22    'Rate limiting',
23    'ValidationPipe',
24    'Compression',
25  ],
26  monitoring: [
27    'Health check endpoint',
28    'Structured logging (JSON)',
29    'Log rotation',
30  ],
31};

Gratulacje, legioniście! Ukończyłeś wielką kampanię — masz teraz pełny pipeline wdrożeniowy dla swojej aplikacji NestJS. Drogi Imperium prowadzą od kodu źródłowego aż do produkcji!

Przejdź do CodeWorlds