⚠️ 주의: 이 포스팅을 포함한 총 3편의 Next.js 배포 최적화 시리즈는 제가 실제 환경에서 시행착오를 겪으며 얻은 경험과 지식을 정리한 글입니다.
이 글들은 완벽한 정답이 아니라, 다양한 시도와 시행착오를 통한 저의 삽질기이자 성장 과정이며, 동시에 나와 비슷한 고민을 하는 사람들과 지식을 나누고자 하는 목적으로 작성되었습니다.
따라서, 가능하면 3편의 글을 모두 읽고, 환경과 상황에 맞춰 신중히 테스트한 후 적용하는 것을 추천합니다.
마지막까지 읽으시면 무엇이 문제였는지, 그리고 어떻게 해결했는지 확인할 수 있습니다! 🚨🚧✨
📋 총 3편의 글 리스트
Next.js + AWS ECS 컨테이너 배포하기 : CodePipeline 활용한 CI/CD 자동화와 Docker 빌드 최적화 사례 분석 [1
⚠️ 주의: 이 포스팅을 포함한 총 3편의 Next.js 배포 최적화 시리즈는 제가 실제 환경에서 시행착오를 겪으며 얻은 경험과 지식을 정리한 글입니다.이 글들은 완벽한 정답이 아니라, 다양한 시도
tacit.tistory.com
Next.js + AWS ECS 컨테이너 배포하기 : CodePipeline 활용한 CI/CD 자동화와 Docker 빌드 최적화 사례 분석 [2
⚠️ 주의: 이 포스팅을 포함한 총 3편의 Next.js 배포 최적화 시리즈는 제가 실제 환경에서 시행착오를 겪으며 얻은 경험과 지식을 정리한 글입니다.이 글들은 완벽한 정답이 아니라, 다양한 시도
tacit.tistory.com
Next.js + AWS ECS 컨테이너 배포하기 : CodePipeline 활용한 CI/CD 자동화와 Docker 빌드 최적화 사례 분석 [3
1. 원인 분석캐시 이미지 생성·업로드·다운로드 과정에서 소요되는 시간 때문에 Docker 레이어 캐싱 전략이 오히려 비효율적이었습니다.npm ci 명령어의 캐싱 불확실성으로 인해 Docker 레이어 캐싱
tacit.tistory.com
🚨빌드 캐싱을 성공적으로 적용했다고 생각했지만, 예상치 못한 큰 문제가 발생하였다
- 동일한 빌드 인스턴스 내에서만 캐싱이 적용되는 현상
- 성공 후 다른 배포 환경에서는 다시 7분대로 빌드 시간이 늘어난 것을 확인
1. 원인 분석
📌 AWS CodePipeline + CodeBuild 빌드 환경의 특성
- AWS CodeBuild는 매번 **새로운 EC2 기반 임시 가상환경(컨테이너 또는 VM)**에서 빌드를 실행합니다.
- Docker의 레이어 캐시는 일반적으로 로컬 호스트의 디스크를 사용하기 때문에, 매번 새로운 환경에서 실행되는 CodeBuild에서는 로컬 캐시를 사용할 수 없습니다.
즉, 빌드가 매번 완전히 새로운 환경에서 실행되기 때문에 이전의 캐시가 전혀 없다는 문제점이 있었습니다.
2. 해결방안 적용하기
✅ BuildKit과 원격 레지스트리 캐시(ECR) 활용
--cache-from type=registry,ref=your-ecr-repo:cache
--cache-to type=registry,ref=your-ecr-repo:cache,mode=max
- Docker 캐시 레이어를 로컬 대신 ECR 같은 외부 저장소에 업로드하여 빌드 환경과 독립적으로 사용합니다.
- BuildKit을 활성화(buildx)하여 사용하며, ECR의 OCI 캐시 기능을 활용합니다.
🚫 효과가 없었던 시도
- 로컬 캐시 사용 (--cache-from=type=local)
- 로컬 디렉토리 캐시를 사용하려 했으나, CodeBuild 환경에서는 실패 ❌
- Docker Layer Caching(DLC) 옵션
- CodeBuild의 인스턴스 재사용이 거의 없어 효과 없음 ❌
3. 적용 코드
📜 buildspec-build.yml 변경
build:
commands:
- echo Build started on `date` - TEST BUILD
- sh locale.sh
- sh buildspec/test/pre_build.sh
# docker buildx 빌더 인스턴스 생성 및 사용
- docker buildx create --use
- |
docker buildx build \
-f $DOCKERFILE_PATH \
-t $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG \
--build-arg WHATAP_LICENSE=$WHATAP_LICENSE \
--cache-from type=registry,ref=$AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:cache \
--cache-to type=registry,ref=$AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:cache,mode=max,image-manifest=true,compression=zstd \
--load \
.
🛠️ BuildKit의 장점
항목 | 설명 |
🔧 기본 설정 | Docker Desktop 및 Docker 23.0 이상에서는 기본 활성화 |
🚀 성능 | 병렬 처리, 불필요한 명령 생략, 빠른 파일 접근 |
📦 캐시 | 효율적인 레이어 캐싱 및 관리 |
📂 컨텍스트 최적화 | 변경된 파일만 전송하여 속도 향상 |
🧩 안정성 | 중간 컨테이너와 이미지 영향을 최소화 |
4. 캐싱의 한계와 실제 효과 분석
- Docker 레이어 캐싱은 Dockerfile의 각 명령별로 캐시 레이어를 생성하여 재사용합니다.
- 특정 레이어 변경 시 이후 모든 레이어가 다시 실행되어야 합니다.
📋 빌드 로그를 통한 캐시 확인 방법
#7 [builder 1/6] FROM public.ecr.aws/docker/library/node:20.5.1-alpine3.18
#7 DONE 0.0s
#8 importing cache manifest from amazonaws.com/front:cache
#8 DONE 0.3s
#9 [builder 2/6] WORKDIR /application
#9 CACHED
#10 [builder 3/6] COPY package*.json ./
#10 CACHED
...
- 캐싱된 레이어는 "CACHED"로 표시되며, 실제 명령 실행 없이 원격 캐시에서 다운로드한 결과입니다.
- 그러나 환경적 요인(새로운 환경, npm 버전 차이, timestamp 등)으로 인해 RUN npm ci 같은 명령은 캐시가 되지 않고 매번 실행됩니다.
👉 결과적으로, 빌드 시간이 기대만큼 단축되지 않았고, 오히려 캐시 업로드 및 다운로드 과정에서 시간이 추가 소요되었습니다.
이에 대한 추가 개선책으로, AWS S3를 이용한 node_modules, .next/cache 디렉토리 캐싱 전략으로 다시 전환하게 되었습니다.
이어서..
Next.js + AWS ECS 컨테이너 배포하기 : CodePipeline 활용한 CI/CD 자동화와 Docker 빌드 최적화 사례 분석 [3
1. 원인 분석캐시 이미지 생성·업로드·다운로드 과정에서 소요되는 시간 때문에 Docker 레이어 캐싱 전략이 오히려 비효율적이었습니다.npm ci 명령어의 캐싱 불확실성으로 인해 Docker 레이어 캐싱
tacit.tistory.com