🏗️

『AWS CDK on Pulumi』でサーバーレス構成を作ってみて、AWS CDKのコードと比較してみる

2024/12/19に公開

この記事は 『AWS CDK Advent Calender 2024』 18日目の記事として書いています。

2024年12月2日に『AWS CDK on Pulumi』がGAしました。

https://www.pulumi.com/blog/aws-cdk-on-pulumi-1.0/

今回は『AWS CDK on Pulumi』を利用して、API Gateway & Lambda の構成を実装し、使用感を確かめてみようと思います!

※本記事では、主にリソース定義のコードを紹介します。初期設定など含めて以下の記事が詳しいので、ご参照ください。

https://dev.classmethod.jp/articles/aws-cdk-on-pulumi-ga/

実装紹介

API GatewayとLambda構成を作成しました。
いきなりですが、今回の実装を紹介します。

package.json
{
    "name": "pulumi-cdk-serverless",
    "main": "index.ts",
    "devDependencies": {
        "@types/node": "^18",
        "typescript": "^5.0.0",
        "esbuild": "^0.24.0"
    },
    "dependencies": {
        "@pulumi/aws": "^6.0.0",
        "@pulumi/awsx": "^2.0.2",
        "@pulumi/cdk": "^1.3.0",
        "@pulumi/docker-build": "^0.0.8",
        "@pulumi/pulumi": "^3.113.0",
        "aws-cdk-lib": "^2.173.2",
        "aws-lambda": "^1.0.7"
    }
}
index.ts
import * as pulumicdk from '@pulumi/cdk';
import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs';
import { Runtime } from 'aws-cdk-lib/aws-lambda';
import * as apigateway from 'aws-cdk-lib/aws-apigateway';
import { RemovalPolicy } from 'aws-cdk-lib';

class ServerlessApiStack extends pulumicdk.Stack {
    constructor(app: pulumicdk.App, id: string, options?: pulumicdk.StackOptions) {
        super(app, id, options);

        // Lambdaの定義
        const lambda = new NodejsFunction(this, 'handler', {
            entry: 'src/index.ts',
            handler: 'handler',
            runtime: Runtime.NODEJS_20_X,
        });


        // APIGatewayの定義
        const restApi = new apigateway.RestApi(
          this,
          'PulumiCdkRestApi',
          {
            defaultCorsPreflightOptions: {
              allowOrigins: apigateway.Cors.ALL_ORIGINS,
              allowMethods: apigateway.Cors.ALL_METHODS,
              allowHeaders: apigateway.Cors.DEFAULT_HEADERS,
            },
            cloudWatchRole: false,  // errorが出るため、Role作成は除外しました
          },
        );
        restApi.root
          .addResource('sample')
          .addMethod(
            'GET',
            new apigateway.LambdaIntegration(lambda, {
              proxy: true,
            }),
          );

    }
}

const app = new pulumicdk.App('app', (scope: pulumicdk.App) => {
    const stack = new ServerlessApiStack(app, 'ServerlessApiStack', {});
});

AWS CDKに慣れている方は気付いたと思います。ほとんどAWS CDKでの書き方同じように書けます。
Pulumiのコード内部で、aws-cdk-libのConstructを使えるため、同じ書き方ができます。

AWS CDKの書き方と並べて、異なる点も紹介しようと思います。

まずはStackクラスです。

index.ts(pulumi)
import * as pulumicdk from '@pulumi/cdk';
class ServerlessApiStack extends pulumicdk.Stack {
lib/hoge-stack.ts(cdk)
import {
  Stack
} from 'aws-cdk-lib';
class ServerlessApiStack extends Stack {

次に、Appクラスです。

index.ts(pulumi)
import * as pulumicdk from '@pulumi/cdk';
const app = new pulumicdk.App('app', (scope: pulumicdk.App) => {
    const stack = new ServerlessApiStack(app, 'ServerlessApiStack', {});
});
bin/hoge-app.ts(cdk)
import * as cdk from 'aws-cdk-lib';
import { ServerlessApiStack } from '../lib/hoge-stack';

const app = new cdk.App();
new ServerlessApiStack(app, 'ServerlessApiStack');

CDKではbin配下にapp定義用のファイルを配置しますが、Pulumiでは一緒になっているだけです。
どちらも@pulumi/cdkを利用しているだけで、大きな差はありません。

動作検証

デプロイし、動作を確認します。

pulumi up # Pulumiのデプロイコマンド

デプロイ結果はCLIで確認できます。
さらに、PulumiCloudを利用することでブラウザ上でも確認することができます。

curlで対象のAPI Gatewayの動作を確認します。

curl https://sampleId.execute-api.ap-northeast-1.amazonaws.com/prod/sample
{"message":"Hello AWS CDK on Pulumi"}

無事動作確認ができました。

所感

AWS CDKの知識を活かして実装ができる点は良かったです。
PulumiはAWS以外のリソースも定義できます。
CloudFlareAuth0といったサービスの定義・別クラウドサービスのリソース定義ができます。

AWS CDKしか触ったことのない人でも、Pulumiを使うことでAWSとAWS外のサービスのIaC構築にCDKの知識を活かせるのが良い点だと思います。
私は基本的にAWS環境で構築を行い、AWS外のサービスは手動で定義しています。AWS CDK on Pulumiを利用すれば学習コストを抑えて、全てIaCで定義することも出来そうです。

Pulumi特有のデプロイサイクルやコマンドを覚えるのは少し大変ですが、覚える価値はありそうです!

AWS CDKと同じ書き方が出来ることは分かったので、Pulumi側でどのようにAWS CDKのConstructを解釈しているのか、今後調べてみたいと思います!

Discussion