Slide 1

Slide 1 text

AWS CDKのConstruct IDは どのように命名するべきか? リテールアプリ共創部 マッハチーム 金城 秀哉 2024/11/01 1

Slide 2

Slide 2 text

自己紹介 金城 秀哉(Shuya Kinjo) リテールアプリ共創部 マッハチーム サーバーサイドエンジニア 興味・関心 IaC(AWS CDK)、CI/CD、生成AI 2

Slide 3

Slide 3 text

AWS CDKでIaCを書く時、こんな経験ありま せんか? 😕 3

Slide 4

Slide 4 text

こんな経験ありませんか? 😕 スタックを宣言 StackのConstruct IDはクラス名 と同じ コンストラクトを宣言 🤔。 。(Construct IDは親を引き継 いで動的にし、衝突を避けよう) new MySpecialServiceStack(app, "MySpecialServiceStack", {}); export class MySpecialServiceStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); new S3Construct(this, `${id}-S3Construct`); } } 4

Slide 5

Slide 5 text

こんな経験ありませんか? 😕 スタックを宣言 StackのConstruct IDはクラス名 と同じ コンストラクトを宣言 🤔。 。(Construct IDは親を引き継 いで動的にし、衝突を避けよう) new MySpecialServiceStack(app, "MySpecialServiceStack", {}); new S3Construct(this, `${id}-S3Construct`); export class MySpecialServiceStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); } } 4

Slide 6

Slide 6 text

こんな経験ありませんか? 😕 S3 Constructの中も同じくIDを引 き継いでおこう export class S3Construct extends Construct { constructor(scope: Construct, id: string) { super(scope, id); new s3.Bucket(this, `${id}-Bucket1`, { versioned: true, removalPolicy: RemovalPolicy.DESTROY, autoDeleteObjects: true, }); new s3.Bucket(this, `${id}-Bucket2`, { encryption: s3.BucketEncryption.KMS_MANAGED, removalPolicy: RemovalPolicy.DESTROY, autoDeleteObjects: true, }); } } 5

Slide 7

Slide 7 text

こんな経験ありませんか? 😕 S3 Constructの中も同じくIDを引 き継いでおこう new s3.Bucket(this, `${id}-Bucket1`, { new s3.Bucket(this, `${id}-Bucket2`, { export class S3Construct extends Construct { constructor(scope: Construct, id: string) { super(scope, id); versioned: true, removalPolicy: RemovalPolicy.DESTROY, autoDeleteObjects: true, }); encryption: s3.BucketEncryption.KMS_MANAGED, removalPolicy: RemovalPolicy.DESTROY, autoDeleteObjects: true, }); } } 5

Slide 8

Slide 8 text

cdk deploy ✨ % cdk deploy 'MySpecialServiceStack' ... Do you wish to deploy these changes (y/n)? y MySpecialServiceStack: deploying... [1/1] MySpecialServiceStack: creating CloudFormation changeset... ✅ MySpecialServiceStack ✨ Deployment time: 53.89s Stack ARN: arn:aws:cloudformation:ap-northeast-1:012345678910:stack/MySpecialServiceStack/1625a640-9787-11ef-9f35-0e80c9521165 ✨ Total time: 61.44s 6

Slide 9

Slide 9 text

デプロイされたリソースをコンソールで確認 7

Slide 10

Slide 10 text

どっちがどっちかわからない 🤷‍♂️ 8

Slide 11

Slide 11 text

こんな時に取る方法 1. リソース定義時に明示的にリソース名を指定する 1. リソース名の衝突が起こりやすくAWS的には非推奨 9

Slide 12

Slide 12 text

こんな時に取る方法 1. リソース定義時に明示的にリソース名を指定する 1. リソース名の衝突が起こりやすくAWS的には非推奨 2. リソースの命名規則を理解して適切なConstruct IDを命名する 1. この話をします 10

Slide 13

Slide 13 text

この10分で話すこと 1. 先に結論 2. CDKで定義したリソースの名前が決まる仕組み 3. 命名Tips4選 11

Slide 14

Slide 14 text

結論 Construct ID は scope の中で一意にする Construct ID は PascalCase で記述する Construct ID に Construct 、 Stack とつけない 親 コンストラクト で表している情報を繰り返さない Default と Resource を活用し Construct ID を短縮する 12

Slide 15

Slide 15 text

この10分で話すこと 1. 先に結論 2. CDKで定義したリソースの名前が決まる仕組み 3. 命名Tips4選 13

Slide 16

Slide 16 text

Construct ID とは Construct ID とは、CDK で コンストラクト を インスタンス化 する際 に、第 2 引数に渡す文字列のことです。 CDK では コンストラクト を利用して Stack 内のリソースを構造化でき ます。指定する Construct ID は コンストラクト のスコープ内で一意で ある必要があります。 例) new sqs.Queue(this, "MyQueue"); // MyQueue が Construct ID 14

Slide 17

Slide 17 text

論理 ID とは 論理 IDは CloudFormation テンプレートの Resources セクションでリ ソースを一意に示す ID です。論理 ID の変更はリソースの置換を意味し ます。 例) Resources: MyEC2Instance: # 論理ID Type: AWS::EC2::Instance Properties: ImageId: ami-0ff8a91507f77f867 15

Slide 18

Slide 18 text

論理 ID とは 論理 IDは CloudFormation テンプレートの Resources セクションでリ ソースを一意に示す ID です。論理 ID の変更はリソースの置換を意味し ます。 例) MyEC2Instance: # 論理ID Resources: Type: AWS::EC2::Instance Properties: ImageId: ami-0ff8a91507f77f867 15

Slide 19

Slide 19 text

Construct ID と論理 ID の関係性 Construct ID は CDK から CloudFormation テンプレートを合成する 際、CloudFormation の論理 ID を決めるために使用されます。 リソースに明示的に名前を指定しない場合、CloudFormation は論理 ID をもとにリソース名を生成します。図にすると以下の関係性です。 AWS CloudFormation AWS CDK cdk synth deploy 自動生成のリソース名 論理ID Construct ID 16

Slide 20

Slide 20 text

論理 IDは切り捨てられる CloudFormation の論理 ID は 255 文字まで指定可能です。 しかし自動生成されるリソース名は論理 ID を一定の桁数で切 り捨てるため、長すぎる論理 ID はリソース名を正しく表せないこ とがあります。 17

Slide 21

Slide 21 text

論理 IDは切り捨てられる CloudFormation の論理 ID は 255 文字まで指定可能です。 しかし自動生成されるリソース名は論理 ID を一定の桁数で切 り捨てるため、長すぎる論理 ID はリソース名を正しく表せないこ とがあります。 Construct IDを適切につけることで論理IDを短縮し、可読性の高いリ ソース名を生成しましょう 17

Slide 22

Slide 22 text

この10分で話すこと 1. 先に結論 2. CDKで定義したリソースの名前が決まる仕組み 3. 命名Tips4選 18

Slide 23

Slide 23 text

Construct ID は PascalCase で記述する 論理 ID 生成時に Construct ID に含まれる英数字以外の文字列は除去さ れます。 Construct ID は PascalCase で記述することで、リソース名の 可読性を高め、意図せぬ論理 ID 衝突を防ぐことができます。 ⭕️ Good ❌ Bad new sqs.CfnQueue(this, "MyQueue"); // 上位のConstruct IDと結合されて区切りがわかりづらくなる new sqs.CfnQueue(this, "myQueue"); // 以下は論理IDが衝突する new sqs.CfnQueue(this, "my-queue"); new sqs.CfnQueue(this, "myqueue"); 19

Slide 24

Slide 24 text

Construct ID に Construct や Stack とつけない Construct ID に Construct や Stack を含めると、CDK の世界で止める べき事情が Cfn テンプレート や AWS の世界に漏れてしまいます。 Construct のクラス名と同じ名前を Construct ID につけたくなった場 合、一歩踏みとどまって、論理 ID やリソース名に使われた時にどう見 えるかを考えて命名しましょう。 ⭕️ Good ❌ Bad new ApiConstruct(this, "Api"); new ApiConstruct(this, "ApiConstruct"); 20

Slide 25

Slide 25 text

親 コンストラクト で表している情報を繰り返さない 論理 ID は コンストラクト のパスツリーを結合して生成されます。 冗長さをなくしましょう。 ⭕️ Good // 親コンストラクトでの宣言 new ApiConstruct(this, "Api"); // ApiGatewayとRoleを定義するカスタムコンストラクト class ApiConstruct extends Construct { constructor(scope: Construct, id: string) { super(scope, id); const role = new iam.Role(this, "ExecutionRole"); // 省略 } } ❌ Bad // 親コンストラクトでの宣言 new ApiConstruct(this, "Api"); // ApiGatewayとRoleを定義するカスタムコンストラクト class ApiConstruct extends Construct { constructor(scope: Construct, id: string) { super(scope, id); const role = new iam.Role(this, "ApiExecutionRole"); // 省略 } } 21

Slide 26

Slide 26 text

親 コンストラクト で表している情報を繰り返さない 論理 ID は コンストラクト のパスツリーを結合して生成されます。 冗長さをなくしましょう。 ⭕️ Good new ApiConstruct(this, "Api"); const role = new iam.Role(this, "ExecutionRole"); // 親コンストラクトでの宣言 // ApiGatewayとRoleを定義するカスタムコンストラクト class ApiConstruct extends Construct { constructor(scope: Construct, id: string) { super(scope, id); // 省略 } } ❌ Bad // 親コンストラクトでの宣言 new ApiConstruct(this, "Api"); // ApiGatewayとRoleを定義するカスタムコンストラクト class ApiConstruct extends Construct { constructor(scope: Construct, id: string) { super(scope, id); const role = new iam.Role(this, "ApiExecutionRole"); // 省略 } } 21

Slide 27

Slide 27 text

親 コンストラクト で表している情報を繰り返さない 論理 ID は コンストラクト のパスツリーを結合して生成されます。 冗長さをなくしましょう。 ⭕️ Good new ApiConstruct(this, "Api"); const role = new iam.Role(this, "ExecutionRole"); // 親コンストラクトでの宣言 // ApiGatewayとRoleを定義するカスタムコンストラクト class ApiConstruct extends Construct { constructor(scope: Construct, id: string) { super(scope, id); // 省略 } } ❌ Bad // 親コンストラクトでの宣言 new ApiConstruct(this, "Api"); // ApiGatewayとRoleを定義するカスタムコンストラクト class ApiConstruct extends Construct { constructor(scope: Construct, id: string) { super(scope, id); const role = new iam.Role(this, "ApiExecutionRole"); // 省略 } } 21 論理ID:ApiExecutionRole

Slide 28

Slide 28 text

親 コンストラクト で表している情報を繰り返さない 論理 ID は コンストラクト のパスツリーを結合して生成されます。 冗長さをなくしましょう。 ⭕️ Good new ApiConstruct(this, "Api"); const role = new iam.Role(this, "ExecutionRole"); // 親コンストラクトでの宣言 // ApiGatewayとRoleを定義するカスタムコンストラクト class ApiConstruct extends Construct { constructor(scope: Construct, id: string) { super(scope, id); // 省略 } } ❌ Bad new ApiConstruct(this, "Api"); const role = new iam.Role(this, "ApiExecutionRole"); // 親コンストラクトでの宣言 // ApiGatewayとRoleを定義するカスタムコンストラクト class ApiConstruct extends Construct { constructor(scope: Construct, id: string) { super(scope, id); // 省略 } } 21 論理ID:ApiExecutionRole

Slide 29

Slide 29 text

親 コンストラクト で表している情報を繰り返さない 論理 ID は コンストラクト のパスツリーを結合して生成されます。 冗長さをなくしましょう。 ⭕️ Good new ApiConstruct(this, "Api"); const role = new iam.Role(this, "ExecutionRole"); // 親コンストラクトでの宣言 // ApiGatewayとRoleを定義するカスタムコンストラクト class ApiConstruct extends Construct { constructor(scope: Construct, id: string) { super(scope, id); // 省略 } } ❌ Bad new ApiConstruct(this, "Api"); const role = new iam.Role(this, "ApiExecutionRole"); // 親コンストラクトでの宣言 // ApiGatewayとRoleを定義するカスタムコンストラクト class ApiConstruct extends Construct { constructor(scope: Construct, id: string) { super(scope, id); // 省略 } } 21 論理ID:ApiExecutionRole 論理ID:ApiApiExecutionRole

Slide 30

Slide 30 text

Construct ID に Default と Resource を活用する DefaultとResourceはコンストラクトIDを短縮するための仕組みです。 共通の設定をあらかじめ入れてお くLambdaのカスタムコンストラ クトを例にします。 LambdaConstructは再利用を前 提に作られており、使用時に一意 に命名されることが期待されま す。 export class LambdaConstruct extends Construct { readonly function: nodejs.NodejsFunction; constructor(scope: Construct, id: string, props: LambdaConstructProps) { super(scope, id); this.function = new nodejs.NodejsFunction(this, "Resource", { functionName, handler: "handler", tracing: lambda.Tracing.ACTIVE, runtime: lambda.Runtime.NODEJS_20_X, timeout: Duration.seconds(5), memorySize: 1769, architecture: lambda.Architecture.ARM_64, ...props, }); } } 22

Slide 31

Slide 31 text

Construct ID に Default と Resource を活用する DefaultとResourceはコンストラクトIDを短縮するための仕組みです。 共通の設定をあらかじめ入れてお くLambdaのカスタムコンストラ クトを例にします。 LambdaConstructは再利用を前 提に作られており、使用時に一意 に命名されることが期待されま す。 this.function = new nodejs.NodejsFunction(this, "Resource", { export class LambdaConstruct extends Construct { readonly function: nodejs.NodejsFunction; constructor(scope: Construct, id: string, props: LambdaConstructProps) { super(scope, id); functionName, handler: "handler", tracing: lambda.Tracing.ACTIVE, runtime: lambda.Runtime.NODEJS_20_X, timeout: Duration.seconds(5), memorySize: 1769, architecture: lambda.Architecture.ARM_64, ...props, }); } } 22

Slide 32

Slide 32 text

Construct ID に Default と Resource を活用する Resource と Default は論理IDを生成する際に除去されます。 これにより、論理IDが短くなり可読部が増えます。 両者の違いについて、詳細は後述するブログに書いています。 ほとんどの場合では Resource を使っておけば無難です。 23

Slide 33

Slide 33 text

結論(再掲) Construct ID は scope の中で一意にする Construct ID は PascalCase で記述する Construct ID に Construct 、 Stack とつけない 親 コンストラクト で表している情報を繰り返さない Default と Resource を活用し Construct ID を短縮する 24

Slide 34

Slide 34 text

もっと詳しく知りたい方はブログを参照してください AWS CDK の Construct ID はどのように命名するべきか? 25

Slide 35

Slide 35 text

参考 [AWS CDK] Construct ID はパスカルケースで命名するのが良い CDK Tips: ID=Default の使い方 AWS CDK がデプロイするリソース名はどうやって決まるのか 26

Slide 36

Slide 36 text

27

Slide 37

Slide 37 text

28