마지막 글이 1년하고 1개월 전입니다. 제가 기술 블로그를 쓰기 어려워하는 사람인 줄 알았는데 그저 게으른 사람이란 걸 알게 되었습니다. 오늘은 최근 회사 리뉴얼 프로젝트에서 nextjs 도커 이미지 사이즈 및 빌드 타임 감소를 진행했던 경험을 공유하고자 합니다.
우선 이직할 때부터 존재하던 Dockerfile을 제대로 살펴보지 않았습니다. 도커에 대한 지식이 부족했고 디자인 시스템이 주 업무였기 때문에 안일했습니다. 그러던 중 시간이 갈수록 프론트엔드 파트에서도 devops 역할을 할 사람이 필요해졌고 이에 따라 공부하면서 파악한 기존 방식의 문제는 두 가지였습니다.
.next
폴더와
node_modules
를
모두 복사하고 있어 불필요하거나 중복하여 의존성을 가져가고 있다.
standalone
속성을 사용하지 않았다.입니다. 1번은 node_modules라는 거대한 의존성을 통째로 docker image로 옮기는 문제, 2번은 .next 역시 보다 경량화가 가능한 문제지만 사실 이는 모두 nextjs에서 제공하는 하나의 해결책을 통해 풀 수 있습니다.
우선 기존 도커파일에서 문제가 되었던 부분을 살펴보겠습니다.
/* Dockerfile */
/* ...중략... */
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 80
CMD ["yarn", "start"]
실제로 현재의 .next 폴더는 node_modules를 가지고 있지 않기 때문에 개발환경 상의 node_modules를 복사하지 않는다면 배포한 웹사이트는 동작하지 않습니다. 이를 위해 nextjs는 standalone
이라는 옵션을 제공합니다.
nextjs output 관련 공식문서 의 설명입니다.
Next.js can automatically create a standalone folder that copies only the necessary files for a production deployment including select files in node_modules. To leverage this automatic copying you can enable it in your next.config.js:
출처: nextjs output
이에 따라 next.config.js 에 아래와 같은 설정을 해주면 build 시 .next 파일에 standalone이라는 파일이 생성되고, 그 안에 배포시 꼭 필요한 node_modules를 생성해 줍니다.
module.exports = {
output: 'standalone',
}
이 때 next.config.js는 next bulid 중에 읽혀 standalone 폴더 내에 들어있는 server.js file에 serialized 됩니다. 따라서 기존처럼 yarn start
를 통해 build 폴더를 실행시키는 대신 server.js
파일을 직접 실행시킵니다.
원래라면 CMD ["node", "server.js"]
명령어를 통해 실행하면 끝입니다. 그러나 BE에서 사용하는 포트번호가 80번이고 containerPort와 hostPort를 통일할 필요가 있어 EXPOSE 80 및 taskdef.json의 port 설정을 바꾸는 대신 가장 간단한 방법인 server.js의 default 포트번호를 3000번에서 80번으로 변경하여 실행시키기로 했습니다. 다음은 변경된 Dockerfile 입니다.
/* Dockerfile */
/* ...중략... */
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
EXPOSE 80
CMD /bin/sh -c "PORT=80 node server.js"
이를 통해 다음과 같은 결과를 얻을 수 있었습니다.
<변경 전 - 2.79GB>
<변경 후 - 187.17MB>
코드 수정은 크지 않았지만 큰 임팩트를 줄 수 있는 이슈였습니다. 결과적으로 해결의 실마리는 nextjs의 build 과정을 보다 잘 이해하고 제공하는 옵션을 활용하는 것에 있었습니다. 그러나 개인적으로 docker 와 aws 에 관해 무지하여 필요 이상의 시간을 소요 했습니다. 현타가 조금 와 냅다 udemy의 docker 강의와 aws 강의를 끊어서 수강하고 있으니 해당 포스트를 조금 더 발전시켜 다시 업로드할 날이 오리라 믿어 의심치 않습니다.