Nodejs

⚡ NestJS Gateway Dockerfile 최적화하기

NestJS 마이크로서비스를 실무에 배포할 때, Dockerfile 최적화는 필수입니다. 단순히 "잘 동작한다"에서 끝나는 것이 아니라,

이미지 빌드 속도 ⏱, 컨테이너 크기, 실행 성능 ⚡까지 모두 고려해야 하기 때문이죠.

 


 

1. 기존 Dockerfile의 문제점 ⭕

처음 보여준 Dockerfile은 이렇게 작성되어 있었습니다:

FROM node:alpine AS development
WORKDIR /usr/src/app
COPY package.json ./
COPY pnpm-lock.yaml ./
# PNPM 설치하기 RUN npm i-g pnpm
# Dependency 설치하기 RUN pnpm i
#나머지 파일/폴더 복사해오기
COPY . .

CMD ["pnpm", "start:dev", "gateway"]

➡️ 이 Dockerfile은 기본적으로는 동작하지만, 문제가 있습니다:

  1. 캐싱 불가능: 모든 소스를 한 번에 복사하기 때문에 작은 변경에도 모든 빌드가 다시 실행됩니다.

  2. 불필요한 파일 복사: 테스트 코드, 설정 파일, 로컬 전용 파일까지 전부 들어갑니다.

  3. 개발 환경과 배포 환경 구분 없음: production 모드 최적화가 전혀 되어 있지 않습니다.

즉, 빠르게 개발 테스트하는 데는 좋지만, 운영 환경 배포에는 비효율적이라는 거죠. ⚠️

 

 

2. 최적화된 Dockerfile ✅

최적화된 버전은 다음과 같이 크게 developmentproduction 두 개의 스테이지로 분리합니다:

FROM node:alpine AS development   # 개발 환경용 베이스 이미지 (가볍고 빠른 alpine)

WORKDIR /usr/src/app   # 컨테이너 내부 작업 디렉토리 지정

COPY package*.json ./   # 패키지 메타 파일 먼저 복사 (캐싱 최적화)
COPY pnpm-lock.yaml ./
COPY tsconfig.json tsconfig.json   # 타입스크립트 설정 파일 복사
COPY nest-cli.json nest-cli.json   # Nest CLI 설정 파일 복사

# PNPM 설치하기
RUN npm i -g pnpm   # 전역으로 pnpm 설치

# Dependency 설치하기
RUN pnpm i   # 모든 의존성 설치 (devDependencies 포함)

# 빌드에 필요한 파일만 복사
COPY proto /proto   # 프로토콜 버퍼 파일 복사
COPY apps/gateway apps/gateway   # 게이트웨이 앱 소스 복사
COPY libs libs   # 공용 라이브러리 복사

RUN pnpm build gateway   # 게이트웨이 앱 빌드 실행

CMD ["pnpm", "start:dev", "gateway"]   # 개발 모드 실행 커맨드

---

FROM node:alpine AS production   # 운영 환경용 베이스 이미지 (더 가볍게)

ARG NODE_ENV=production
ENV NODE_ENV=${NODE_ENV}   # 운영 모드 환경 변수 설정

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

COPY package.json ./   # 필요한 패키지 파일만 복사
COPY pnpm-lock.yaml ./
COPY proto /proto   # 실행 시 필요한 proto 파일만 복사

RUN npm install -g pnpm   # pnpm 전역 설치
RUN pnpm install --prod   # 운영용 의존성만 설치 (devDependencies 제외)

COPY --from=development /usr/src/app/dist ./dist   # 빌드된 결과물만 가져오기

CMD [ "node", "dist/apps/gateway/main" ]   # 게이트웨이 앱 운영 모드 실행

➡️ 이 구조의 핵심은 멀티 스테이지 빌드입니다.

 

 

3. 멀티 스테이지 빌드의 장점 ⚡

  1. 빌드 단계와 실행 단계를 분리

    • development 단계에서는 TypeScript를 빌드하고, production 단계에서는 빌드된 결과물(dist)만 가져옵니다.

    • 이렇게 하면 최종 이미지 크기가 대폭 줄어듭니다.

  2. 의존성 최소화

    • 개발 단계에서는 devDependencies까지 설치 (pnpm i)

    • 운영 단계에서는 dependencies만 설치 (pnpm install --prod)

    • ➡️ 배포 이미지는 더 가볍고, 보안상도 안전합니다.

  3. 빌드 캐시 활용

    • package.json, pnpm-lock.yaml만 먼저 복사하고 설치를 하기 때문에, 소스 코드 변경 시에도 dependency 설치를 다시 하지 않아도 됩니다.

 

 

 

4. 실무 적용 팁 ⭕

  1. 빌드 속도 최적화

    • .dockerignore 파일을 꼭 작성하세요. node_modules, test/, .git 같은 불필요한 파일이 들어가면 이미지 빌드가 느려집니다.

  2. 보안 강화

    • node:alpine 이미지를 사용하면 기본 Debian 이미지보다 훨씬 가볍습니다. 다만, 필요 시 apk add로 패키지를 설치해야 하니 주의하세요.

  3. 환경 변수 관리

    • ARG와 ENV를 잘 구분하세요.

    • ARG는 빌드 시점에만 사용, ENV는 런타임까지 유지됩니다.

 

 

 

5. 핵심 정리 ✅

  1. 기존 Dockerfile 문제점: 캐싱 불가, 불필요한 파일 복사, 개발/운영 구분 없음.

  2. 최적화된 Dockerfile 핵심: 멀티 스테이지 빌드 ➡️ 개발과 운영 단계 분리.

  3. 이점: 빌드 속도 향상, 이미지 크기 최소화, 보안 강화.

➡️ 결론: NestJS 같은 대규모 프로젝트는 반드시 멀티 스테이지 빌드를 적용해야 합니다.

 

 

 

6. 추가 학습 포인트 ⚡

  • Docker BuildKit 사용법 (DOCKER_BUILDKIT=1)

  • CI/CD 환경에서 docker-compose와 멀티 스테이지 빌드 조합하기

  • distroless 이미지로 보안 강화하기 (Google 제공)

 

 

about author

PHRASE

Level 60  라이트

It is a wise child that knows its own father. (자식은 부모의 마음을 모른다. = 자기 아버지를 아는 아이는 현명한 아이다).

댓글 ( 0)

댓글 남기기

작성