Nest.js를 배워보자/15. NestJS & Prisma 완벽 가이드

🚢 6부. 실전 배포 환경 구성

_Blue_Sky_ 2025. 12. 3. 19:48
728x90

프로젝트를 개발 환경에서 벗어나 실제 사용자에게 제공하는 배포 환경(Production Environment)으로 옮길 때는 몇 가지 중요한 설정과 전략이 필요합니다. 특히 환경 변수 관리, 컨테이너화(Docker), 그리고 안전한 마이그레이션 실행이 핵심입니다.


6.1. 환경 변수 관리

운영 환경에서 데이터베이스 연결 문자열(DATABASE_URL)과 같은 민감한 정보는 소스코드 외부에 안전하게 보관하고 관리해야 합니다.

📜 1. .env 파일과 NestJS ConfigModule

개발 환경에서는 프로젝트 루트의 .env 파일을 사용합니다. NestJS에서는 공식적으로 @nestjs/config (ConfigModule)를 사용하여 환경 변수를 효율적으로 읽고 애플리케이션에 주입합니다.

설치:

npm install @nestjs/config

사용:

  1. AppModule에 등록:
    // src/app.module.ts
    import { ConfigModule } from '@nestjs/config';
    
    @Module({
      imports: [
        ConfigModule.forRoot({
          isGlobal: true, // 전역 모듈로 설정하여 어디서든 ConfigService 사용 가능
          envFilePath: '.env', // 개발 환경 파일 경로
        }),
      ],
      // ...
    })
    export class AppModule {}
    
  2. PrismaService에서 사용: PrismaService는 .env 파일을 직접 읽기 때문에 ConfigModule을 필수로 사용할 필요는 없지만, 애플리케이션의 다른 설정(예: API 키, 포트 번호)을 관리할 때 ConfigService를 사용하면 일관성 있게 환경 변수에 접근할 수 있습니다.
     
    // src/app.service.ts 또는 다른 서비스
    import { ConfigService } from '@nestjs/config';
    
    // ...
    constructor(private configService: ConfigService) {
      const port = this.configService.get<number>('PORT');
      console.log(`Application running on port: ${port}`);
    }
    

🔐 2. 운영 환경 변수 설정

운영 환경에서는 .env 파일을 사용하지 않고, 컨테이너 오케스트레이션 도구(Kubernetes), 클라우드 서비스(AWS ECS/Lambda), 또는 CI/CD 파이프라인에서 직접 환경 변수를 주입합니다.

# 운영 환경 배포 시 (예시)
# DATABASE_URL을 직접 설정
DATABASE_URL="postgresql://user:password@db-host:5432/production_db" npm run start:prod

6.2. Docker를 이용한 배포 환경

Docker를 사용하면 애플리케이션과 모든 종속성을 컨테이너 이미지로 패키징하여, 개발 환경과 동일한 조건으로 운영 환경에서 실행할 수 있습니다.

🐳 1. Dockerfile 작성

NestJS 애플리케이션을 빌드하고 실행하는 기본적인 Dockerfile입니다.

# 1단계: 빌드 환경 (Node.js LTS 버전 사용)
FROM node:20-alpine AS builder

# 작업 디렉토리 설정
WORKDIR /usr/src/app

# 패키지 파일 복사 및 종속성 설치
COPY package*.json ./
RUN npm install

# 전체 소스 코드 복사
COPY . .

# NestJS 앱 빌드
RUN npm run build

# 2단계: 운영 환경
FROM node:20-alpine AS production

# 작업 디렉토리 설정
WORKDIR /usr/src/app

# 운영 환경 종속성만 설치
COPY package*.json ./
# 개발 종속성을 제외하고 설치
RUN npm install --only=production

# 빌드 단계에서 생성된 결과물 복사
COPY --from=builder /usr/src/app/dist ./dist
# Prisma Client를 실행하는 데 필요한 파일 복사
COPY --from=builder /usr/src/app/node_modules/.prisma/client ./node_modules/.prisma/client
COPY prisma ./prisma

# 애플리케이션이 수신할 포트 노출
EXPOSE 3000

# NestJS 애플리케이션 실행
# 환경 변수 (DATABASE_URL 등)는 컨테이너 실행 시 주입됩니다.
CMD ["node", "dist/main"]

📦 2. 컨테이너 환경에서 Prisma Client 실행

Prisma Client는 데이터베이스와의 연결을 위해 바이너리 파일을 사용합니다. Dockerfile에서 다음 단계를 통해 이 바이너리 파일이 최종 이미지에 포함되도록 반드시 보장해야 합니다.

# ⭐️ 핵심: 빌드 단계에서 생성된 Prisma Client 파일을 복사
COPY --from=builder /usr/src/app/node_modules/.prisma/client ./node_modules/.prisma/client
COPY prisma ./prisma


6.3. 운영 환경 마이그레이션 전략

운영 데이터베이스는 민감하므로, 마이그레이션은 자동화되고 안전하게 실행되어야 합니다.

🚦 1. migrate deploy 사용

운영 환경에서는 개발 환경에서 사용했던 npx prisma migrate dev 대신 npx prisma migrate deploy 명령을 사용해야 합니다.

  • migrate dev: 개발 전용 명령어. 마이그레이션 기록이 없거나 충돌 시 DB를 초기화하거나 수정하라는 프롬프트를 띄웁니다 (운영에서 절대 금지).
  • migrate deploy: 운영 전용 명령어. 이미 존재하는 마이그레이션 파일(prisma/migrations)을 읽고, 아직 DB에 적용되지 않은 마이그레이션만 안전하게 실행합니다. 사용자와의 상호작용이 전혀 없습니다.

실행 순서:

  1. 개발 환경: 로컬에서 npx prisma migrate dev --create-only를 사용하여 마이그레이션 파일을 생성하고 커밋합니다.
  2. 배포 파이프라인: 컨테이너 빌드 후, 애플리케이션 실행 전에 마이그레이션을 실행합니다.
     
    # 컨테이너 환경에서 실행되는 스크립트 (예시)
    
    # 1. 마이그레이션 실행
    npx prisma migrate deploy
    
    # 2. 애플리케이션 시작
    node dist/main.js
    

🤝 2. zero-downtime 배포

데이터베이스 마이그레이션 시 서비스 중단 시간을 최소화하는 것이 중요합니다.

  • Non-breaking Changes Only: 마이그레이션은 기존 애플리케이션 버전이 문제없이 동작할 수 있는 방식(예: 컬럼 추가, 인덱스 추가)으로만 수행해야 합니다.
  • Two-Phase Deployment: 컬럼 삭제나 이름 변경과 같은 파괴적인 변경은 여러 단계를 거쳐야 합니다.
    1. 새 컬럼 추가/기존 컬럼 유지.
    2. 새 버전 애플리케이션 배포 (새 컬럼 사용 시작).
    3. 다음 배포 시 (한 버전 후) 기존 컬럼을 삭제합니다.
728x90