Amazon Web Services 한국 블로그
실전 Amazon S3와 CloudFront로 정적 파일 배포하기
많은 사용자들이 이용하는 웹사이트 및 모바일 앱에는 이미지, 동영상 또는 음악 같은 파일이나 .css 또는 .js 같은 정적 파일을 가지고 있습니다. 콘텐츠 배포 네트워크(CDN) 서비스가 등장하기 전에는 특정 지역에 서버를 일일이 두고 서비스를 해야 했습니다.
이 글에서는 Amazon Simple Storage Service(S3)와 Amazon CloudFront를 사용해 정적 콘텐츠를 대규모로 저장하고, 보호하고, 전송할 수 있는 방법에 대해 살펴보겠습니다. 그 밖에 클릭 몇 번만으로 시작하는 데 도움이 되도록 서비스를 빠르게 프로비저닝할 수 있는 CloudFormation 템플릿도 포함되어 있습니다. (설정 방법에 대해서는 나중에 알아보겠습니다)
먼저 콘텐츠를 보안성도 높고 확장 가능한 방법으로 저장해야 합니다. 인터넷으로 접근 가능한 정적 콘텐츠에 간단하고 유연하게 접근할 수 있는 방법은 Amazon S3 서비스를 이용하는 것입니다. 파일을 “버킷(Bucket)”에 무제한으로 저장하고 가져올 수 있도록 설계되었습니다. 또한, 손쉽게 확장이 가능한 고가용성 데이터 스토리지를 저렴한 비용으로 제공합니다.
콘텐츠를 클라우드 환경의 S3 버킷에 저장하면 많은 일들이 더욱 쉬워집니다. 첫째, S3 버킷이 자동으로 확장 및 축소되기 때문에 스토리지 공간을 계획하여 특정 크기를 할당할 필요가 없습니다. 둘째, S3는 서버리스(Serverless) 서비스이기 때문에 파일이 저장되는 서버를 관리하거나 패치할 필요가 없습니다. 단지 콘텐츠를 저장하고 가져오기만 하면 됩니다. 마지막으로, 애플리케이션(동적 애플리케이션 등)에 서버가 필요하더라도 정적 콘텐츠에 대한 요청을 처리할 필요가 없기 때문에 서버 크기를 줄일 수 있습니다.
S3를 사용해 정적 콘텐츠를 저장하면 다양한 이점이 있습니다. 하지만 비용을 효과적으로 관리하는 동시에 애플리케이션의 성능과 보안까지 최적화하려면 Amazon CloudFront를 설정해 S3 버킷과 함께 사용하면서 콘텐츠를 제공하고 보호하는 것이 좋습니다. CloudFront는 전 세계의 정적/동적 웹 콘텐츠, 비디오 스트림 및 API를 안전하게 대규모로 전송할 수 있는 콘텐츠 전송 네트워크(CDN) 서비스입니다. CloudFront에서 데이터를 전송하면 설계상 S3에서 직접 사용자에게 전송하는 것보다 더욱 비용 효율적입니다.
CloudFront는 엣지 로케이션이라고 하는 데이터 센터의 전 세계 네트워크를 통해 콘텐츠 서비스를 제공합니다. 엣지 서버를 사용해 콘텐츠를 캐싱하고 서비스를 제공하면 최종 사용자가 위치한 곳에 더욱 가깝게 콘텐츠를 전송할 수 있기 때문에 성능이 향상됩니다. CloudFront는 아래 지도에서도 볼 수 있듯이 전 세계 여러 곳에 엣지 서버가 있습니다.
사용자가 CloudFront에서 전송하는 콘텐츠를 요청할 경우 요청이 가까운 엣지 로케이션으로 라우팅됩니다. 이때 CloudFront에 요청된 파일의 캐시 사본이 있으면 CloudFront가 빠르게(낮은 지연 시간) 응답하여 해당 사본을 사용자에게 전송합니다. 요청한 파일이 아직 캐싱되어 있지 않으면 CloudFront가 예를 들어 콘텐츠가 저장된 S3 버킷 같은 오리진 서버에서 파일을 가져옵니다. 이후부터는 동일한 콘텐츠를 로컬에서 요청하더라도 가까운 곳에 캐싱되어 있기 때문에 서비스를 즉시 제공할 수 있습니다.
CloudFront가 콘텐츠를 엣지 로케이션에 캐싱하기 때문에 S3 버킷에 대한 부하를 줄일 뿐만 아니라 콘텐츠를 요청하는 사용자에게도 더욱 빠르게 응답할 수 있습니다. 또한 CloudFront를 사용해 콘텐츠 데이터를 전송하면 S3에서 직접 파일을 제공하는 것보다 더욱 비용 효율적이며, S3에서 CloudFront로 데이터를 전송하는 수수료도 없습니다. 요청 수수료에 더해 CloudFront에서 인터넷으로 전송되는 콘텐츠에 대해서만 요금을 지불하면 됩니다(전체 요금 정보 참조).
예를 들어 동적 콘텐츠를 제공하는 이유로 콘텐츠를 캐싱하고 싶지 않더라도 CloudFront는 엣지 로케이션을 통해 사용자와 더욱 가깝게 연결을 구성하여 유지하기 때문에 콘텐츠 전송이 더욱 효과적입니다. 그 밖에도 별도의 인터넷 백본인 AWS 글로벌 프라이빗 네트워크를 이용해 월드와이드 네트워크 문제를 회피함으로써 정적/동적 콘텐츠의 전송 성능을 높입니다.
그림으로 설명하면 이러한 원리를 더욱 쉽게 이해할 수 있습니다. 아래 그림의 시나리오를 봐주세요. 유럽의 한 리전에 위치한 S3 버킷에 콘텐츠가 저장되어 있고, 전 세계 사용자가 이 콘텐츠에 액세스하고 있습니다.
화살표에서 알 수 있듯이 사용자가 콘텐츠를 요청할 때마다 요청은 퍼블릭 인터넷을 통해 원본 위치인 유럽의 S3 버킷으로 전송됩니다. 이때 사용자의 위치에 따라 전송 시간은 길어질 수 있습니다. 이렇게 시간이 지연되면 일부 사용자 요청이 반송되어 페이지에서 오류를 반환할 가능성도 있습니다.
이번에는 S3 버킷과 함께 CloudFront를 설정했다고 가정하겠습니다. 아래 그림에서는 콘텐츠 사용을 위해 전 세계를 가로질러 전송되는 요청을 볼 수 없습니다. 대신에 요청이 “지연 시간을 최소화하는”, 즉 전송 속도와 관련하여 가장 가까운 엣지 로케이션으로 라우팅됩니다. 그러면 초록색 화살표가 가리키듯이 CloudFront가 가까운 거리에서 요청한 사용자에게 캐싱된 콘텐츠를 직접 빠르게 제공합니다.
이때 콘텐츠가 엣지 서버에 아직 캐싱되어 있지 않으면 CloudFront가 S3 버킷 오리진에서 해당 콘텐츠를 가져옵니다. 그 밖에도 콘텐츠가 퍼블릭 인터넷이 아닌 AWS 프라이빗 네트워크를 통해 전송되는 동시에 CloudFront가 TCP 핸드셰이크를 최적화하기 때문에 요청 및 콘텐츠 반환 속도가 퍼블릭 인터넷을 통해 액세스하는 것보다 훨씬 빠릅니다.
콘텐츠 보안 유지
인터넷을 통해 콘텐츠를 배포하는 기업들은 종종 유료 고객 등 선택된 사용자만 요청할 수 있도록 문서, 비즈니스 데이터, 미디어 스트림 또는 기타 콘텐츠에 대한 액세스를 제한하려고 합니다. CloudFront를 사용하면 지리적 제한, 서명된 URL, 서명된 쿠키 등 액세스 제한을 추가로 설정하여 기준이 서로 다른 콘텐츠에 대한 액세스 제한을 강화할 수 있습니다.
CloudFront의 또 다른 보안 기능은 Origin Access Identity(OAI)입니다. 이 기능은 S3 버킷 및 콘텐츠에 대한 액세스를 CloudFront와 CloudFront가 실행하는 작업으로 제한합니다. 이번 블로그 포스트에 포함된 CloudFormation 템플릿에는 콘텐츠를 보호하고 제한할 수 있는 OAI가 있습니다.
그 밖에 CloudFront에는 악성 공격을 차단할 수 있는 기능도 있습니다. 이러한 보호 기능을 제공하기 위해 CloudFront는 잘 알려진 웹 공격에서 웹 애플리케이션을 보호하는 웹 애플리케이션 방화벽인 AWS WAF와, 그리고 AWS 기반 웹 애플리케이션에 대한 관리형 DDoS 보호 서비스인 AWS Shield와 통합됩니다. AWS WAF에서는 콘텐츠 요청 시 IP 주소나 쿼리 문자열 값 등 지정하는 조건에 따라 콘텐츠에 대한 액세스를 제어할 수 있습니다.
이때 조건이 충족되면 CloudFront가 요청된 콘텐츠와 함께 응답하고, 그렇지 않으면 HTTP 403 상태 코드(금지됨)로 응답합니다. 모든 CloudFront 고객은 추가 비용 없이 자동으로 AWS Shield Standard의 보호를 받을 수 있습니다. 하지만 DDoS 공격을 더욱 심층적으로 이해하고 효과적으로 완화하는 동시에 비용을 보호하려는 고객이라면 AWS Shield Advanced를 사용할 수 있습니다.
정적 파일 CloudFormation으로 배포하기
AWS는 Amazon S3와 CloudFront를 최대한 일괄적으로 설정할 수 있도록 시작할 때 사용할 CloudFormation 템플릿을 개발하였습니다. 이 템플릿은 S3 버킷을 먼저 생성한 다음 Origin Access Identity와 함께 CloudFront 배포를 추가합니다.
다음은 사용자의 환경에 설정을 복제할 때 따라야 할 단계입니다.
1) 콘솔에 로그인한 다음 아래 있는 Launch Stack 버튼을 클릭하여 AWS 계정에서 CloudFormation 스택을 시작합니다. 이때 스택은 버지니아 북부(us-east-1) 리전에서 시작됩니다.
2) 마법사를 따라 진행한 후 마지막 단계에서 Create 버튼을 선택합니다. CloudFormation 스택 생성을 마칠 때까지는 일반적으로 약 15분 정도 걸립니다. 따라서 실행 도중에 잠시 휴식한 후 다시 돌아와서 계속 진행해도 됩니다.
3) CloudFormation 상태가 CREATE_COMPLETE로 바뀌면 스택과 Outputs 탭을 차례대로 선택합니다. 여기에 나열되는 S3 버킷 이름(S3BucketName)과 CloudFront 도메인 이름(CfDistributionDomainName)을 기록합니다. 이 두 값은 파일에 대한 액세스를 테스트할 때 사용하게 됩니다.
4) S3 콘솔을 열고 이미지 파일을 CloudFormation에서 생성한 S3 버킷에 업로드합니다. 이번 예에서는 이름이 image.jpg인 파일을 업로드하였습니다.
5) 파일 업로드를 마치면 파일에 액세스할 URL을 선택합니다. CloudFormation은 OAI 기능을 설정하기 때문에 버킷에 업로드되는 파일은 S3에서 직접 공개적으로 액세스할 수 없습니다. 따라서 아래 스크린샷과 비슷한 메시지가 표시됩니다.
6) 대신에 CloudFront 배포 도메인 이름으로 파일에 액세스할 URL을 입력합니다. 3단계에서 복사한 CloudFront 배포 값으로 6단계에서 S3 버킷에 업로드한 파일 이름을 추가합니다. 이번 예에서는 제가 Java라는 이름의 강아지 사진을 업로드한 것을 알 수 있습니다. CloudFront에는 OAI 액세스가 S3 버킷에 구성되어 있으므로 CloudFront URL을 사용하면 이미지에 액세스할 수 있습니다.
콘텐츠 배포 성능 추적
앞에서 CloudFormation 템플릿을 사용해 S3 버킷을 생성한 후 CloudFront를 추가하여 S3 콘텐츠에 액세스하였습니다. 하지만 CloudFront를 별도로 추가할 정도로 가치가 있을까요? 전 세계 여러 위치에서 이미지를 볼 때 성능이 실제로 향상되었는지 살펴보겠습니다. 이를 확인하기 위해 지리적으로 다른 위치에서 사이트 및 콘텐츠 로드 시간을 측정하는 온라인 플랫폼을 사용하겠습니다.
저의 S3 버킷 오리진은 버지니아 북부 리전에 위치하고 있습니다. CloudFront가 있을 때와 없을 때 파일 전송 결과를 비교하기 위해 동일한 리전에서 동일한 이미지가 추가된 S3 버킷을 생성하였지만 CloudFront는 추가하지 않았습니다. 아래 차트에도 표시되어 있지만 로드 시간을 테스트한 위치는 스웨덴(스톡홀롬), 미국(뉴욕) 및 호주(멜버른)입니다.
각 위치마다 4번씩 테스트를 진행하였습니다. 일반적으로 CloudFront가 있을 때는 첫 번째 GET 요청이 CloudFront가 없을 때 동일한 요청에 비해 약간 빠릅니다. 하지만 이후부터는 각 GET 요청의 속도가 현저히 빨라집니다. 이렇게 차이가 나는 이유는 캐싱에서 찾을 수 있습니다. 저의 S3 버킷에서 전송되는 파일이 첫 번째 GET 요청 이후 캐싱되어 이미 테스트를 실시하는 곳과 가장 가까운 엣지 로케이션에 저장되었기 때문입니다. 경우에 따라 파일 반환 속도가 100배까지 빨라지기도 합니다!
간단하지 않습니까? 이제 S3와 함께 CloudFront를 간단하게 설정하는 것만으로 다음과 같이 두 가지 커다란 이점을 얻을 수 있다는 사실을 잊지 않으시기 바랍니다. 첫째, 콘텐츠를 더욱 빠르게 사용자에게 전송하여 애플리케이션 성능을 높일 수 있습니다. 둘째, CloudFront의 보안 기능으로 애플리케이션의 보안을 강화할 수 있습니다. 아! 또 한 가지가 있군요. CloudFront에서 인터넷으로 데이터를 전송하는 요금이 간혹 S3에서 인터넷으로 전송하는 요금보다 저렴하여 AWS 청구 비용을 아낄 수 있다는 점 역시 빼놓을 수 없습니다.
이 글은 AWS Networking & Content Delivery 블로그에 실린 Amazon S3 + Amazon CloudFront: A Match Made in the Cloud의 한국어 번역입니다.