ã¯ããã«
ãšããäºæ 㧠MediaPackage ã®ãšã³ããã€ã³ãçšã® CloudFront ãã£ã¹ããªãã¥ãŒã·ã§ã³ã AWS SDK ã§äœæããæ©äŒããããŸããããã®éåŸãç¥èŠããœãŒã¹ã³ãŒãã亀ããªããåå¿é²ãšããŠèšäºã«æ®ããŠãããŸãã
æ¬èšäºå 容ã§çŽ¹ä»ããŠãããœãŒã¹ã³ãŒã㯠Gist ã«ãåãå 容ã§ã¢ããããŠãããŸãã
ã¡ãªã¿ã« MediaLive + MediaPackage + CloudFront ã®æ§æã§ã€ã³ãã©æ§ç¯ãããå Žåã¯ãCloudFormation ã MediaPackage ã«ã察å¿ããã®ã§ CloudFormation ã®å©çšãæšå¥šããŸãã
æ¬èšäºå 容ã¯ãããŸã§ãäœããã®äºæ ã§ãåŸãã CloudFront ãã£ã¹ããªãã¥ãŒã·ã§ã³ã MediaPackage ãšã³ããã€ã³ãã«çŽã¥ãããã±ãŒã¹çã§åèã«ãªããšæãããŸãã
å®è£ å 容
äœæãããœãŒã¹ã³ãŒãã®å
容ã¯äžèšã«ãªããŸãã
æäžéšã® createDistributionForMediaPackage
ãæ¬èšäºã¿ã€ãã«ã«è©²åœããé¢æ°ã§ãã
import { CloudFront } from "aws-sdk";
import * as url from "url";
import {
CreateDistributionWithTagsResult,
GetDistributionResult,
UpdateDistributionResult
} from "aws-sdk/clients/cloudfront";
export class CloudFrontClientForMediaPackage {
private cloudFront: CloudFront;
constructor() {
this.cloudFront = new CloudFront({
region: "ap-northeast-1",
apiVersion: '2020-05-31',
});
}
/**
* CloudFront ãã£ã¹ããªãã¥ãŒã·ã§ã³ã®æ
å ±ãååŸããããã«å©çšãã
* @param id CloudFront ãã£ã¹ããªãã¥ãŒã·ã§ã³ã® ID
* @return ãã£ã¹ããªãã¥ãŒã·ã§ã³ã®æ
å ±ãååŸãã
*/
async getDistribution(id: string): Promise<GetDistributionResult> {
const distribution = await this.cloudFront.getDistribution({
Id: id
}).promise()
return distribution;
}
/**
* CloudFront ãã£ã¹ããªãã¥ãŒã·ã§ã³ã®èšå®å
容ãååŸããããã«å©çšãã
* @param id CloudFront ãã£ã¹ããªãã¥ãŒã·ã§ã³ã® ID
* @return ãã£ã¹ããªãã¥ãŒã·ã§ã³ã®èšå®å
容ãååŸãã
*/
async getDistributionConfig(id: string): Promise<CloudFront.DistributionConfig> {
const config = await this.cloudFront.getDistributionConfig({
Id: id
}).promise()
return config.DistributionConfig;
}
/**
* CloudFront ãã£ã¹ããªãã¥ãŒã·ã§ã³ãåé€ãã
* @param id åé€ããã CloudFront ãã£ã¹ããªãã¥ãŒã·ã§ã³ã® ID
*/
async deleteDistribution(id: string) {
const distribution = await this.getDistribution(id);
await this.cloudFront.deleteDistribution({
Id: id, IfMatch: distribution.ETag
}).promise()
}
/**
* CloudFront ãã£ã¹ããªãã¥ãŒã·ã§ã³ãç¡å¹åãã
* @param id ç¡å¹åããã CloudFront ãã£ã¹ããªãã¥ãŒã·ã§ã³ã® ID
* @return ç¡å¹åãã CloudFront ãã£ã¹ããªãã¥ãŒã·ã§ã³ã®æ
å ±
*/
async disableDistribution(id: string): Promise<UpdateDistributionResult> {
const distribution = await this.getDistribution(id);
const config = distribution.Distribution.DistributionConfig;
config.Enabled = false;
return await this.cloudFront.updateDistribution({
Id: id,
IfMatch: distribution.ETag,
DistributionConfig: config
}).promise();
}
/**
* MediaPackage ã®ãšã³ããã€ã³ãçšã® CloudFront ãã£ã¹ããªãã¥ãŒã·ã§ã³ãäœæãã
* @param id CloudFront ãã£ã¹ããªãã¥ãŒã·ã§ã³ãå€å¥ããããã® ID
* @param mediaPackageArn MediaPackage ãã£ã³ãã«ã® ARN
* @param mediaPackageUrl MediaPackage ãšã³ããã€ã³ãã® URL
*/
async createDistributionForMediaPackage(
id: string,
mediaPackageArn: string,
mediaPackageUrl: string
): Promise<CreateDistributionWithTagsResult> {
// 1. url ã¢ãžã¥ãŒã«ãçšã㊠URL æååãããŒã¹ãã
const mediaPackageEndpoint = url.parse(mediaPackageUrl);
/**
2. MediaPackage ã®ãšã³ããã€ã³ã URL ãã FQDN ãååŸããã
åŸè¿°ãã CloudFront ãã£ã¹ããªãã¥ãŒã·ã§ã³ã®ãªãªãžã³ã®ãã¡ã€ã³åãšããŠãå©çšãã
*/
const mediaPackageHostname = mediaPackageEndpoint.hostname;
/**
3. MediaPackage ã®ãšã³ããã€ã³ã URL ã®ãã©ãŒãããã¯
https://<AccountID>.mediapackage.<Region>.amazonaws.com/**** ãšãªã£ãŠããã®ã§ã
FQDN ã®å
é éšåãæåååå²ã§åãåºããšã¢ã«ãŠã³ã ID ãååŸã§ãã
*/
const accountId = mediaPackageHostname.split('.')[0];
// 4. åŸè¿°ãã CloudFront ãã£ã¹ããªãã¥ãŒã·ã§ã³ã®ãªãªãžã³ ID ãšããŠãã¢ã«ãŠã³ã ID ãå©çšãã
const targetOriginId = `MP-${accountId}`
/**
5. createDistribution ã§ã¯ãªããcreateDistributionWithTags é¢æ°ã§ã
CloudFront ãã£ã¹ããªãã¥ãŒã·ã§ã³ãäœæãããMediaPackage ãšã®çŽä»ãã«ã¿ã°ãå©çšããããã
*/
return await this.cloudFront.createDistributionWithTags({
DistributionConfigWithTags: {
Tags: {
Items: [
/**
!!!!!éèŠ!!!!!
6. CloudFront ãã£ã¹ããªãã¥ãŒã·ã§ã³ã«çŽä»ããã
MediaPackage ãšã³ããã€ã³ãã®ãã£ã³ãã« ARN ã
mediapackage:cloudfront_assoc ã§å®çŸ©ããã
mediapackage:cloudfront_assoc ãå®çŸ©ããããšã§ã
CloudFront ãã£ã¹ããªãã¥ãŒã·ã§ã³ãš
MediaPackage ãã£ã³ãã«ãçŽä»ããããšãå¯èœãšãªãã
*/
{
Key: 'mediapackage:cloudfront_assoc',
Value: mediaPackageArn
},
{
Key: 'Id',
Value: id
},
{
Key: 'Product',
Value: 'product'
},
{
Key: 'Stage',
Value: 'dev'
}
]
},
DistributionConfig: {
CallerReference: new Date().toISOString(),
Comment: `Managed by MediaPackage - ${id}`,
Enabled: true,
/**
7. CloudFront ãã£ã¹ããªãã¥ãŒã·ã§ã³ã®ãªãªãžã³ã«ã¯ 2ã€èšå®ããŸãã
1ã€ã MediaPackage ã®ãšã³ããã€ã³ãã«å¯Ÿãããã®ãšã
ãã 1ã€ã MediaPacakge ãµãŒãã¹ã«å¯Ÿãããã®ã§ãã
åºæ¬çã«ã¯ MediaPackage ã®ãšã³ããã€ã³ãã«å¯Ÿãããªãªãžã³ãå©çšããŸãã
äŸå€æã«åãããªãªãžã³ã MediaPacakge ãµãŒãã¹ã«å¯Ÿãããã®ã«ãªããŸãã
*/
Origins: {
Quantity: 2,
Items: [
{
DomainName: mediaPackageHostname,
Id: targetOriginId,
CustomOriginConfig: {
HTTPPort: 80,
HTTPSPort: 443,
OriginProtocolPolicy: 'match-viewer'
}
},
{
DomainName: 'mediapackage.amazonaws.com',
Id: "TEMP_ORIGIN_ID/channel",
CustomOriginConfig: {
HTTPPort: 80,
HTTPSPort: 443,
OriginProtocolPolicy: 'match-viewer'
}
}
]
},
/**
8. CacheBehaviors ã®ãããã«ãåœãŠã¯ãŸããªãã£ãå Žåã®
ãã£ãã·ã¥ã®æ¯ãèããå®çŸ©ããŸãã
MediaPackage 㯠ã¿ã€ã ã·ãã衚瀺æ©èœã䜿çšããéçã§ãã¯ãšãªæååã« start, m, end ãå©çšããŠããŸãã
ãã®ããããããã®æåå㯠WhitelistedNames ã«å«ã QueryString ã«ã¯ true ãæå®ããŠãããŸãã
DefaultCacheBehavior ã«åŒã£ãããæåã¯äŸå€çæ±ããªã®ã§ã
䜿çšãããªãªãžã³ã¯ MediaPackage ãµãŒãã¹ã®ãã®ãèšå®ããŸãã
*/
DefaultCacheBehavior: {
ForwardedValues: {
Cookies: {
Forward: 'whitelist',
WhitelistedNames: {
Quantity: 3,
Items: [
'end', 'm', 'start'
]
}
},
QueryString: true,
Headers: {
Quantity: 0
},
QueryStringCacheKeys: {
Quantity: 0
}
},
MinTTL: 6,
TargetOriginId: "TEMP_ORIGIN_ID/channel",
TrustedSigners: {
Enabled: false,
Quantity: 0
},
ViewerProtocolPolicy: 'redirect-to-https',
AllowedMethods: {
Items: [
'GET', 'HEAD'
],
Quantity: 2,
},
MaxTTL: 60
},
/**
9. CloudFront ã®ãšã©ãŒã³ãŒãå
šãŠã® TTL ã« 1sec ãèšå®ããŸãã
MediaPackage ã®ãšã©ãŒã®ãã£ãã·ã¥ãé·æéæç¶ããŠããŸããšã
ãã®é㯠MediaPackage ã§æ£åžžã«é
ä¿¡ã§ããŠãããšããŠãã
埩æ§ã§ããªãç¶æ
ãšãªãããã§ãã
*/
CustomErrorResponses: {
Quantity: 10,
Items: [
{
ErrorCode: 400,
ErrorCachingMinTTL: 1
}, {
ErrorCode: 403,
ErrorCachingMinTTL: 1
}, {
ErrorCode: 404,
ErrorCachingMinTTL: 1
}, {
ErrorCode: 405,
ErrorCachingMinTTL: 1
}, {
ErrorCode: 414,
ErrorCachingMinTTL: 1
}, {
ErrorCode: 416,
ErrorCachingMinTTL: 1
}, {
ErrorCode: 500,
ErrorCachingMinTTL: 1
}, {
ErrorCode: 501,
ErrorCachingMinTTL: 1
}, {
ErrorCode: 502,
ErrorCachingMinTTL: 1
}, {
ErrorCode: 503,
ErrorCachingMinTTL: 1
}
]
},
/**
10. CloudFront ãã£ã¹ããªãã¥ãŒã·ã§ã³ã®ãã£ãã·ã¥ã®æ¯ãèãã 2ã€å®çŸ©ããŸãã
ããããã®èšå®å
容ã¯åºæ¬çã« DefaultCacheBehavior ã§å®çŸ©ãããã®ãšåæ§ã§ãã
ããããå©çšãããªãªãžã³ã¯ MediaPackage ãšã³ããã€ã³ãã«åãããã®ãå©çšããŸãã
1ã€ã¯ Microsoft Smooth Streaming ã§ã®é
ä¿¡æã«å©çšãã
index.ism ã«å¯Ÿãããã®ã§ Smooth Streaming ã true ã«èšå®ããŠããŸãã
ãã 1ã€ã¯äžèš Microsoft Smooth Streaming 以å€ã®
å
šãŠã«åœãŠã¯ãŸãã¹ããªãŒãã³ã°ã«é©çšããããã®ã«ãªããŸãã
*/
CacheBehaviors: {
Quantity: 2,
Items: [{
MinTTL: 6,
PathPattern: 'index.ism/*',
TargetOriginId: targetOriginId,
ViewerProtocolPolicy: 'redirect-to-https',
AllowedMethods: {
Items: [
'GET', 'HEAD'
],
Quantity: 2,
},
ForwardedValues: {
Cookies: {
Forward: 'whitelist',
WhitelistedNames: {
Quantity: 3,
Items: [
'end', 'm', 'start'
]
}
},
QueryString: true,
Headers: {
Quantity: 0
},
QueryStringCacheKeys: {
Quantity: 0
},
},
SmoothStreaming: true
}, {
MinTTL: 6,
PathPattern: '*',
TargetOriginId: targetOriginId,
ViewerProtocolPolicy: 'redirect-to-https',
AllowedMethods: {
Items: [
'GET', 'HEAD'
],
Quantity: 2,
},
ForwardedValues: {
Cookies: {
Forward: 'whitelist',
WhitelistedNames: {
Quantity: 3,
Items: [
'end', 'm', 'start'
]
}
},
QueryString: true,
Headers: {
Quantity: 0
},
QueryStringCacheKeys: {
Quantity: 0
},
}
}]
},
PriceClass: 'PriceClass_All'
}
}
}).promise()
}
}
createDistributionForMediaPackage
ã§äœæãããã£ã¹ããªãã¥ãŒã·ã§ã³ã¯ãå
¬åŒããŒãžã«èšèŒãããæé ã§äœæãã CloudFront ãã£ã¹ããªãã¥ãŒã·ã§ã³ãšåçã®ãã®ã«ãªããŸãã
詳现ãªèª¬æã¯ã€ã³ã©ã€ã³ã³ã¡ã³ãã«ãŠæžããŸããããäžå¿è£è¶³èª¬æãå°ãä»ãå ããŠãããŸãã
éæã«åºãŠãã Quantity
ã«ã€ããŠ
Quantity
ã«ã¯ Items
ã§æå®ããé
ç®ã®æ°ãå
¥åããŸãã äŸãã° Headers
ã QueryStringCacheKeys
ã«ã¯ Items
ã«äœãæå®ããŠããªããããQuantity
ã« 0
ãæå®ããŸãã
ããããAllowedMethods
ã WhitelistedNames
ã«ã¯ Items
ã«æå®ããé
ç®æ°ã§ãã 2
ã 3
ã Quantity
ã«å
¥åããŠããŸããQuantity
ã®æ°ãš Items
ã®é
ç®æ°ãåããªããšããšã©ãŒãçºçããããã泚æãå¿
èŠã§ãã
mediapackage:cloudfront_assoc
ãå®çŸ©ããæå³
CloudFront ãã£ã¹ããªãã¥ãŒã·ã§ã³ã®ã¿ã°ã« mediapackage:cloudfront_assoc
ã§çŽä»ãã MediaPackage ã®ãã£ã³ãã« ARN ãæå®ããããšã§ãMediaPackage ã³ã³ãœãŒã«ããçŽä»ãããã CloudFront ãã£ã¹ããªãã¥ãŒã·ã§ã³æ
å ±ãåç
§ã§ããããã«ãªããŸãã
è©Šãã«çŽã¥ãããã MediaPackage ã®ãã£ã³ãã«ã®ãšã³ããã€ã³ã詳现ããŒãžã«é·ç§»ãããšã äžèšã®ãããªç»é¢ã確èªã§ããã¯ãã§ãã
mediapackage:cloudfront_assoc
ã§çŽä»ãã CloudFront ãã£ã¹ããªãã¥ãŒã·ã§ã³ã確èªã§ãã
æ¬èšäºå
ã®ãœãŒã¹ã³ãŒãã§ã¯ä»ã«ã Id
, Product
, Stage
ãšãã£ãã¿ã°ãå®çŸ©ããŠããŸãããMediaPackage ãšã¯é¢ä¿ç¡ããã®ãªã®ã§åé€ããŠåé¡ãããŸããã
updateDistribution
ãå®è¡ããéã®æ³šæç¹
ããã¯ä»åã®èšäºå 容ãšã¯çŽæ¥é¢ä¿ãªãã®ã§ãããå°å³ã«ããã£ãã®ã§èŒããŠãããŸãã
CloudFront ã§ã¯ createDistribution
ã®æã«èŠæ±ããããã©ã¡ãŒã¿ããã updateDistribution
ã§èŠæ±ããããã©ã¡ãŒã¿ã®ã»ããå€ãã§ãã AWS å
¬åŒããŒãžã®æ¯èŒè¡šã«ããéãã§ãã
ãã®ãããupdateDistribution
ã§èšå®ãäžéšæŽæ°ãããã ããªã®ã«ããšãŠãå€ãã®ãã©ã¡ãŒã¿ãæå®ããå¿
èŠãããéåžžã«é¢åã§ããäŸãã° CloudFront ãã£ã¹ããªãã¥ãŒã·ã§ã³ã® Enable/Disable ãåãæ¿ããã ãã§ã 30 åè¿ããã©ã¡ãŒã¿ãæå®ããå¿
èŠãããŸãã
äžèšã®å
¥åã®æéãçãã®ã«ã¯ getDistribution
ã§ååŸããæ¢åã®ãã£ã¹ããªãã¥ãŒã·ã§ã³æ
å ±ãæ¹å€ãã圢㧠updateDistribution
ã®ãã©ã¡ãŒã¿ãäœæãããšæ¥œã§ããã
ä»åã®ãœãŒã¹ã³ãŒãã®å
容ãåç
§ãããš disableDistribution
ã該åœããŸãã
// 1. getDistribution ãå®è¡ã㊠CloudFront ãã£ã¹ããªãã¥ãŒã·ã§ã³ã®æ
å ±ãååŸãã
const distribution = await this.getDistribution(id);
// 2. CloudFront ãã£ã¹ããªãã¥ãŒã·ã§ã³ã®èšå®å
容ãååŸãã
const config = distribution.Distribution.DistributionConfig;
// 3. CloudFront ãã£ã¹ããªãã¥ãŒã·ã§ã³ã® Enabled/Disabled ãåãæ¿ãããªãã·ã§ã³ãæ¹å€ãã
config.Enabled = false;
// 4. 3. ã§æ¹å€ããå
容ã updateDistribution 㧠CloudFront ãã£ã¹ããªãã¥ãŒã·ã§ã³ã«åæ ãã
return await this.cloudFront
.updateDistribution({
Id: id,
IfMatch: distribution.ETag,
DistributionConfig: config,
})
.promise();
ãããã«
ããããªå 容ãªã®ã§ãæ¬èšäºå 容ãä»åŸå©çšãããã©ããã¯åãããŸããããäžå¿åŸãç¥èŠãèšäºãšããŠæ®ããŠãããŸãããåæ§ã®ããšãè¡ãå¿ èŠãåºãŠããæ¹ã®åèã«ãªããã°å¹žãã§ãã