ECS Fargate のメトリクスを Grafana の画面で確認している様子

📔 ECS Fargate のメトリクスを Prometheus Agent 使って AMP に送って Grafana で監視する

はじめに この記事は AWS Advent Calendar 2021 の 5 日目の記事です。 Fargate で Node.js アプリのメトリクスを Prometheus Agent をサイドカーコンテナとして動かして、Amazon Managed Service for Prometheus (AMP) に送信して Grafana で見られるようにしてみました。 ちなみに Promethus Agent はまだ 実験的な機能 なため、実務での利用は推奨しません。 本記事の環境構築には AWS CDK を利用しています。 動作環境 Node.js v16.13.0 AWS CDK 2.0.0 (build 4b6ce31) Prometheus 2.32.1 環境構築 早速環境構築を進めていきます。まだ AMP については CDK から操作できないようでしたので、ワークスペースの作成については AWS コンソールから手動で行います。(2021/12/06) aws-aps を利用することで AWS CDK からでも Amazon Managed Service for Prometheus のワークスペースを作成すること確認できましたので、そちらの利用を推奨いたします… 🙇🙇 lib/prometheus-agent-test-stack.ts のコードも修正済みで AWS CDK で Amazon Managed Service for Prometheus のワークスペースを作成するように編集しました。(2021/12/18 追記) ...

12月 5, 2021 · 6 分 · Me

📔 MediaPackage 用の CloudFront ディストリビューションを AWS SDK で作成する

はじめに とある事情で 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 ディストリビューションと同等のものになります。 ...

12月 15, 2020 · 5 分 · Me

📔 Serverless のプラグインを TypeScript で作成する方法

はじめに Serverless Framework を使っていて、度々デプロイ時に手動で設定していた作業内容を自動化したいなと思い、プラグイン作成の知識習得も兼ねてライブラリを作成し NPM で公開してみました。 https://www.npmjs.com/package/serverless-amplify-auth 今後も開発する可能性はありそうなので Serverless のプラグインを TypeScript で作成する際の手順をまとめておきました。各手順はザックリと紹介しつつ、主にその過程でハマった点や工夫した点に重きをおいて記事を書いていきます。 動作環境 Node.js 12.19.0 Serverless Framework Framework Core: 2.10.0 Plugin: 4.1.1 SDK: 2.3.2 Components: 3.3.0 開発環境を整える 本記事の内容を最後まで実践した際の最終的なプロジェクトのディレクトリ構造は下記になります。 tree -I node_modules -L 2 ./ ./ ├── example # ライブラリの動作検証用のサンプルコードを配置するフォルダ │ ├── handler.js │ ├── package.json │ └── serverless.yml ├── lib # src フォルダ内のファイルをコンパイルした結果を配置するフォルダ (ライブラリとして利用する際に含まれるソースコード群) │ ├── index.js │ └── index.js.map ├── package-lock.json ├── package.json ├── src # Serverless プラグインのソースコードを配置するフォルダ │ └── index.ts └── tsconfig.json 基本的には TypeScript で Serverless Framework の Plugin を書いてみる | Developers.IO の手順をなぞっていくだけで環境構築自体は可能です。そこで、ここでは自分なりに工夫した箇所について記載していきます。 ...

11月 8, 2020 · 5 分 · Me