Slide 1

Slide 1 text

JAWS-UG 茨城 #11 CDK 支部コラボ回 2026/2/1 Shota Kawasaki なぜconsole.log はToken になるのか? もうハマらないためにToken をちゃんと理解する

Slide 2

Slide 2 text

出身: 千葉県 所属: SIer 年次: 1 年目(CDK 利用歴半年) 好きなサービス: CDK, Kiro : @kawaaaas Shota Kawasaki

Slide 3

Slide 3 text

CDK を学び始めて約半年、 難しいことがたくさんあります

Slide 4

Slide 4 text

CDK を学び始めて約半年、 難しいことがたくさんあります Stack 間の値の受け渡しが うまくいかなかったり...

Slide 5

Slide 5 text

CDK を学び始めて約半年、 難しいことがたくさんあります 循環参照に陥って、 deploy ができなかったり... Stack 間の値の受け渡しが うまくいかなかったり...

Slide 6

Slide 6 text

CDK を学び始めて約半年、 難しいことがたくさんあります リソースのID が変わって リソースが再作成されてしまったり... 循環参照に陥って、 deploy ができなかったり... Stack 間の値の受け渡しが うまくいかなかったり...

Slide 7

Slide 7 text

CDK を学び始めて約半年、 難しいことがたくさんあります リソースのID が変わって リソースが再作成されてしまったり... 循環参照に陥って、 deploy ができなかったり... Stack 間の値の受け渡しが うまくいかなかったり... 中でも頻繁にやってしまうことは...

Slide 8

Slide 8 text

つい、普通の開発と同様に 文字列比較したり、console 出力してしまいがち

Slide 9

Slide 9 text

何度も値の扱いでハマる全私に向けて Token について整理しました

Slide 10

Slide 10 text

console.log() ではバケット名がToken と出力される

Slide 11

Slide 11 text

console.log() ではバケット名がToken と出力される 本来であれば物理名を指定することは望ましく ないですが、説明の都合上指定しています

Slide 12

Slide 12 text

Token とは何か? コンストラクトの定義やスタックの合成時にわからない 値のプレースホルダー 実際のインフラストラクチャが作成されると、これらの 値はデプロイ時に実際の値に展開される (公式ドキュメントより) https://docs.aws.amazon.com/ja_jp/cdk/v2/guide/tokens.html

Slide 13

Slide 13 text

cdk synth 時 cdk deploy 時 なぜToken が必要か Cfn テンプレート時点では まだリソースが存在しない Cfn がリソースを作成して はじめてarn やID が確定 「まだ決まっていない値」をTypeScript として 扱うために、仮の値を埋め込んでおく必要がある。 これがToken

Slide 14

Slide 14 text

Construct Prepare Validate Synthesize CDK のアプリケーションライフサイクル CDK App Deploy Cfn

Slide 15

Slide 15 text

Construct Prepare Validate Synthesize CDK のアプリケーションライフサイクル CDK App Deploy Cfn TypeScript コードのほとんどはConstruct フェーズで実行され、実際にToken が生成される 生成されたToken が解決され、 Cfn に展開される

Slide 16

Slide 16 text

物理名を指定してCfn に出力されていても、 TS 上ではToken として扱われる Construct

Slide 17

Slide 17 text

参照では「確定していない値」が渡される 入力値→ 指定したbucketName(physicalName) が渡される 参照値→ 指定したbucketName に関わらず、参照を渡す /packages/aws-cdk-lib/aws-s3/lib/bucket.ts Construct

Slide 18

Slide 18 text

ref ではToken クラスのメソッドを叩き、 トークンエンコーディングが行われる bucketName() がToken を返す仕組み /packages/aws-cdk-lib/aws-s3/lib/bucket.ts /packages/aws-cdk-lib/core/lib/cfn-element.ts Construct

Slide 19

Slide 19 text

Token クラスはStatic Methods を提供する ユーティリティクラス Construct Token.isUnresolved(bucketName) にてトークンであるかを検証する Token クラス /packages/aws-cdk-lib/core/lib/token.ts トークンエンコーディング用メソッド

Slide 20

Slide 20 text

トークンエンコーディング IResolvable の可能性がある値を TS で扱えるようにプリミティブ型のToken にする技術 Construct Token.asString(value) →${TOKEN[Bucket.Name.1234]} Token.asNumber(value) →-1.8881545897087626e+289 Token.asList(value) →["#{TOKEN[Stack.NotificationArns.1234]}"]

Slide 21

Slide 21 text

IResolvable インターフェイス 遅延評価される値を表現するためのインターフェース /packages/aws-cdk-lib/core/lib/resolvable.ts IResolvable な値は resolve メソッドを定義する Construct

Slide 22

Slide 22 text

トークンエンコーディング時にIResolvable な値は Map で保持され、synth 時に展開されることに よってCloudFormation に埋め込まれる TokenMap によるIResolvable な値の保持 /packages/aws-cdk-lib/core/lib/private/token-map.ts Construct

Slide 23

Slide 23 text

Synthesize CfnReference がresolve される /packages/aws-cdk-lib/core/lib/private/cfn-reference.ts Synthesize フェーズではTS がCfn に変換されるため、 検知されたToken もTokenMap によってIResolvable な値が 取り出され、Cfn に解決される Intrinsic クラスを継承しており、Intrinsic クラスのresolve メソッドを実行する

Slide 24

Slide 24 text

Synthesize Intrinsic クラス packages/aws-cdk-lib/core/lib/private/intrinsic.ts Cfn テンプレートに最終的に出力される値を表す トークンの基底クラス 解決時にはすでに保持しているCfn 形式の値をそのまま出力する

Slide 25

Slide 25 text

結局、Token に対して文字列操作したい時はどうする? Fn 組み込み関数を利用する CloudFormation に埋め込まれ、deploy 時に解決される Fn.join(delimiter, values)→ 文字列を結合 Fn.split(delimiter, string)→ 文字列を分割 Fn.select(index, array)→ 配列から要素を選択 Fn.sub(template, variables)→ テンプレート文字列を置換

Slide 26

Slide 26 text

遅延処理を実現するLazy 指定した時点では決定させず、 synth 完了時に値を解決させるための機能 Lazy.string() で呼び出し時点では値が 未確定であるが最終的には確定する

Slide 27

Slide 27 text

Lazy の仕組み 内部ではトークンエンコーディングの仕組みが 用いられている Token.asString(value) にてIResolvable の 可能性がある値をTS のプリミティブ型にする

Slide 28

Slide 28 text

これでもうToken でハマることはない( はず) CDK は面白い。 これからももっと勉強していきます!