この記事はRust+SvelteKit+CDKでRSS要約アプリを作ってみる Advent Calendar 2025の6日目の記事になります。
また、筆者が属している株式会社野村総合研究所のアドベントカレンダーもあるので、ぜひ購読ください。
CDKとは
AWS公式が提供するIaCツールで、TypeScriptなどの一般的なプログラミング言語を使って宣言的にAWSリソースを定義し、そのコードからCloudFormationテンプレートを合成・デプロイできます。CloudFormationのYAML/JSONを直接管理するより、既存の言語資産やテスト手法を取り込める点が大きな魅力です。
CDKプロジェクトを初期化して環境を整える
今回利用するAWSインフラをCDKで定義していきます。まずはプロジェクト用のディレクトリを用意し、その中で初期化コマンドを叩きます。
mkdir cdk
cd cdk
cdk init app --language typescript
コマンド実行後は多数のファイルが生成されますが、実際にリソースを記述するのはlib/cdk-stack.ts(プロジェクト名に応じて変化)です。まずはここにスタックを定義していきます。
cdkコマンドを実行するディレクトリに応じて、生成されるファイル名は異なります。
スタック定義を追加したらcdk bootstrapを実行し、CDKが利用するS3バケットやIAMロールなどの下準備を整えます。まだ業務リソースは作成されず、これ以降のcdk deployで本番のスタックを構築する流れです。
基本スタックにLambda・DynamoDB・IAMロールを並べる
今回のRSS要約システムで最低限必要なリソースは、以下のとおりです。
- 記事取得用Lambda
- 要約用Lambda
- データを保持するDynamoDBテーブル
- 静的サイトをホスティングするS3(+Cloudfront)
- OpenRouterのAPIキーを格納するパラメータ(SSM)
- SQS
リソースの種類(例:Lambda、DynamoDB)ごとに指定できるオプションが大きく異なるため、必要な項目を公式ドキュメントと突き合わせながら丁寧に埋めていくのがポイントです。例えばDynamoDBであれば、パーティションキーや課金体系、GSIの設定などをコードに含められます。
例)記事テーブル
// 記事テーブルの定義
const articleDb = new cdk.aws_dynamodb.Table(this, "ArticleTable", {
partitionKey: {
name: "id",
type: cdk.aws_dynamodb.AttributeType.STRING,
},
removalPolicy: cdk.RemovalPolicy.DESTROY,
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
});
重要なのはリソース間の権限設計です。デフォルトではLambdaからDynamoDBへアクセスできないため、用途ごとに権限を付与します。CDKならリソースの参照を変数として保持できるので、以下のようにメソッド呼び出し一つでポリシーを紐付けられます。
// 各LambdaにDynamoDBの書き込み権限を付与
articleDb.grantReadWriteData(processorLambda);
feedDb.grantReadWriteData(collectorLambda);
articleDb.grantReadWriteData(collectorLambda);
スタック全体は下記のような構成になります(細部は割愛)。1スタックの中でS3やCloudFront、SSMパラメータ、Lambda、イベントソースを完結させられるのがCDKのメリットです。
export class CdkStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const param = ssm.StringParameter.fromSecureStringParameterAttributes(
this,
"OpenRouterApiKey",
// 中略
);
// 記事テーブルの定義
const articleDb = new cdk.aws_dynamodb.Table(this, "ArticleTable", {
// 中略
});
articleDb.addGlobalSecondaryIndex({
indexName: "ByDate",
// 中略
});
articleDb.addGlobalSecondaryIndex({
indexName: "BySource",
// 中略
});
articleDb.addGlobalSecondaryIndex({
indexName: "ByState",
// 中略
});
const feedDb = new dynamodb.Table(this, "FeedTable", {
// 中略
});
const websiteBucket = new s3.Bucket(this, "SumarssWebsiteBucket", {
// 中略
});
const distribution = new cdk.aws_cloudfront.Distribution(
this,
"SumarssDistribution",
// 中略
);
const articleBucket = new s3.Bucket(this, "SumarssArticleBucket", {
// 中略
});
const queue = new sqs.Queue(this, "ArticleProcessQueue", {
queueName: "article-process-queue",
// 中略
});
// RSSフィード収集Lambda
const collectorLambda = new RustFunction(this, "CollectorFunction", {
// 中略
});
// 記事処理Lambda
const processorLambda = new RustFunction(this, "ProcessorFunction", {
// 中略
});
// 各LambdaにDynamoDBの書き込み権限を付与
articleDb.grantReadWriteData(processorLambda);
feedDb.grantReadWriteData(collectorLambda);
articleDb.grantReadWriteData(collectorLambda);
queue.grantSendMessages(collectorLambda);
queue.grantConsumeMessages(processorLambda);
processorLambda.addEventSource(
// 中略
);
param.grantRead(processorLambda);
new events.Rule(this, "RssFeedScheduleRule", {
// 中略
});
articleBucket.grantWrite(collectorLambda);
articleBucket.grantRead(processorLambda);
}
}
合成からデプロイ、スタックのドリフト確認までの軽い運用
cdk CLIには多数のサブコマンドがありますが、日常的によく使うのは以下の3つです。
-
cdk synth: テンプレートを確認する。 -
cdk diff: 変更量を確認する。 -
cdk deploy: デプロイを実行する。
実際の開発現場ではdeployの前にsynthで生成テンプレートを確認し、diffで差分を把握してから適用するのが無難です。今回は個人開発でスピード重視のため、deployを中心に回していますが、チーム開発時はレビューと組み合わせると安心感が増します。
AWSコンソールなどで手動変更を加えると、スタック定義との乖離(ドリフト)が生じます。cdk drift detectionを実行すれば、CDKが認識している構成と実際のリソース状況との差分を検出できます。長期運用では定期的なドリフトチェックをジョブ化しておくと、意図しない変更を早期に把握できて便利です。
まとめ
基本フローは「スタック定義を編集して」「cdk deployで反映する」の繰り返しです。synthやdiff、ドリフト検知など周辺機能をパイプラインに織り込めば、IaCらしい堅牢な運用が実現できます。CDKをまだ触ったことがない方も、TypeScriptでインフラを組み立てられる体験をぜひ味わってみてください。