NestJS 프로젝트 docker 배포 + 이미지 크기 줄이기

Jaden Kim·2023년 3월 18일
1
post-thumbnail
post-custom-banner

server 부분의 프로젝트는 NestJS로 구성되어 있었다.
처음에는 dependency package를 설치하고, build 하고, 실행하는 커맨드 지정하는 식으로 간단한 수준의 Dockerfile을 작성했다.

FROM node:16-alpine

WORKDIR /usr/src/app

COPY ./package.json ./

RUN yarn

COPY . .

RUN yarn build

CMD [ "yarn", "start:prod" ]

이렇게 하면 간단하게 구현 가능하지만, 전혀 최적화되지 않은 상태로 이미지가 빌드된다.
그래서 처음에는 이미지의 크기가 대략 570MB 정도였다.

이미지 크기를 줄이기 위해 블로그를 찾아보니, 다단계 도커를 활용하여 효율적으로 이미지를 만든 포스팅을 찾을 수 있었다.
https://www.tomray.dev/nestjs-docker-production

해당 내용을 프로젝트에 맞게 일부 수정한 후 새롭게 이미지를 빌드해보니 이미지 크기가 290MB 정도로 절반으로 줄일 수 있었다!
아래는 해당 내용들 각각에 대한 설명이다.

1. dev 의존성 설치

FROM node:18-alpine AS base

FROM base AS deps
WORKDIR /usr/src/app

COPY --chown=node:node package.json yarn.lock ./
RUN yarn --frozen-lockfile;

USER node

yarn을 이용해서 production에 필요한 패키지들만 설치하기 위해서는 --production 옵션을 사용하면 된다.
하지만 이렇게 할 경우 이후에 production용 빌드를 얻기 위해 yarn build -> nest build 명령어를 실행해야 하는데, nest 키워드를 사용할 수 없다는 결과를 얻게 된다.

#9 0.495 yarn run v1.22.19
#9 0.527 $ nest build
#9 0.542 /bin/sh: nest: not found
#9 0.552 error Command failed with exit code 127.
#9 0.552 info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

nest는 dev dependency에 추가되도록 package manager가 구성되어 있기 때문에 발생하는 문제이다.
이 때문에 1차적으로는 dev dependency까지 모두 받아야 한다.

2. 프로젝트 빌드 & prod 의존성 재설치

FROM base AS build
WORKDIR /usr/src/app

COPY --chown=node:node --from=deps /usr/src/app/node_modules ./node_modules
COPY --chown=node:node . .

RUN yarn build

ENV NODE_ENV production

RUN yarn --frozen-lockfile --production;
RUN rm -rf ./.next/cache

USER node

yarn build -> yarn build를 이용하여 프로젝트를 빌드한다.
전 단계에서 dev dependency를 모두 설치했기 때문에 nest 명령어 사용이 가능한 상태이다.
빌드가 완료되면 yarn --production을 통해 production에 필요한 패키지만 골라서 재설치한다.
이렇게 하면 이전 단계의 dev dependency가 포함된 node_modules가 덮어씌어져서 최적화된 패키지 목록만 가지고 있게 된다.

3. 프로젝트 실행

FROM base AS production
WORKDIR /usr/src/app

COPY --chown=node:node --from=build /usr/src/app/node_modules ./node_modules
COPY --chown=node:node --from=build /usr/src/app/dist ./dist

CMD [ "node", "dist/main.js" ]

yarn build 결과 dist 하위 폴더에 최적화된 빌드 파일이 형성된다.
해당 빌드 파일들과 node_modules를 최종 이미지에 copy하고, 빌드 파일을 실행하는 명령어인 node dist/main.js 를 컨맨드로 등록한다.

전체 파일

FROM node:18-alpine AS base

# INSTALL DEPENDENCIES FOR DEVELOPMENT (FOR NEST)
FROM base AS deps
WORKDIR /usr/src/app

COPY --chown=node:node package.json yarn.lock ./
RUN yarn --frozen-lockfile;

USER node

# INSTALL DEPENDENCIES & BUILD FOR PRODUCTION
FROM base AS build
WORKDIR /usr/src/app

COPY --chown=node:node --from=deps /usr/src/app/node_modules ./node_modules
COPY --chown=node:node . .

RUN yarn build

ENV NODE_ENV production
RUN yarn --frozen-lockfile --production;
RUN rm -rf ./.next/cache

USER node

# PRODUCTION IMAGE
FROM base AS production
WORKDIR /usr/src/app

COPY --chown=node:node --from=build /usr/src/app/node_modules ./node_modules
COPY --chown=node:node --from=build /usr/src/app/dist ./dist

CMD [ "node", "dist/main.js" ]
post-custom-banner

0개의 댓글