기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.
CloudFront를 사용하여 비디오 스트리밍
미디어 워크플로는 일반적으로 비디오 온디맨드(VOD) 파일, HTTP 라이브 스트리밍(HLS) 패키지, 이미지 및 그래픽과 같은 완성된 콘텐츠를 편집기, 생산자 및 자동화 시스템이 NFS 또는 SMB를 사용하여에 쓰는 FSx for ONTAP 볼륨에 저장합니다.
FSx for ONTAP 볼륨에 연결된 Amazon S3 액세스 포인트를 사용하여 CloudFront는 볼륨에서 직접 콘텐츠를 제공할 수 있습니다. 편집기와 프로덕션 시스템은 항상 있는 방식으로 NFS 또는 SMB를 통해 볼륨에 게시하고, CloudFront는 액세스 포인트를 통해 콘텐츠를 가져오며, 최종 사용자는 가장 가까운 CloudFront 엣지 로케이션에서 콘텐츠를 수신합니다.
이 자습서에서는 샘플 비디오를 HLS 적응 비트레이트 패키지로 인코딩하고, 출력을 FSx for ONTAP 볼륨에 연결된 액세스 포인트에 업로드하고, 오리진 액세스 제어로 CloudFront 배포를 구성하여 최종 사용자가 CloudFront를 우회하여 볼륨에 직접 도달할 수 없도록 하고, 스트림이 처음부터 끝까지 재생되는지 확인합니다.
참고
이 자습서를 완료하는 데 약 40~60분이 걸립니다. AWS 서비스 사용한 에는 생성한 리소스에 대한 요금이 발생합니다. 정리 섹션을 포함하여 모든 단계를 즉시 완료하면 미국 동부(버지니아 북부)에서 예상 비용이 1 USD 미만입니다 AWS 리전. 이 견적에는 FSx for ONTAP 볼륨 자체에 대한 지속적인 요금은 포함되지 않습니다.
패턴 작동 방식
요청 흐름은 다음과 같습니다.
최종 사용자의 플레이어(브라우저, 모바일 앱, 스마트 TV)가 CloudFront 도메인에서 HLS 마스터 재생 목록을 요청합니다.
CloudFront는 엣지 캐시를 확인합니다. CloudFront는 오리진 액세스 제어(OAC)와 함께 서명 버전 4(SigV4)를 사용하여 요청에 서명하고 액세스 포인트의 Amazon S3 엔드포인트로 전달합니다.
액세스 포인트는 CloudFront 서비스 보안 주체가 배포로 범위가 지정되도록 허용하는 액세스 정책에 대해 요청을 승인하고 FSx for ONTAP 볼륨에서 요청된 객체를 반환합니다.
CloudFront는 엣지에서 응답을 캐싱하여 최종 사용자에게 반환합니다.
HLS 패키지는 서로 다른 캐시 정책의 이점을 활용하는 두 가지 유형의 파일을 혼합합니다.
재생 목록(
.m3u8)은 스트림을 구성하는 세그먼트를 설명합니다. 업데이트된 재생 목록을 빠르게 게시할 수 있도록 짧은Cache-ControlTTL을 사용합니다.세그먼트(
.ts)에는 인코딩된 비디오와 오디오가 포함됩니다. 일단 작성되면 세그먼트의 콘텐츠는 변경되지 않으므로 변경 불가능한 긴Cache-ControlTTL을 사용합니다.
사전 조건
Amazon S3 액세스 포인트가 연결된 FSx for ONTAP 볼륨입니다. CloudFront가 액세스할 수 있도록 액세스 포인트에 인터넷 네트워크 오리진이 있어야 합니다. 지침은 액세스 포인트 생성 섹션을 참조하세요.
AWS CLI 버전 2는 CloudFront 배포, 오리진 액세스 제어 및 액세스 포인트 정책을 생성할 수 있는 자격 증명으로 설치 및 구성됩니다.
샘플 비디오를 HLS로 인코딩하기 위해 로컬에 설치된 FFmpeg
입니다. 소스 비디오 파일입니다. 이 자습서에서는 Creative Commons 아래에 릴리스된 52초 1080p 클립인 Blender Foundation의 Sintel 트레일러
를 사용합니다.
1단계: 소스 비디오를 HLS 패키지로 인코딩
FFmpeg를 사용하여 사실적인 OTT(over-the-top) 비트레이트로 360p, 720p 및 1080p에서 3가지 변형 HLS 패키지를 생성합니다. 결과 패키지에는 변형별 재생 목록을 참조하는 마스터 재생 목록이 포함되며, 각 재생 목록은 4초 전송 스트림 세그먼트를 나열합니다.
-
소스 비디오를 다운로드합니다.
$mkdir -p ~/media && cd ~/media curl -sSL -o sintel-1080p.mp4 \ https://download.blender.org/durian/trailer/sintel_trailer-1080p.mp4 -
세 가지 적응 비트레이트 변형을 사용하여 비디오를 HLS로 인코딩합니다.
$mkdir hls && cd hls ffmpeg -i ../sintel-1080p.mp4 \ -filter_complex "[0:v]split=3[v1][v2][v3]; \ [v1]scale=w=640:h=360[v1out]; \ [v2]scale=w=1280:h=720[v2out]; \ [v3]scale=w=1920:h=1080[v3out]" \ -map "[v1out]" -c:v:0 libx264 -b:v:0 800k -maxrate:v:0 856k -bufsize:v:0 1200k \ -map "[v2out]" -c:v:1 libx264 -b:v:1 3000k -maxrate:v:1 3200k -bufsize:v:1 4500k \ -map "[v3out]" -c:v:2 libx264 -b:v:2 5500k -maxrate:v:2 5900k -bufsize:v:2 8250k \ -preset veryfast -g 48 -keyint_min 48 -sc_threshold 0 \ -map a:0 -map a:0 -map a:0 -c:a aac -b:a:0 96k -b:a:1 128k -b:a:2 128k \ -f hls -hls_time 4 -hls_playlist_type vod -hls_flags independent_segments \ -hls_segment_filename "stream_%v/seg_%03d.ts" \ -master_pl_name master.m3u8 \ -var_stream_map "v:0,a:0,name:360p v:1,a:1,name:720p v:2,a:2,name:1080p" \ "stream_%v/playlist.m3u8"명령은 마스터 재생 목록 1개, 변형 재생 목록 3개, 각 변형에 대한 전송 스트림 세그먼트가 있는 디렉터리 트리를 생성합니다.
hls/ ├── master.m3u8 ├── stream_360p/ │ ├── playlist.m3u8 │ ├── seg_000.ts │ └── ... ├── stream_720p/ │ ├── playlist.m3u8 │ ├── seg_000.ts │ └── ... └── stream_1080p/ ├── playlist.m3u8 ├── seg_000.ts └── ...
2단계: 액세스 포인트에 HLS 패키지 업로드
패키지를 두 번 업로드합니다. 즉, TTL이 짧은 재생 목록의 경우 한 번, 변경 불가능한 TTL이 길고 변경 불가능한 세그먼트의 경우 한 번 업로드합니다. 올바른 설정은 중요합니다. 대부분의 플레이어Content-Type는 .m3u8 및 application/vnd.apple.mpegurl에 대해 video/mp2t가 필요합니다.ts.
access-point-alias를 액세스 포인트 별칭으로 바꿉니다.
$# Playlists: short TTL, m3u8 content type aws s3 cp ~/media/hls/ "s3://access-point-alias/content/sintel/" \ --recursive --exclude "*" --include "*.m3u8" \ --content-type "application/vnd.apple.mpegurl" \ --cache-control "max-age=60" # Segments: long immutable TTL, ts content type aws s3 cp ~/media/hls/ "s3://access-point-alias/content/sintel/" \ --recursive --exclude "*" --include "*.ts" \ --content-type "video/mp2t" \ --cache-control "max-age=31536000,immutable"
두 파일이 모두 예상 콘텐츠 유형 및 캐시 헤더와 함께 업로드되었는지 확인합니다.
$aws s3api head-object --bucketaccess-point-alias\ --key content/sintel/master.m3u8 \ --query '{ContentType:ContentType,CacheControl:CacheControl}'
3단계: 오리진 액세스 제어 생성
오리진 액세스 제어(OAC)를 사용하면 CloudFront만 객체를 가져올 수 있도록 CloudFront가 액세스 포인트에 대한 요청에 서명할 수 있습니다. OAC가 없으면 최종 사용자는 액세스 포인트 엔드포인트에서 직접 객체를 요청하여 CloudFront를 우회할 수 있습니다.
$aws cloudfront create-origin-access-control \ --origin-access-control-config \ 'Name=fsxn-media-oac,SigningProtocol=sigv4,SigningBehavior=always,OriginAccessControlOriginType=s3'
응답의 Id에 주의하세요. 다음 단계에서 해당 항목을 사용합니다.
4단계: CloudFront 배포 생성
액세스 포인트 별칭을 오리진 도메인으로 사용하여 CloudFront 배포를 생성합니다. 2단계에서 설정한 Cache-Control 헤더를 준수하는 CachingOptimized 관리형 캐시 정책을 사용합니다.
-
다음 구성을 라는 파일에 저장하여 자리 표시자를
dist.json바꿉니다.{ "CallerReference": "fsxn-media-1", "Comment": "FSx for ONTAP media delivery", "Enabled": true, "DefaultRootObject": "", "Origins": { "Quantity": 1, "Items": [{ "Id": "fsxn-ap", "DomainName": "access-point-alias.s3.region.amazonaws.com", "S3OriginConfig": {"OriginAccessIdentity": ""}, "OriginAccessControlId": "oac-id", "ConnectionAttempts": 3, "ConnectionTimeout": 10 }] }, "DefaultCacheBehavior": { "TargetOriginId": "fsxn-ap", "ViewerProtocolPolicy": "redirect-to-https", "AllowedMethods": { "Quantity": 2, "Items": ["GET", "HEAD"], "CachedMethods": {"Quantity": 2, "Items": ["GET", "HEAD"]} }, "Compress": true, "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6" }, "PriceClass": "PriceClass_100", "ViewerCertificate": {"CloudFrontDefaultCertificate": true} }참고
PriceClass_100는 북미 및 유럽에서만 CloudFront 엣지 로케이션을 사용하므로이 자습서에서는 비용을 낮게 유지합니다. 글로벌 엣지 적용 범위의 경우 값을 로 변경합니다PriceClass_All. 자세한 내용은 CloudFront 배포의 가격 등급 선택을 참조하세요. -
배포를 생성합니다.
$aws cloudfront create-distribution --distribution-config file://dist.json \ --query 'Distribution.{Id:Id,DomainName:DomainName,ARN:ARN}'응답에 배포 ID, ARN 및 도메인 이름을 기록해 둡니다. 배포하는 데 약 5분이 걸립니다. 배포하는 동안 5단계로 계속 진행할 수 있습니다.
5단계: CloudFront를 허용하는 액세스 포인트 정책 연결
액세스 포인트 정책은 CloudFront 서비스 보안 주체에게 AWS:SourceArn 조건을 사용하여 특정 배포로 범위가 지정된 객체를 읽을 수 있는 권한을 부여합니다.
-
다음 정책을 라는 파일에 저장하여 자리 표시자를
ap-policy.json바꿉니다.{ "Version": "2012-10-17", "Statement": [{ "Sid": "AllowCloudFrontServicePrincipal", "Effect": "Allow", "Principal": {"Service": "cloudfront.amazonaws.com"}, "Action": "s3:GetObject", "Resource": "arn:aws:s3:region:account-id:accesspoint/access-point-name/object/*", "Condition": { "StringEquals": { "AWS:SourceArn": "arn:aws:cloudfront::account-id:distribution/distribution-id" } } }] } -
정책을 액세스 포인트에 연결합니다.
$aws s3control put-access-point-policy \ --account-idaccount-id\ --nameaccess-point-name\ --policy file://ap-policy.json
6단계: 재생 확인
배포가 Deployed 상태에 도달할 때까지 기다립니다.
$aws cloudfront get-distribution --iddistribution-id\ --query 'Distribution.Status'
CloudFront를 통해 마스터 재생 목록을 가져옵니다.
$curl -sS "https://distribution-domain/content/sintel/master.m3u8"
응답에는 세 가지 변형이 나열되어야 합니다.
#EXTM3U #EXT-X-VERSION:6 #EXT-X-STREAM-INF:BANDWIDTH=1031744,RESOLUTION=640x360,CODECS="avc1.64001e,mp4a.40.2" stream_360p/playlist.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=3497301,RESOLUTION=1280x720,CODECS="avc1.64001f,mp4a.40.2" stream_720p/playlist.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=6311285,RESOLUTION=1920x1080,CODECS="avc1.640028,mp4a.40.2" stream_1080p/playlist.m3u8
응답 헤더에서 올바른 콘텐츠 유형, 캐시 제어 및 캐시 상태를 확인합니다.
$curl -sSI "https://distribution-domain/content/sintel/stream_1080p/seg_000.ts"
응답이 성공하면 content-type: video/mp2t, cache-control: max-age=31536000,immutable및 응답이 엣지에서 왔는지 오리진에서 왔는지 여부를 나타내는 x-cache 헤더가 표시됩니다.
마지막으로 스트림을 FFmpeg로 끝까지 재생하여 모든 세그먼트가 올바르게 가져오고 디코딩되는지 확인합니다.
$ffprobe -v error \ -show_entries stream=codec_name,width,height \ -show_entries format=duration \ "https://distribution-domain/content/sintel/master.m3u8"
Safari 또는 VLC에서 마스터 재생 목록 URL을 열거나 hls.js와 같은 JavaScript 플레이어를 사용하여 웹 페이지에 포함할 수도 있습니다. https://github.com/video-dev/hls.js
패턴 확장
HTTPS와 함께 사용자 지정 도메인을 사용합니다. 도메인에 대한 ACM 인증서를 요청하고 배포에 연결한 다음 CloudFront 도메인을 가리키는 CNAME 레코드를 추가합니다. 지침은 CloudFront에서 사용자 지정 URLs.
서명된 URLs 또는 서명된 쿠키로 프리미엄 콘텐츠를 보호합니다. 권한이 필요한 콘텐츠(구독 서비스, 조기 액세스 미리 보기, 지오펜스 콘텐츠)의 경우 CloudFront 서명된 URLs 또는 서명된 쿠키를 사용합니다. 서명된 URLs.
새 콘텐츠를 게시할 때 캐시를 무효화합니다. 재생 목록을 교체하거나 새 HLS 패키지를 업로드할 때
aws cloudfront create-invalidation를 사용하여 CloudFront 엣지에서 이전 버전을 제거합니다. TTLs이 긴 변경 불가능한 세그먼트의 경우 세그먼트 파일 이름은 패키지별로 고유하기 때문에 일반적으로 무효화가 필요하지 않습니다.브라우저 기반 플레이어에 대해 CORS를 활성화합니다. 다른 도메인의 브라우저 기반 HLS 플레이어가 스트림을 로드하는 경우 CloudFront 응답
Access-Control-Allow-Origin헤더 정책을 사용하여 응답에 헤더를 추가합니다.최종 사용자 요청을 로깅합니다. CloudFront 표준 로깅 또는 실시간 로그를 활성화하여 분석, 결제 또는 남용 탐지에 대한 최종 사용자 요청을 캡처합니다.
문제 해결
- 403 CloudFront에서 금지됨
액세스 포인트 정책이 누락되었거나, CloudFront 서비스 보안 주체가 포함되어 있지 않거나,
AWS:SourceArn조건이 잘못된 배포 ARN을 참조합니다. 를 사용하여 정책을aws s3control get-access-point-policy확인하고 배포 ARN이aws cloudfront create-distribution응답의 정책과 일치하는지 확인합니다.- 플레이어가 마스터 재생 목록을 로드하지만 재생하지 못함
세그먼트 파일에
Content-Type: video/mp2t및 재생 목록에이 있는지 확인합니다Content-Type: application/vnd.apple.mpegurl. 일부 플레이어는 일반 콘텐츠 유형의 세그먼트를 거부합니다. 올바른--content-type플래그로 다시 업로드합니다.- 새 재생 목록은 최종 사용자에게 도달하는 데 시간이 걸립니다.
CloudFront는
Cache-Control헤더가 설정한 TTL의 재생 목록을 캐시합니다. 더 짧은 TTL이 필요한 경우 더 작은max-age값으로 재생 목록을 다시 업로드하거나 무효화를 생성합니다. 세그먼트의 내용은 변경되지 않으므로 세그먼트에이 문제가 없습니다.x-cache: Miss from cloudfront모든 요청 시리전의 최종 사용자가 파일을 처음 요청할 때는 정상입니다. CloudFront는 누락 시 오리진에서 가져오고 TTL에 대한 응답을 캐싱합니다. 해당 엣지 로케이션에서 동일한 파일에 대한 후속 요청은를 반환합니다
Hit from cloudfront.- 액세스 포인트에 대한 직접 액세스가 거부됨
이는 예상된 동작입니다. OAC에는 CloudFront의 SigV4-signed 요청이 필요하며 액세스 포인트 정책은 CloudFront 서비스 보안 주체에 대한 액세스를 제한합니다. 최종 사용자는 배포 도메인을 통해서만 콘텐츠에 도달할 수 있습니다.
정리
배포를 비활성화하고 삭제한 다음 나머지 리소스를 삭제합니다. 배포를 삭제하려면 먼저 비활성화해야 합니다.이 작업은 몇 분 정도 걸립니다.
를 비활성화하려면의 두 가지 값--if-match, get-distribution-config즉 ETag의와의 내부 DistributionConfig 객체가 필요합니다--distribution-config(전체 응답에는 수락하지 update-distribution 않는 ETag도 포함됨).
$# Capture the current ETag and the DistributionConfig body GET_ETAG=$(aws cloudfront get-distribution-config --iddistribution-id\ --query 'ETag' --output text) aws cloudfront get-distribution-config --iddistribution-id\ --query 'DistributionConfig' --output json \ | jq '.Enabled = false' > dist-updated.json # Disable the distribution. The response returns a new ETag. UPDATE_ETAG=$(aws cloudfront update-distribution --iddistribution-id\ --if-match "$GET_ETAG" --distribution-config file://dist-updated.json \ --query 'ETag' --output text) # Wait for Status to reach Deployed before deleting. aws cloudfront get-distribution --iddistribution-id\ --query 'Distribution.Status' # Delete the distribution using the ETag from the update call. aws cloudfront delete-distribution --iddistribution-id\ --if-match "$UPDATE_ETAG" # Fetch the OAC ETag, then delete the OAC. OAC_ETAG=$(aws cloudfront get-origin-access-control --idoac-id\ --query 'ETag' --output text) aws cloudfront delete-origin-access-control --idoac-id\ --if-match "$OAC_ETAG" aws s3control delete-access-point-policy \ --account-idaccount-id--nameaccess-point-nameaws s3 rm "s3://access-point-alias/content/sintel/" --recursive