Next.JS 최적화 여정: 도커 이미지 78% 경량화와 CDN 적용기

Dev
2025년 10월 12일

들어가며

학교 캡스톤 프로젝트로 시작한 체험단 서비스인 ‘체험콕'을 개발중이며, 실제 운영까지 목표로 하다 보니 CI/CD 구축은 필수였다.

다만 서비스 초기에 설정해둔 CI/CD 과정은 실제로 서비스가 가동되기까지 오랜 시간이 걸렸다. 이 문제를 해결하기 위해 필자가 겪었던 과정을 정리해보고, 또 필자와 같은 주니어 개발자들이 본인의 프로젝트에도 직접 적용해보는 과정을 겪으면 좋겠다는 마음에 이번 포스팅을 작성하게 되었다.

도커 이미지 경량화

Next.js 프로젝트를 컨테이너로 배포하기 위해서는 도커 이미지를 빌드해야 한다. 도커 허브에 푸시하거나 빌드 서버에서 배포 서버로 이미지를 옮기는 상황을 고려하면, 이 도커 이미지의 용량이 작을수록 속도 면에서 유리할 것이다.
결국 도커 이미지의 용량을 줄이기 위해서는 빌드 파일의 용량을 경량화 시켜야 한다. Next.js에서는 빌드 결과물을 경량화할 수 있는 기능을 제공하고 있고, 필자는 이 기능을 이용해서 경량화를 진행했다.

Next.js standalone 공식문서

standalone 옵션으로 빌드 결과물 경량화

먼저 Next.js 프로젝트의 next.config.tsoutput: ‘standalone’ 옵션을 추가했다.

next.config.ts의 output옵션 설정next.config.ts의 output옵션 설정

옵션을 추가한 이후 next build 명령어를 실행하면, 빌드 결과물과 함께 .next/standalone 폴더가 생성된다.
이 폴더 안에는 프로덕션 서버 구동에 필요한 최소한의 의존성 파일만 복사해서 들어간다.

따라서 이미지를 빌드할 때 standalone 폴더와 함께 public, .next/static 폴더 그리고 환경 변수 파일 등 서비스 구동에 필요한 파일을 포함시키면 된다.

빌드 결과빌드 결과

Next.js 공식 문서에서는 static과 같은 정적 파일 (js, css 등)은 CDN을 통해 서빙하는 것을 권장하고 있다.
이 내용은 다음 섹션 CDN 파트에서 다룰 예정이다.

필자의 경우에는 Jenkins가 구동 중인 서버에서 이미지를 빌드하고 있다. Jenkins 파이프라인에서 프로젝트를 빌드 할 때, Jenkins에 저장된 환경 변수 파일을 주입한다.
빌드가 완료되면, 위에서 설명한 서비스 구동에 필수적인 파일들만 포함하여 최종 도커 이미지를 생성한다.

도커 이미지 용량 비교도커 이미지 용량 비교

필자는 개발중인 프로젝트에 위 옵션을 적용하고 실질적으로 어느정도 경량화가 이루어졌는지 확인해보았다.
standalone 옵션 적용 전인 1.58GB에서 354.4MB로 약 78%의 용량 개선을 이뤄냈다.

빌드 시간 단축

CI/CD 구조를 개편하며 빌드 시간도 단축되었다. 기존 56분 많게는 8분까지 걸리던 전체 파이프라인이 약 4분 내외로 완료되어 23분가량의 시간을 단축시킬 수 있었다. (아쉽게도 변경 전 빌드 시간을 확인하지 못하여 변경 후 사진만 업로드했다. 추후 확인이 가능하면 추가로 업데이트 할 예정이다.)

파이프라인 소요 시간파이프라인 소요 시간

CDN 적용

앞서 언급했듯이 publicstatic 폴더에 있는 정적 데이터(css, js, 이미지, 폰트 등)는 CDN을 통해 서빙하는 것이 성능 최적화에 유리하기 때문에 Next.js 공식 문서에서 권장하고 있다.

이 글에서 AWS S3 버킷 생성 또는 CloudFront 설정과 같은 구체적인 클라우드 서비스 설정 방법은 다루지 않을 것이다. 개인마다 사용하는 환경이 다를 수 있고, 이 부분은 본인이 사용하고 있는 스펙에 맞춰 다른 블로그를 참고해주길 바란다.

CDN을 연동하는 방법은 매우 간단하다. next.config.ts 파일에서 assetPrefix 옵션을 설정해주면 끝이다.

CDN 설정CDN 설정

필자는 S3에 정적 파일들을 업로드하여 CDN과 연동했다. 주의할 점은 static 폴더 내부의 파일 또는 폴더들은 빌드마다 명칭이 변경된다. 따라서 빌드마다 새로 업로드를 해주도록 설정했다.
왜 빌드마다 명칭이 변경되는지 궁금해서 찾아보니 다음과 같은 이유가 있다고 알게 되었다.

CDN은 엣지 서버를 통해 정적 파일을 서빙한다. 그리고 각 엣지서버는 더 나은 성능을 위해 정적 파일들의 정보를 캐싱한다.
이 때, 우리가 프로젝트의 기능을 업데이트해서 새로 빌드하고 올렸는데 파일의 명칭이 동일하면 엣지 서버는 파일이 변경되었는지 인식하지 못한다.
이러한 문제를 방지하기 위해 빌드 시 파일명에 고유한 해시값을 붙여 파일이 변경되었음을 감지하도록 하며, 사용자는 최신 버전의 파일을 받을 수 있다.

S3에 업로드한 정적 파일S3에 업로드한 정적 파일

이제 설정을 했으니 실제 배포 서비스에서 데이터를 어떻게 받아오는지 확인해보자.
CDN 적용 전에는 서비스를 실행중인 Next.js 서버에서 파일을 받아오는것을 확인할 수 있다.

CDN 적용 전CDN 적용 전

CDN 적용 후에는 설정한 CloudFront 주소에서 받아오는 것을 확인할 수 있다.
CDN 적용 후CDN 적용 후

마무리

CI/CD 파이프라인을 직접 구축하고 CDN을 적용해본 경험은 아주 값졌다. 주니어 개발자로서 인프라를 직접 만져볼 기회도 적었고, 어드민이나 B2B 서비스 개발에 주로 참여하다 보니 CDN 같은 기술을 사용할 기회도 많지 않았다.
이번 경험을 통해 서비스 성능 최적화의 중요성과 인프라에 대한 이해도를 한층 높일 수 있었고, 앞으로도 많은 시도를 해볼 예정이다.