정리해봐요/White label 자동화 여정

해외 진출 딜레마를 CloudFront로 해결하기

양승길 2025. 6. 30. 21:52

문제의 시작: 글로벌 확장의 현실

우리 서비스가 해외로 확장되면서 예상치 못한 문제들에 직면했다. 기존에는 국내에서만 서비스를 제공했는데,
해외 고객들의 요청이 늘어나면서 글로벌 서비스를 고려하게 되었다.

처음에는 단순하게 생각했다. "해외 리전에 똑같은 인프라를 구축하면 되겠네!" 하지만 현실은 달랐다.

마주한 문제들

  • 해외 리전 인프라 구축 비용이 예상보다 2배 이상 증가
  • 국내에서 해외 인프라를 관리하려니 네트워크 지연으로 운영이 어려움
  • 화이트라벨 고객마다 개별 도메인 설정 요청이 쏟아짐
  • 서비스 담당자와 개발자가 매번 수동으로 설정해주는 커뮤니케이션 비용 급증

특히 화이트라벨 서비스 특성상 고객들이 자체 도메인으로 서비스를 제공하고 싶어했는데, 매번 개발팀에 요청해서 수동으로 설정하는 과정이 비효율적이었다.

해결책: CloudFront를 활용한 스마트한 접근

고민 끝에 CloudFront를 중심으로 한 해결책을 찾았다. 핵심 아이디어는 이랬다:

기본 전략

  • 기존 국내 인프라는 그대로 유지
  • CloudFront로 글로벌 CDN 제공
  • 파일 타입별 캐싱 최적화로 성능 극대화

CloudFront 설정의 핵심 Origin을 기존 ALB(Application Load Balancer)로 지정했다. 이렇게 하면 기존 인프라를 그대로 활용하면서도 전 세계 사용자들에게 빠른 속도를 제공할 수 있었다.

가장 중요한 건 파일 타입별 캐싱 전략이었다:

우선순위 1: /assets/*.js (CachingOptimized)
우선순위 2: /assets/*.css (CachingOptimized) 
우선순위 3: /assets/*.woff (CachingOptimized)
우선순위 4: /* (Default behavior - UseOriginCacheControlHeaders)

정적 파일들(JS, CSS, 폰트)은 CachingOptimized 정책으로 오랫동안 캐싱해서 전 세계 어디서든 빠르게 로드되도록 하고, 동적 콘텐츠는 원본 서버의 캐시 헤더를 따르도록 설정했다.

Vue.js 프론트엔드에서 CloudFront 캐싱 최적화

우리는 Vue.js로 프론트엔드를 제공하고 있고, webpack을 통해 bundle로 빌드하고 있다. 실제 운영에서 CloudFront 캐싱이 어떻게 동작하는지 확인해보니 몇 가지 흥미로운 포인트들을 발견할 수 있었다.

빌드 파일별 캐싱 동작 차이

JS/CSS 파일의 경우 Vue.js 빌드 시 webpack이 파일 내용에 따라 해시값을 생성해서 파일명에 포함시킨다:

app.a1b2c3d4.js
main.e5f6g7h8.css

이렇게 되면 코드가 변경될 때마다 완전히 새로운 파일명이 생성되기 때문에, CloudFront에서는 새로운 파일로 인식해서 Origin에서 가져온다. 캐시 무효화를 별도로 할 필요가 없어서 매우 편리하다.

WOFF 폰트 파일의 경우 반면 woff 파일은 bundle처럼 빌드할 때마다 해시값으로 파일명을 부여하지 않는다:

roboto-regular.woff (항상 고정된 이름)

항상 고정된 이름으로 빌드되기 때문에 개발자가 직접 파일명을 바꾸지 않는 한, 캐시 미스가 날 케이스는 거의 없다. 그럼에도 불구하고 폰트 파일은 용량이 크고 변경 빈도가 낮기 때문에 캐싱 처리로 성능 최적화 효과가 크다.

실제 캐싱 동작 확인

배포 직후 CloudFront 캐싱 동작을 관찰해보니 예상과 다른 부분들이 있었다.

첫 번째 궁금증: 배포 후 즉시 확인 시 캐시 미스 새로 배포된 CSS 파일을 확인하려고 페이지를 리프레시해도 두어 번 정도는 캐시 미스가 발생했다. 처음엔 캐싱이 제대로 안 되는 건 아닌가 의심했지만, 이는 정상적인 동작이다.

새로 배포된 파일이므로 CloudFront 엣지에는 해당 파일의 캐시가 없다. 따라서 오리진 서버에서 파일을 가져와서 엣지에 저장하는 과정이 필요하다. 때로는 여러 엣지 로케이션 간의 동기화나 네트워크 라우팅으로 인해 한 번 더 미스가 발생할 수 있다.

두 번째 궁금증: 이전 번들 파일은 언제 삭제되나 새로운 빌드가 배포되면 이전 해시값을 가진 번들 파일들은 더 이상 참조되지 않는다. 그럼 CloudFront 엣지에 남아있는 이전 파일들은 언제 사라질까?

CachingOptimized 정책에 의하면 24시간이 지나면 자동으로 삭제된다. 이는 AWS가 제공하는 관리형 캐시 정책으로, 정적 자원에 최적화된 TTL을 자동으로 설정해준다.

캐싱 효과 측정

실제로 캐싱이 잘 되고 있는지 확인하는 방법:

1. CloudFront 로그 확인 CloudFront 액세스 로그에서 sc-status 필드를 보면:

  • Hit: 엣지에서 캐시된 파일 제공
  • Miss: 오리진에서 파일을 가져와서 제공
  • RefreshHit: 조건부 요청으로 304 응답

2. 브라우저 개발자 도구 Network 탭에서 응답 헤더를 확인하면:

  • X-Cache: Hit from cloudfront: 캐시에서 제공
  • X-Cache: Miss from cloudfront: 오리진에서 제공

3. CloudWatch 메트릭 CloudFront 메트릭에서 CacheHitRate를 모니터링하면 전체적인 캐시 효율을 확인할 수 있다.

최적화 팁

청크 분할 최적화 Vue.js에서 webpack의 SplitChunksPlugin을 활용해서 vendor 라이브러리와 앱 코드를 분리하면 더 효율적이다:

// webpack.config.js
optimization: {
  splitChunks: {
    cacheGroups: {
      vendor: {
        name: 'vendor',
        chunks: 'all',
        test: /node_modules/
      }
    }
  }
}

이렇게 하면 앱 코드만 변경되어도 vendor 청크는 캐시를 그대로 활용할 수 있다.

프리로딩 전략 중요한 CSS나 폰트 파일은 <link rel="preload">를 사용해서 미리 로드하면, CloudFront 캐시 웜업 효과도 얻을 수 있다.

CloudFront 구축 경험담: 알아두면 유용한 포인트들

CloudFront를 구축하면서 여러 포인트들을 발견했다. 이런 경험을 공유하면 같은 상황에서 더 빠르게 해결할 수 있을 것 같다.

1. ACM 인증서는 반드시 버지니아 북부에서

중요 포인트: CloudFront에서 사용할 SSL 인증서는 반드시 us-east-1 (버지니아 북부) 리전에 있어야 한다. 이건 AWS의 고정된 규칙이다.

상황: 다행히 우리 인프라가 이미 버지니아 북부에도 구축되어 있어서 큰 문제는 없었다.

2. 대체 도메인 이름은 Wildcard가 효율적

상황: 서브도메인이 많아질수록 관리가 복잡해지고, 새로운 서브도메인 추가할 때마다 CloudFront 설정을 수정해야 하는 상황이었다.

해결: Wildcard 도메인 *.example.com을 설정하니 모든 서브도메인 라우팅이 자동으로 처리되었다. 훨씬 깔끔하다.

3. 대체 도메인의 전역 유일성

중요한 특징: 대체 도메인은 전 세계에서 유일해야 한다. 한 번 어떤 계정에서 example.com을 사용하면, 다른 계정에서는 같은 도메인을 사용할 수 없다.

이유: CloudFront는 전 세계 엣지 로케이션에 배포되기 때문에, 같은 도메인이 여러 배포에 존재하면 라우팅이 꼬일 수 있다.

주의사항: 테스트용으로 실제 도메인을 사용했다가 나중에 삭제하고 다른 계정에서 사용하려고 하면 안 된다. 신중하게 설정해야 한다.

4. WAF와 함께 사용할 때 주의점

보안 강화: WAF를 CloudFront에 연결해서 보안을 강화했다.

발생한 문제: WAF를 설정하고 나니 모든 요청이 차단되었다. CloudFront에서 오는 요청인지 구분할 방법이 없었기 때문이다.

해결: Origin(ALB)에서 커스텀 헤더 X-CloudFront-Access를 확인하도록 설정했다. CloudFront에서만 이 헤더를 추가해서 보내니, WAF에서 이 헤더가 있는 요청만 허용하도록 규칙을 만들 수 있었다.

CloudFront → Origin Request에 X-CloudFront-Access: secret-value 추가
ALB/WAF → X-CloudFront-Access 헤더가 있는 요청만 허용

5. Default 동작 설정의 중요성

핵심 설정: Default 동작 설정을 제대로 하는 것이 중요하다.

올바른 설정:

  • Default 동작은 반드시 * 패스 패턴으로 설정
  • 캐싱 정책은 UseOriginCacheControlHeaders로 설정해서 원본 서버의 캐시 헤더를 존중

이렇게 하니 정적 파일은 CloudFront에서 캐싱되고, 동적 콘텐츠는 원본 서버의 캐시 정책을 따르게 되어 완벽하게 동작했다.

결과: 비용과 효율성의 극대화

이런 과정을 거쳐 완성된 시스템의 성과는 놀라웠다:

비용 측면

  • 해외 별도 인프라 구축 비용 80% 절감
  • CloudFront 사용량 기반 과금으로 실제 사용한 만큼만 지불
  • 운영 인력 절약으로 간접 비용 대폭 감소

성능 측면

  • 해외 사용자의 정적 파일 로딩 속도 70% 향상
  • 국내 사용자는 기존과 동일한 성능 유지
  • 글로벌 사용자 경험 통일

운영 효율성

  • 화이트라벨 고객들이 이제 도메인만 알려주면 설정 완료
  • 도메인 설정 시간: 2-3일 → 30분 이내
  • 개발팀 커뮤니케이션 비용 90% 감소

핵심 설정 체크리스트

CloudFront 설정할 때 꼭 확인해야 할 포인트들을 정리해봤다:

인증서

  • [ ] ACM 인증서가 us-east-1 리전에 있는지 확인
  • [ ] 도메인 검증이 완료되었는지 확인

대체 도메인

  • [ ] 서브도메인이 많다면 Wildcard(*.example.com) 사용
  • [ ] 루트 도메인도 함께 사용한다면 별도 추가
  • [ ] 다른 계정에서 사용 중인 도메인은 아닌지 확인

보안 설정

  • [ ] WAF 사용 시 커스텀 헤더(X-CloudFront-Access) 설정
  • [ ] Origin에서 해당 헤더 검증 로직 구현

동작 설정

  • [ ] 정적 파일별 CachingOptimized 정책 설정
  • [ ] Default 동작을 * 패턴으로 설정
  • [ ] Default 캐싱 정책을 UseOriginCacheControlHeaders로 설정

마무리

CloudFront 설정은 겉보기엔 간단해 보이지만, 실제로는 여러 고려할 점들이 있다. 특히 글로벌 서비스의 특성상 한 번 잘못 설정하면 되돌리기 어려운 부분들이 있어서 더욱 신중해야 한다.

이런 경험들을 통해 얻은 가장 큰 교훈은 "작은 것부터 차근차근"이다. 처음부터 복잡한 설정을 시도하지 말고, 기본 동작을 확인한 후 점진적으로 고도화하는 것이 훨씬 안전하고 효율적이다.

혹시 CloudFront 설정하면서 비슷한 문제를 겪고 있다면, 이 경험이 도움이 되었으면 좋겠다.

반응형