React 배포 방식을 EC2에서 S3와 CloudFront로 변경한 이유

#React#배포

들어가며

앱 서비스를 운영하던 스타트업에서 React로 쇼핑몰 사이트를 개발했다. 해당 프로젝트를 배포할 당시, 나는 따로 맡은 기능이 있어 동료가 배포 작업을 진행했다. 배포 방식을 물어보니 EC2를 활용한다고 했다.

나는 S3와 CloudFront를 이용한 방식이 비용 면에서 훨씬 유리하다는 것을 알고 있었기에 이를 제안했다. 하지만 동료는 해당 방식에 대한 경험이 없었고, 새롭게 학습하여 진행할 시간적 여유가 부족하여 우선 EC2에 배포하는 방식으로 진행했다.

하지만 나는 EC2 배포 방식이 비효율적임을 알고 있었다. React는 빌드한 파일을 정적으로 호스팅만 해주면 되기 때문이다. 특히 자원이 한정된 스타트업에서는 시간만큼이나 비용도 소중한 자원이다. EC2와 S3+CloudFront의 운용 비용 차이는 간과할 수 없는 수준이었기에, 결국 배포 방식을 변경하기로 했다.

이번 글에서는 React가 어떻게 빌드되고 배포되는지 살펴보고, 왜 EC2보다 S3와 CloudFront를 사용하는 것이 경제적인지 정리하려 한다.

React 애플리케이션은 어떻게 빌드되고 배포될까?

React가 어떻게 배포되는지 이해해야 S3+CloudFront 조합의 효율성을 파악할 수 있다.

React는 npm run build 명령어를 통해 프로덕션 환경에 최적화된 빌드 결과물을 생성한다. 이 과정은 소스코드를 브라우저가 실행할 수 있는 형태의 정적 파일들로 변환하며, 결과물은 프로젝트 루트의 build 또는 dist 디렉터리에 저장된다. 즉, 빌드 후 생성된 정적 파일을 브라우저의 요청에 따라 응답하기만 하면 배포가 완료되는 구조다.

당시 AWS를 사용 중이었기에, 이 정적 파일들을 서빙하기 위한 선택지는 두 가지였다.

  1. EC2에 파일을 올려 호스팅하는 방식
  2. 객체 스토리지(S3)와 CDN(CloudFront)을 조합하여 서빙하는 방식

EC2와 S3 + CloudFront 비교하기

두 방법 모두 서빙 자체에는 문제가 없지만, 효율성 측면에서 다음과 같은 차이가 있다.

1. 가격 (Cost)

Asia Pacific (Seoul) 리전을 기준으로 비교한 결과다.

  • EC2: t4g.micro 인스턴스 1대 사용 시, 한 달 기준 약 $7.74(약 11,426원)가 발생한다. 파일 크기나 요청 수와 상관없이 가용 시간 내내 금액이 부과되는 구조다.
  • S3 + CloudFront: S3는 $0.025/GB 수준이며, CloudFront는 매달 1TB의 데이터 전송과 1,000만 건의 요청을 평생 무료로 제공한다.

당시 MAU는 약 1,700명이었고 빌드 파일 크기는 100MB 미만이었기에, S3와 CloudFront를 사용하는 것은 비용이 0에 수렴했다. 요청이 적은 상황에서 EC2를 계속 켜두는 것은 매우 비효율적이었다.

2. 배포 파이프라인 (Pipeline)

GitHub Actions에서 빌드를 수행하고 결과물을 전송하는 과정에서도 차이가 발생했다.

  • EC2 방식: SSH 핸드셰이크 과정을 거치며 오버헤드가 발생하고, 서버 사양에 따라 처리량이 결정되어 전송 속도가 다소 느렸다. 또한 파일 전송 후 서버 명령을 별도로 실행해야 반영되었다.
  • S3 방식: AWS CLI의 s3 sync 명령어를 사용하면 S3 API의 멀티파트 업로드와 병렬 전송을 활용할 수 있다. 이는 파일을 병렬로 업로드하여 처리량을 극대화하며, 전송 즉시 반영된다는 장점이 있다. 2

S3와 CloudFront 방식의 문제점: 캐시 이슈

배포 방식 변경 후, 새로운 빌드 결과물을 업로드해도 즉시 반영되지 않는 캐시 문제가 발생했다.

CloudFront는 S3의 콘텐츠를 전 세계 엣지 로케이션에 복사하여 저장한다. 이때 기존 파일의 TTL(Time To Live)이 만료되지 않으면, S3에 새 파일이 올라가도 기존 파일을 응답하게 된다. 특히 최신 빌드 툴은 JS/CSS 파일명에 해시값을 붙여 관리하지만, 파일명이 고정된 index.html은 이전 버전을 반환할 가능성이 높다.

이를 해결하기 위해 당시에는 가장 빠르고 단순한 방법인 **CloudFront 캐시 무효화(Invalidation)**를 수행했다. 사용자 규모가 작았고 비즈니스적으로 우선순위가 높은 업무가 많았기 때문이다. 만약 더 근본적인 해결이 필요했다면 AWS가 권장하는 Tiered TTLs1 방식을 적용했을 것이다.

마치며

React 배포 방식을 EC2에서 S3와 CloudFront로 변경하며 인프라 효율을 높일 수 있었다. 물론 SEO를 위한 SSR(Server Side Rendering)이 필요하거나 특수한 목적이 있다면 EC2를 사용할 수 있지만, 상황과 목적에 맞게 클라우드 제품을 선택하는 것이 중요하다.

한 가지 아쉬운 점은 두 방식의 차이를 수치로 정밀하게 기록하지 못한 점이다. 배포 속도가 얼마나 단축되었는지, 비용이 정확히 얼마나 절감되었는지 지표로 남겼다면 더 설득력 있는 글이 되었을 것이다. 다음부터는 이러한 지표 측정을 의식적으로 챙겨야겠다.

References


Profile picture

모든 강아지가 행복했으면 하는 꿈을 가진 개발자 김동호입니다.
주로 개발 공부, 독서・생각 기록, 유기견 봉사활동 후기 등을 기록하고 있어요.