도커 이미지 최적화: 멀티 스테이지 빌드와 Turbo Prune 활용

Woody·2024년 8월 26일
0

도커

목록 보기
2/2

멀티 스테이지 빌드와 Turborepo의 turbo prune 명령어를 활용하여 이미지 크기를 대폭 줄이는 방법에 대해 알아보겠습니다.

  1. 기본 환경 설정
dockerfileCopyFROM node:20-slim AS base
ENV PNPM_HOME="/pnpm"  
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable
RUN apt-get update && apt-get install -y
  • node:20-slim 버전을 사용하여 베이스 이미지 자체를 경량화합니다.
  • pnpm에서 제시하는 방식으로 환경 변수를 지정합니다.
  • corepack enable을 통해 패키지 매니저를 사용할 수 있도록 설정합니다.
  • apt-get을 사용하여 필요한 패키지를 설치합니다.
  1. 빌드 환경 설정
dockerfileCopyFROM base AS builder
WORKDIR /app

ARG APP_NAME  
ENV APP_NAME=${APP_NAME}

COPY . .
RUN npx turbo prune --scope=${APP_NAME} --dockere --scope=${APP_NAME} --docker
  • 베이스 이미지를 기반으로 builder 스테이지를 생성합니다.

  • APP_NAME을 인수로 받아 환경 변수로 설정합니다.

  • turbo prune 명령어를 사용하여 의존성을 최적화합니다.

  • --docker 옵션을 통해 도커용으로 최적화된 출력을 생성합니다.

  • out과 full 디렉토리로 구분하여 의존성을 정리합니다.

turbo prune을 사용하면 워크스페이스의 파일이 추가될 때마다 처음부터 다시 설치하는 문제를 해결할 수 있습니다. 의존성과 관련된 부분만 캐싱하여 빌드 속도를 개선합니다.

  1. 의존성 설치
dockerfileCopyFROM base AS installer  
WORKDIR /app

ARG APP_NAME
ENV APP_NAME=${APP_NAME}  

COPY .gitignore .gitignore
COPY --from=builder /app/out/json/ .
COPY --from=builder /app/out/pnpm-lock.yaml ./pnpm-lock.yaml  
COPY --from=builder /app/out/pnpm-workspace.yaml ./pnpm-workspace.yaml
RUN pnpm install --frozen-lockfile
  • builder 스테이지에서 생성된 out 디렉토리에서 필요한 파일들을 복사합니다.
  • pnpm install --frozen-lockfile을 사용하여 의존성을 설치합니다.
  1. 빌드 단계
dockerfileCopyCOPY --from=builder /app/out/full/ .  
RUN pnpm --filter ${APP_NAME} build
  • builder 스테이지에서 생성된 full 디렉토리를 복사합니다.
  • APP_NAME을 필터로 사용하여 프로젝트를 빌드합니다.
  1. 최종 실행 환경 설정
dockerfileCopyFROM base AS runner  
WORKDIR /app

ARG APP_NAME
ENV APP_NAME=${APP_NAME}  
ENV NODE_ENV=production

COPY --from=installer /app/apps/${APP_NAME}/.next/standalone ./
COPY --from=installer /app/apps/${APP_NAME}/.next/static ./apps/${APP_NAME}/.next/static  
COPY --from=installer /app/apps/${APP_NAME}/public ./apps/${APP_NAME}/public
  • installer 스테이지에서 필요한 파일들을 복사합니다.

  • Next.js의 standalone 옵션을 사용하여 경량화된 프로덕션 빌드를 생성합니다.

  • next.config.mjs 파일에서 output: 'standalone' 옵션을 설정해야 합니다.

  • node_modules를 설치하지 않고도 독립적으로 배포할 수 있습니다.

  • public과 static 디렉토리는 별도로 복사해야 합니다.

start.sh 스크립트 생성

dockerfileCopyRUN echo "#!/bin/sh\n\  
if [ -z \"\$APP_NAME\" ]; then\n\
  echo \"APP_NAME 환경 변수가 설정되지 않았습니다.\"\n\  
  exit 1\n\
fi\n\
echo \"Starting application \${APP_NAME}...\"\n\
exec node apps/\${APP_NAME}/server.js" > start.sh

RUN chmod +x start.sh

ENV PORT=8000
EXPOSE 8000

ENTRYPOINT ["./start.sh"]
  • start.sh 스크립트를 생성하여 애플리케이션을 실행합니다.
  • APP_NAME 환경 변수가 설정되어 있는지 확인하고, 애플리케이션을 시작합니다.
  • ENTRYPOINT를 사용하여 컨테이너 실행 시 스크립트를 자동으로 실행합니다.

결과


  1. 위와 같은 최적화 과정을 거쳐 도커 이미지 크기를 기존 1.08GB에서 274.76MB까지 줄일 수 있었습니다.
  2. 캐시 히트 전략을 통해서 빌드의 속도를 늘려 CI 속도 개선을 성공했습니다.

요약

  1. 멀티 스테이지 빌드를 활용
  2. turbo prune을 사용하여 의존성을 최적화함으로써 이미지 크기를 대폭 줄일 수 있습니다.
  3. Next.js의 standalone 옵션을 사용하여 경량화된 프로덕션 빌드를 생성할 수 있습니다.

레퍼런스

https://pnpm.io/docker

https://nextjs.org/docs/app/building-your-application/deploying

https://turbo.build/repo/docs/guides/tools/docker

https://nextjs.org/docs/pages/api-reference/next-config-js/output

https://turbo.build/repo/docs/reference/prune

https://turbo.build/repo/docs/reference/prune

https://www.inflearn.com/blogs/3871

https://oliveyoung.tech/blog/2024-06-16/next-cdn-standalone/

profile
프론트엔드 개발자로 살아가기

0개의 댓글