CloudFront + S3로 SPA를 제공할 때 사용할 수 있는 실전형 배포 스크립트를 정리한다.
전제
- 클라우드 벤더는 AWS를 사용
- 프런트엔드 빌드 결과물을 S3에 두고 CloudFront를 통해 배포
인프라 구성
S3
- 버킷 버저닝: 비활성화
- 암호화: SSE-S3
- Block Public Access: ON
- 정적 웹사이트 호스팅: 비활성화
CloudFront
- 요금 클래스: 모든 엣지 로케이션 사용
- 지원 HTTP 버전: HTTP/3, 2, 1.1, 1.0
오리진
- 오리진 이름: S3-frontend-app
- 오리진 도메인:
<bucket_name>.s3.ap-northeast-1.amazonaws.com - 오리진 경로:
/current - 오리진 액세스: Origin access control settings
비헤이비어
기본값 (*)
- 오리진: S3-frontend-app
- 뷰어 프로토콜 정책: HTTP to HTTPS
- 캐시 정책: Managed-CacheOptimized
- 뷰어 요청: CloudFront Functions 사용
배포 스크립트
AWS 자격 증명 부분은 실행 환경에 따라 달라지므로 생략한다.
# global varsreadonly S3_BUCKET=""readonly DIST_DIR=""
function main() { # BUILD_ID는 Git 커밋 해시여도 된다 local -r build_id=$(date -Iseconds)
local -r base_uri="s3://$S3_BUCKET" local -r deploy_uri="$base_uri/builds/$build_id" local -r previous_uri="$base_uri/previous" local -r current_uri="$base_uri/current"
# builds 아래에 배포한다
# js,css aws s3 sync "$DIST_DIR" "$deploy_uri" \ --exclude "*" \ --include "*.js" \ --include "*.css" \ --metadata-directive "REPLACE" --cache-control "public,max-age=31536000,immutable"
# js,css,html 이외 aws s3 sync "$DIST_DIR" "$deploy_uri" \ --exclude "*.js" \ --exclude "*.css" \ --exclude "*.html" \ --metadata-directive "REPLACE" \ --cache-control "public,max-age=1,stale-while-revalidate=604800"
# html aws s3 sync "$DIST_DIR" "$deploy_uri" \ --exclude "*" \ --include "*.html" \ --metadata-directive "REPLACE" \ --cache-control "no-cache"
# current 경로에서 서비스 중인 프런트엔드 자산을 previous로 백업 aws s3 sync "$current_uri" "$previous_uri" --delete --exact-timestamp
# 이번 빌드를 current로 복사해 사용자에게 공개 aws s3 sync "$deploy_uri" "$current_uri" --delete --exact-timestamp}왜 이런 순서로 Cache-Control을 설정하는가
원래는 마지막 단계인 aws s3 sync "$deploy_uri" "$current_uri"에서 cache-control을 설정하고 싶지만, S3에서 S3로 sync할 때 --metadata-directive "REPLACE"를 사용하면 AWS 동작상 Content-Type 추론이 사라져 모든 파일이 binary/octet-stream으로 처리된다.
반면 로컬에서 S3로 sync할 때는 Content-Type 추론 결과가 유지되므로, 실제 운영에서는 이런 식의 순서를 택하고 있다.
롤백 스크립트
문제가 생기면 previous에서 current로 되돌린다.
# global varsreadonly S3_BUCKET=""
function revert() { local -r base_uri="s3://$S3_BUCKET" local -r previous_uri="$base_uri/previous" local -r current_uri="$base_uri/current"
# copy previous to current aws s3 sync "$previous_uri" "$current_uri" --delete --exact-timestamp}정리
CloudFront + S3로 SPA를 제공할 때 적절한 cache-control 설정과 블루그린 스타일의 배포 구조를 함께 쓰면 더 안전하고 효율적인 배포가 가능하다.
builds 아래에 이력을 남기고 current, previous로 현재 버전과 직전 버전을 관리하면, 문제 발생 시 빠르게 롤백할 수 있다.
hsb.horse