Slide 1

Slide 1 text

App Staging Synthesizer に入門する AWS CDK Conference Japan 2024

Slide 2

Slide 2 text

自己紹介 🧑‍💻 名前 櫻井 良 📝 普段の業務 AWSを使ったアプリ開発 🛠 好きなAWSサービス AWS CDK Amazon ECS

Slide 3

Slide 3 text

App Staging Synthesizerって??

Slide 4

Slide 4 text

App Staging Synthesizer This library includes constructs aimed at replacing the current model of bootstrapping and providing greater control of the bootstrap experience to the CDK user. ドキュメントより引用 (雑な日本語訳) 「このライブラリには、現在のブートストラップモデルを置き換え、CDKユーザーに対してブートストラップ体験をより コントロールできるようにするための構成が含んでいる」 既存のブートストラップの仕組みの置き換えを目指して開発されている ブートストラップ体験をよりコントロールできるようにする??

Slide 5

Slide 5 text

App Staging Synthesizerを理解するには App Staging Synthesizerを理解するには以下の項目がキーになる 1. 既存のBootstrapモデルが抱えている課題とは? 2. App Staging Synthesizerがどのように解決を目指しているか これからこの2つをメインテーマとして深ぼっていきます

Slide 6

Slide 6 text

既存のBootstrapモデルとは

Slide 7

Slide 7 text

Bootstrapの役割 Bootstrapping is the process of preparing your AWS environment for usage with the AWS Cloud Development Kit (AWS CDK). Before you deploy a CDK stack into an AWS environment, the environment must first be bootstrapped. Developer Guideより (雑な日本語訳) 「ブートストラッピングとは、AWS Cloud Development Kit(AWS CDK)を使用するためにAWS環境を準備するプロセ スです。 」 「CDKスタックをAWS環境にデプロイする前に、まずその環境をブートストラップする必要があります。 」 あるAWSアカウントに対して初めてAWS CDKを利用したデプロイを行う前に必要となる処理のこと しれっと出てきた環境(Environment)という概念が重要

Slide 8

Slide 8 text

環境(Environment)とは AWSアカウントとリージョンの組み合わせを環境(Environment)と呼んでいる 同じAWSアカウントでもリージョンが違えばことなる Environment となる 以下の2つはことなる Environment なので注意 アカウント(111111111111) => リージョン(us-east-1) アカウント(111111111111) => リージョン(ap-northeast-1) 📝 https://docs.aws.amazon.com/cdk/v2/guide/environments.html 同じアカウントでも異なるリージョンにデプロイする場合は最初に2回のブートストラップが必要 なので注意

Slide 9

Slide 9 text

Bootstrapプロセスは何をするか CDKのデプロイに利用するAWSリソースのプロビジョニングが主なお仕事 CDKのアセットを保存するS3バケットやECRリポジトリ アセットの保存やデプロイを行う際にAssumeするIAM Role プロビジョニングされるリソースはGitHub上で確認が可能 https://github.com/aws/aws-cdk/blob/main/packages/aws-cdk/lib/api/bootstrap/bootstrap-template.yaml cdk bootstrap --show-template コマンドでも確認可能 $ cdk bootstrap ACCOUNT-NUMBER/REGION # e.g. $ cdk bootstrap 1111111111/us-east-1 $ cdk bootstrap --profile test 1111111111/us-east-1

Slide 10

Slide 10 text

プロビジョニングされるリソース(2024年7月現在) Application Composerで見てみると色々なリソースが確認できる

Slide 11

Slide 11 text

作成されるIAM Role 以下のようなIAM RoleがBootstrapプロセスによって作成される(細かい部分は省略します) ロール名 概要 ImagePublishingRole ECRへコンテナイメージの保存に利用(後述) FilePublishingRole S3へファイルの保存に利用(後述) DeploymentActionRole 主にCFnスタックに関連する操作に利用 CloudFormationExecutionRole CFn実行時のサービスロールとして利用 LookupRole fromLookup メソッド実行時にAWSリソース参照のために利用

Slide 12

Slide 12 text

その他のリソース 論理名 概要 StagingBucket CFnテンプレートやCDKのファイルアセットの保存場所 ContainerAssetsRepository CDKのコンテナイメージアセットの保存場所 FileAssetsBucketEncryptionKey StagingBucketの暗号化に利用するKMSキー(マネージドキーの利用も可)

Slide 13

Slide 13 text

デプロイのフロー Security-And-Safety-Dev-Guideより

Slide 14

Slide 14 text

ロールが利用される様子 cdk deploy コマンドに -v オプションを付与するとデバッグログが表示される Assuming role ~ というログからどういったRoleを利用しているか確認可能 Assuming role ~ だけを切り出してみると色々なロールを駆使してデプロイしているのがわかる [23:54:26] Assuming role 'arn:aws:iam::111111111111:role/cdk-hnb659fds-deploy-role-111111111111-ap-nor [23:54:26] Assuming role 'arn:aws:iam::111111111111:role/cdk-hnb659fds-deploy-role-111111111111-ap-nor [23:54:26] Assuming role 'arn:aws:iam::111111111111:role/cdk-hnb659fds-file-publishing-role-1111111111 [23:54:26] Assuming role 'arn:aws:iam::111111111111:role/cdk-hnb659fds-file-publishing-role-1111111111 [23:54:27] Assuming role 'arn:aws:iam::111111111111:role/cdk-hnb659fds-file-publishing-role-1111111111 [23:54:27] Assuming role 'arn:aws:iam::111111111111:role/cdk-hnb659fds-file-publishing-role-1111111111 [23:54:27] Assuming role 'arn:aws:iam::111111111111:role/cdk-hnb659fds-lookup-role-111111111111-ap-nor

Slide 15

Slide 15 text

Bootstrapモデルのまとめ cdk deployに必要なAWSリソースのプロビジョニングを行うプロセス アセットを保存するためのECRとS3バケット cdkコマンドの実行時にAssumeするためのIAM Role Bootstrapにはリージョンリソースが含まれるため各リージョンで実行が必要 グローバルリソースであるIAM Roleは {roleName}-{region} という命名で作成されるので命名が被ることはない CDKのデプロイには色々なIAM RoleにAssumeを行うことで実現されている Bootstrapping is the process of preparing your AWS environment for usage with the AWS Cloud Development Kit (AWS CDK). Before you deploy a CDK stack into an AWS environment, the environment must first be bootstrapped. Developer Guideより もう2つApp Staging Synthesizerの理解のために必要な概念があるので触れていきます

Slide 16

Slide 16 text

① Stack Synthesizer Each Stack has a synthesizer, an object that determines how and where the Stack should be synthesized and deployed. https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib-readme.html#stack-synthesizers より (雑な日本語訳) 「各スタックにはsynthesizerがあり、これはスタックがどのように、そしてどこに合成およびデプロイされるべきかを 決定するオブジェクトです」 役割としては主に2点 CDKのアセットをどこに保存して参照するか CFnスタックをデプロイするためにどのIAM Roleを利用するか いくつか種類がありますがここではデフォルトで利用される DefaultStackSynthesizer を取り上げます

Slide 17

Slide 17 text

DefaultStackSynthesizer デフォルトで利用されるStack Synthesizer Bootstrapで作成されたアセットの保存場所とIAM Roleを使用する cdkコマンド実行時に利用するIAM Role Arnの決定 アセット保存時にどのS3バケットやECRに保存するかを決定 Bootstrapテンプレートを変更している場合は、変更内容をDefaultStackSynthesizerにも教えてあげる必要有 これらの情報とCFnテンプレートファイルの場所などを合成時に cdk.out/manifest.json に吐き出す cdk.out/manifest.json を元にアプリケーションのデプロイが行われる AppStagingSynthesizer はこの DefaultStackSynthesizer の代わりに利用するモジュール

Slide 18

Slide 18 text

② Assets CDKアプリケーションが必要とするファイルやコンテナイメージを指す Bootstrapで作成されたS3バケットとECRに保存(自由に保存先を選択出来ないので注意) S3に保存されるファイルとECRに保存されるコンテナイメージの2種類が存在 import { Asset } from 'aws-cdk-lib/aws-s3-assets'; import { DockerImageAsset } from 'aws-cdk-lib/aws-ecr-assets'; // 明示的にS3アセットを作成する場合 // 多くはLambda関数作成時など裏側で作成される const directoryAsset = new Asset(this, "SampleZippedDirAsset", { path: path.join(__dirname, "sample-asset-directory") }); // ECRアセットを作成する場合 const asset = new DockerImageAsset(this, 'MyBuildImage', { directory: path.join(__dirname, 'my-image') });

Slide 19

Slide 19 text

Bootstrapモデルが抱える課題って?

Slide 20

Slide 20 text

① セキュリティポリシーへの準拠 デフォルトで作成されるリソースが組織のセキュリティポリシーに準拠していない場合がある Bootstrapテンプレートはユーザー側で変えることが出来る cdk bootstrap コマンドの --template オプションに変更したテンプレートを指定可能 例えばECRのスキャンの有効化などなど ただ、元のBootstrapテンプレートが変更される場合もあるので追従していく手間がある cdk bootstrap --show-template コマンドなどで最新のテンプレートを確認し、カスタムテンプレートに反映す る 同一環境でデプロイされる複数のプロジェクトにおいてリソースの分離が難しい アカウントを分けるのがベストではあるが、分けられない事情があるケースも 📝 https://github.com/aws/aws-cdk-rfcs/blob/main/text/0513-app-specific-staging.md#v2

Slide 21

Slide 21 text

② S3・ECR内のアセット数の肥大化 同一環境で同一のS3とECRを利用することで、色々なアプリケーションのアセットが混在するためライフサイクルポ リシーの設定が難しい アプリケーションのよって必要なライフサイクルは異なる ファイル名やコンテナイメージのタグ名はハッシュ値になっているので定期的に削除バッチを走らせるのも工夫が 必要 CFnから参照されていないことを確認してから消さないといけない 2018年からissueでアセットに対するガベージコレクションが議論されている 特に進展は無し Coreチームとしては App Staging Synthesizer を使ってくれというスタンス? サードパーティ製のガベージコレクションツールも存在している https://github.com/jogold/cloudstructs/tree/master/src/toolkit-cleaner 📝 Garbage Collection for Assets: https://github.com/aws/aws-cdk-rfcs/issues/64

Slide 22

Slide 22 text

App Staging Synthesizerの概要

Slide 23

Slide 23 text

App Staging Synthesizerの概要 DefaultStackSynthesizer に変わる新しいSynthesizerの実装 導入後ユーザーが作成したスタックとは別に StagingStack がデプロイされる CDKアプリケーションごとにS3バケットとECRを作成可能 => CDKアプリごとにリソースの分離が出来る これらは StagingStack に含まれ、Bootstrapの一部代わりとなる import { BucketEncryption } from 'aws-cdk-lib/aws-s3'; const app = new App({ defaultStackSynthesizer: AppStagingSynthesizer.defaultResources({ appId: 'my-app-id', // `StagingStack`のスタック名やS3バケットのprefixとして利用される stagingBucketEncryption: BucketEncryption.S3_MANAGED, }), }); 📝 https://docs.aws.amazon.com/cdk/api/v2/docs/app-staging-synthesizer-alpha-readme.html

Slide 24

Slide 24 text

StagingStackとは App Staging Synthesizer導入時に作成されるスタック スタック名は StagingStack-{appId} で作成される S3バケット・ECRとこれらにアクセスするためのIAM Roleなどが含まれる

Slide 25

Slide 25 text

BootstrapとApp Staging Synthesizerの関係

Slide 26

Slide 26 text

App Staging Synthesizerの特徴 変わらない点 IAM Roleについては引き続きBootstrapプロセスで作成されたIAM Roleを使用 現状ではBootstrapプロセスが不要にはならない(詳しくは後述) 変更点 各アセットはBootstrapプロセスで作成されたS3バケットとECRではなく、CDKアプリごとに作成されたS3バケット とECRに保存される S3バケットは1つ作成される ECRはイメージ種類ごとに作成される(詳しくは後述)

Slide 27

Slide 27 text

なぜBootstrapが不要にならないか 前述の通りApp Staging SynthesizerはBootstrapプロセスで作成されたIAM Roleを使用するため ファイルとコンテナイメージの保存には新しく作成したIAM Roleを使用 一方でリージョンリソース(S3, ECR)についてはBootstrapプロセスで作成する必要は無い 現状でIAM Roleのみ作成するBootstrapテンプレートは提供されていないので要カスタマイズ BootstrapはIAM Role名のsuffixして実行したリージョンを付与するので、Bootstrapしていないリージョンで cdk deploy を実行する際はリージョンの指定が必要 ただ現状はStagingStackのデプロイに利用するロール名の指定がおかしくバグっている。 。 deploymentIdentities: DeploymentIdentities.defaultBootstrapRoles({bootstrapRegion: 'us-east-1'}), const app = new cdk.App({ defaultStackSynthesizer: AppStagingSynthesizer.defaultResources({ appId: "my-app", stagingBucketEncryption: BucketEncryption.S3_MANAGED, }), });

Slide 28

Slide 28 text

StagingStackで作成されるS3バケットの特徴 バケット名は明示的に指定が可能、デフォルトは cdk-${appId}-staging-${account}-${region} デフォルトで RemovalPolicy が Destroy かつ autoDeleteObjects もtrueに設定されている StagingStack スタックの削除で全てのS3アセットは削除される autoDeleteStagingAssets プロパティで制御可能 autoDeleteStagingAssets: false の場合は RemovalPolicy が Retain に変更される stagingBucketName : "my-staging-bucket", autoDeleteStagingAssets: false, const app = new App({ defaultStackSynthesizer: AppStagingSynthesizer.defaultResources({ appId: 'my-app-id', stagingBucketEncryption: BucketEncryption.S3_MANAGED, }), });

Slide 29

Slide 29 text

AppStagingSynthesizerにおけるS3アセットの扱い Deploy Time S3 Assets という概念が追加された 合成したCFnテンプレートやLambdaのコードバンドルなど、デプロイ時にみに参照するアセットが該当 これらのアセットは deploy-time/{assetName} というキーで保存される またデフォルトで30日間保持されるようにライフサイクルルールが設定される deployTimeFileAssetLifetime プロパティで保持期間を明示的に設定可能 ロールバックの期間を考え慎重に設定する必要がある deployTimeFileAssetLifetime: Duration.days(100), const app = new cdk.App({ defaultStackSynthesizer: AppStagingSynthesizer.defaultResources({ appId: "my-app", stagingBucketEncryption: BucketEncryption.S3_MANAGED, }), });

Slide 30

Slide 30 text

Deploy Time S3 Assetsとして扱われるアセット Lambda関数のコードバンドル aws-s3-assets を利用した場合でも明示的に指定が可能 deployTime: false, // デフォルトはtrueとみなされる new Function(this, 'Lambda', { code: new AssetCode(path.join(__dirname, "function"), { }), }); deployTime: true, new Asset(this, 'S3Asset', { path: path.join(__dirname, "asset"), });

Slide 31

Slide 31 text

StagingStackで作成されるECRの特徴① デフォルトでライフサイクルルールで最大3つのイメージまで保持 & emptyOnDelete がtrueに設定 imageAssetVersionCount プロパティでイメージの世代数を指定可能 バケットと同じく autoDeleteStagingAssets をtrueに指定した場合、ECRの RemovalPolicy が Retain に変更される S3と共通の設定なのでECRのみ RemovalPolicy.Destroy などは出来ない imageAssetVersionCount: 10, // コンテナイメージの最大数の指定 autoDeleteStagingAssets: false, // S3バケットと共通の設定 const app = new App({ defaultStackSynthesizer: AppStagingSynthesizer.defaultResources({ appId: 'my-app-id', stagingBucketEncryption: BucketEncryption.S3_MANAGED, }), });

Slide 32

Slide 32 text

StagingStackで作成されるECRの特徴② AppStagingSynthesizer 利用時は DockerImageAsset で assetName プロパティの指定が必須 この assetName ごとにECRが作成される(DockerImageAssetを利用しない限りECRは作成されない) リポジトリ名は明示的に指定出来ず、 ${appId}/${assetName} となるのでスタック名を入れるなど工夫が必要 タグ名は既存と同じでハッシュ値になり指定出来ない assetName: "backend", // `{appId}/backend`というリポジトリが作成される assetName: "frontend", // `{appId}/frontend`というリポジトリが作成される export class TestStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); new DockerImageAsset(this, 'ECRAsset', { directory: path.join('assets'), }); new DockerImageAsset(this, 'ECRAsset2', { directory: path.join('assets2'), }); } }

Slide 33

Slide 33 text

主な利用上の注意点① StagingStack は環境ごとに作成される 各Stack classの synthesizer プロパティに設定は出来るが複数スタックが同一環境の場合は1つのみ作成されるため あまり意味はない synthesizer: AppStagingSynthesizer.defaultResources({}), synthesizer: AppStagingSynthesizer.defaultResources({}), // 複数のAppStagingSynthesizerを指定しているが1つのStagingStackしか出来ない例 new BackendStack(app, 'BackendStack', { env: { account: '111111111111', region: 'ap-northeast-1' }, // 同じ環境 }); new FrontendStack(app, 'FrontendStack', { env: { account: '111111111111', region: 'ap-northeast-1' }, // 同じ環境 });

Slide 34

Slide 34 text

つづき 全てのスタックが同一環境の場合、 App の初期化時に指定を行う 各スタックで環境が違う場合、 Stack に指定することで環境毎に設定が可能 ただ、挙動が直感的ではないので基本的には App に指定するのが無難? // `App`に指定した場合でも各スタックが異なる環境の場合は各リージョンで`StagingStack`を作成して defaultStackSynthesizer: AppStagingSynthesizer.defaultResources({}), env: { account: '111111111111', region: 'ap-northeast-1' }, // ap-northeast-1独自の設定をしたい場合 defaultStackSynthesizer: AppStagingSynthesizer.defaultResources({}), env: { account: '111111111111', region: 'us-east-1' }, // ue-east-1独自の設定をしたい場合 defaultStackSynthesizer: AppStagingSynthesizer.defaultResources({}), const app = new App({ }); new TokyoStack(app, 'TokyoStack', { }); new VirginiaStack(app, 'VirginiaStack', { });

Slide 35

Slide 35 text

主な利用上の注意点② CDK Pipelineは非対応 作成出来るECRリポジトリは20個までに制限されている(将来緩和の可能性あり) StagingStack のCFnテンプレートをS3経由でデプロイが出来ないためCloudFormationのクォータでテンプレート サイズが51,200 bytesに制限される S3バケットは StagingStack で作成されるため、 StagingStack のデプロイ時はそもそもバケットが存在しない BootstraplessSynthesizer というまた別のSynthesizerを利用してデプロイを実現している まだalpha版のモジュールのため破壊的な変更が入る恐れがある 本番環境での利用は要検討 既知のバグに関してはGitHub issueをご参照ください 📝制限について: https://docs.aws.amazon.com/cdk/api/v2/docs/app-staging-synthesizer-alpha- readme.html#known-limitations 📝GitHub issue: https://github.com/aws/aws-cdk/labels/%40aws-cdk%2Fapp-staging-synthesizer-alpha

Slide 36

Slide 36 text

まとめ アセットの保存にCDKアプリ毎で作成したECRとS3バケットを利用することで、CDKアプリ毎のリソース分離を行え る これによりアセットのライフサイクルが管理しやすくなりコストも削減 将来的にはよりBootstrapの存在を意識しなくてもよくなるかも まだAlpha版なのでご利用は計画的に 参考資料 触れられなかった機能もまだあるので興味が湧いた方はこちらの資料をぜひご覧ください 📝Docs: https://docs.aws.amazon.com/cdk/api/v2/docs/app-staging-synthesizer-alpha-readme.html 📝AWS Blogs: https://aws.amazon.com/blogs/devops/enhancing-resource-isolation-in-aws-cdk-with-the-app- staging-synthesizer/ 📝Security-And-Safety-Dev-Guide: https://github.com/aws/aws-cdk/wiki/Security-And-Safety-Dev-Guide

Slide 37

Slide 37 text

よりよいCDKライフを! ご清聴ありがとうございました。