App Runner上でのメトリックス監視のためのSpring BootとCloudWatchの設定

はじめに

先日、AWS App Runner上で動くコンテナ化したSpring Bootアプリケーションの可観測性に関する実装の一環でトレースをX-Rayに送ることを実装しました。

miyohide.hatenablog.com

ただ本番環境においてはトレースだけでは足りず、リクエスト数やJVMの状態などさまざまな情報が必要になります。App Runnerにおいては、リクエスト数などは特に何もしなくてもメトリックスタブから参照できます。

今回はJVMなどの各種情報をCloudWatchに送信するようにしてみます。

前提

今回の検証では以下のバージョンを使いました。

  • Java 21
  • Gradle 8.5
  • Spring Boot 3.2.2
  • Jib 3.4.0
  • AWS OpenTelemetry Agent 1.32.0

ライブラリの選定

Spring関連プロジェクトにて、AWSのマネージドサービスを扱うためのライブラリとしてSpring Cloud AWSというものがあります。

awspring.io

今回はこのSpring Cloud AWSを使います。

Spring Cloud AWSはSpring BootやSpring Frameworkのバージョンに応じて使用するバージョンが異なります。詳細は以下GitHubに記載があるので確認します。

github.com

今回はSpring Boot 3.2.2を使っているので、Spring Cloud AWS 3.1.xを使います。

実装

build.gradleでの実装方法はSpring Cloud AWSのドキュメントに書いている通りに従います。

docs.awspring.io

CloudWatchにメトリックスを送信するためには下記ドキュメントの通りio.micrometer:micrometer-registry-cloudwatch2も必要となります。

docs.awspring.io

具体的な実装は以下の通り。

// 省略
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    // Spring Cloud AWSを使用するための記述 ここから
    implementation platform("io.awspring.cloud:spring-cloud-aws-dependencies:3.1.0")
    implementation 'io.awspring.cloud:spring-cloud-aws-starter'
    implementation 'io.micrometer:micrometer-registry-cloudwatch2'
    // Spring Cloud AWSを使用するための記述 ここまで
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    javaAgent('software.amazon.opentelemetry:aws-opentelemetry-agent:1.32.0')
}

CloudWatchにメトリックスを送信するためには以下のドキュメントを参考にしながらapplication.propertiesに設定を記述します。

docs.awspring.io

今回は以下のように記述しました。

management.cloudwatch.metrics.export.enabled=true
management.cloudwatch.metrics.export.namespace=app/micrometer

なお、ネット上ではSpring Cloud AWS 2.xの情報が目につくのですが、Spring Cloud AWS 2.xと3.xにて幾らか変更点があるようです。以下のMigration Guideを確認すると良いかと思われます。

docs.awspring.io

AWSの設定

AWS App RunnerからCloudWatchにメトリックスを送信するためには、cloudwatch:PutMetricData権限が必要となります。今回、AWS App Runnerに付与しているIAMロールにインラインポリシーにて追加しました。

動作

以上の内容で各種メトリックスがCloudWatchに送信されます。「カスタム名前空間」にmanagement.cloudwatch.metrics.export.namespaceで設定していた値のものが作られていることが確認できます。

中身を確認すると、いろいろな情報が送信されています。

Javaアプリケーションに欠かせないヒープなどの情報は「area,id」のところにでていました。

GCの情報などは「action,cause,gc」のところにありました。

考察

ライブラリと少しの設定で各種メトリックスをCloudWatchに送信できるのは非常に有用です。何かトラブルが発生した時に情報が足りないとトラブル解決ができなくなることもあるので、設定しておいて損はないかと考えます。

一方で、CloudWatchは無料で使えるわけではないです。

aws.amazon.com

料金を踏まえて、取るメトリックを制限したい場合はapplication.propertiesに以下の記述をします。

# いったん全てのメトリックスの送信を止める
management.metrics.enable.all=false
# JVM関連だけを送信する
management.metrics.enable.jvm=true

また、Spring Cloud AWSの設定が間違っていてもSpring Bootアプリケーション自身は正常に動くのも注意が必要です。正常に動いているのでメトリックスも取れているだろうと思い込まずに実際に画面を見た方が良いと考えます。

AWS App Runner上での可観測性向上に向けた取り組み(Spring Bootを使った実装例)

はじめに

SREとして語られるものの一つに可観測性というものがあります。単純にログを吐けば良いというものから、どのようなリクエストが行われているのかや各種メトリックスなどの情報を取得することが必要となってきています。ここではAWS App Runner上で動くコンテナ化したSpring Bootアプリケーションの可観測性に関する実装を行なっていきます。

前提事項

今回の検証では以下のバージョンを使いました。

  • Java 21
  • Gradle 8.5
  • Spring Boot 3.2.2
  • Jib 3.4.0
  • AWS OpenTelemetry Agent 1.32.0

アプリケーションの実装

まずは、ライブラリとしてAWS OpenTelemetry Agentを使用します。

aws-otel.github.io

build.gradleに以下の記述を追加します。

dependencies {
    // 省略
    javaAgent 'software.amazon.opentelemetry:aws-opentelemetry-agent:1.32.0'
}

javaAgentという記述は、Gradleのconfigurationを使って依存性の管理をするように宣言しておきます。

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
    javaAgent
}

今回Jibを使ってコンテナイメージを作成するので、AWS OpenTelemetry Agentをコンテナイメージに取り込み、起動時にjavaagentオプションで指定する記述を追加してあげます。

task agentLibs(type: Copy) {
    from configurations.javaAgent.singleFile
    into 'myagent'
    rename 'aws-opentelemetry-agent-.*\\.jar', 'aws-opentelemetry-agent.jar'
}
jib.from.image = 'eclipse-temurin:21-jre'
jib.container.jvmFlags = ['-javaagent:./myagent/aws-opentelemetry-agent.jar']

jib {
    container {
        appRoot = '/app'
        workingDirectory = '/app'
        extraDirectories {
            paths {
                path {
                    from = './myagent'
                    into = '/app/myagent'
                }
            }
        }
    }
}

tasks.jibDockerBuild.dependsOn agentLibs

これでアプリケーション側の準備はOKです。

App Runnerの設定

App Runnerは2022年にX-Rayのサポートを開始しました。

aws.amazon.com

具体的な実装は、英語&Pythonの例ですが以下に記述があります。

aws.amazon.com

ポイントは、IAM Roleです。AWSXRayDaemonWriteAccessが付与されていないとX-Rayには何も表示されないので注意が必要です。

今回、Spring Boot 3.2を使うためにJava 21を使用しました。2024年1月時点でApp RunnerはJava 11までしかサポートしていないので、最新のSpring Bootを使いたい場合はアプリをコンテナ化する必要があります。

docs.aws.amazon.com

環境変数として以下を設定しておきます。

項目 備考
OTEL_PROPAGATORS xray
OTEL_METRICS_EXPORTER none App RunnerのOpenTelemetryサポートはメトリックスに未対応のため
OTEL_RESOURCE_ATTRIBUTES service.name=任意の名前

App Runnerの可観測性のトレースのスイッチをオンにすることも忘れずに。

実行

App Runnerにアプリをデプロイし、いくつかアクセスを行うとX-Rayにトレースやトレースマップが表示されます。

トレースには各リクエストごとにレスポンスコードや応答時間などが取られていることがわかります。

上はトレースマップ。単純な例なのであまり面白い結果ではないですが、どのようなサービスを利用しているかが図として表示されます。

考察

可観測性の重要性はよく語られますが、実際に実装しようとすると思いのほか面倒臭かったです。今回たまたまAWS OpenTelemetry Agentの存在を知り、動作させることを思い立ったのですが、Jibの設定が手間でした。

また、App RunnerのOpenTelemetryサポートはメトリックスに未対応ということもあったのが残念でした。ここについては、Spring Boot Actuatorで取れるのかなと思いますので、今後実装してみようかなと思います。

また、App RunnerがコードビルドとしてサポートしているJavaのバージョンが2024年1月時点では若干古い(Java 11まで)ので、最新のSpring Bootを使いたい場合はコンテナ化一択となる点も注意かなと考えました。

AWS CDKでリソースの構築とテストコードの書き方について

はじめに

最近はAWS CDKでリソースを構築することが多いのですが、AWS CDKは一般的なプログラミング言語AWSのリソースを定義するものなので、テストコードを書くことができます。そのテストコードの書き方についてまとめてみます。

前提条件

本記事は、以下の言語とAWS CDKのバージョンについて記しています。

  • TypeScript
  • AWS CDK 2.118.0

公式ドキュメント

AWS CDKの公式ドキュメントにテストについて記されたページがあるので目を通します。が、機械翻訳での提供なので、英語版を読んだ方が良いかもしれません。

docs.aws.amazon.com

テストのカテゴリ

上記公式ドキュメントに記されていますが、テストには以下2つのカテゴリがあるようです。

  • きめ細やかなアサーション(Fine-grained assertions)
    • AWS CDKが生成するCloudFormationの各種設定値が期待通りに生成されているかテストする
  • スナップショット(Snapshot test)
    • AWS CDKが生成するCloudFormationのテンプレートを以前のものと比較し、差分があるかをテストする

開発中は「きめ細やかなアサーション(Fine-grained assertions)」でテストを書いて、本番運用後は「スナップショット(Snapshot test)」を組み合わせる感じかなと考えました。

今回は「きめ細やかなアサーション(Fine-grained assertions)」の書き方について記します。

実装

cdk initにてプロジェクトを生成すると以下のようなサンプルテストコード込みで生成されるので、それを拡張するようにします。

// import * as cdk from 'aws-cdk-lib';
// import { Template } from 'aws-cdk-lib/assertions';
// import * as Cdk from '../lib/cdk-stack';

// example test. To run these tests, uncomment this file along with the
// example resource in lib/cdk-stack.ts
test('SQS Queue Created', () => {
//   const app = new cdk.App();
//     // WHEN
//   const stack = new Cdk.CdkStack(app, 'MyTestStack');
//     // THEN
//   const template = Template.fromStack(stack);

//   template.hasResourceProperties('AWS::SQS::Queue', {
//     VisibilityTimeout: 300
//   });
});

template変数を生成するまではいわゆるおまじないなので、ある程度コピペで。stack変数を生成するnew Cdk.CdkStack(app, 'MyTestStack');は適宜自分が生成したいStackに合わせて修正するぐらいです。

AWS CDKはCloudFormationを生成するので、CloudFormationの値が想定値と一致しているかどうかをテストするのが基本的な戦略になるかなと思います。AWS CDKのaws-cdk-lib.assertionsモジュールにて、各種Matcherの説明があるのでこれがテストコードの実装の拠り所になるかなと思います。

docs.aws.amazon.com

個人的には、以下のMatcherを使うことが多いです。

  • resourceCountIs
    • 対象のリソースが想定する数作成されるか
  • hasResourceProperties
    • 対象のリソースのプロパティが想定している値であるか
  • hasResource
    • 対象のリソースのプロパティ以外の設定(DeletionPolicyなど)の値が想定しているものか

繰り返しになりますが、AWS CDKはCloudFormationを生成するので、各種検証する値はCloudFormationのドキュメントも合わせて確認することになるかなと思います。

docs.aws.amazon.com

利用するサービスに対してCloudFormationの知識がないとテストも書きにくいと思います。この辺がちょっとハードルが高いかなと思いますが、一回ですべてを網羅するのは難しいので徐々に書き足す形が良いのかなと思っています。

なお、AWSの各種サービスは日々バージョンアップが行われ、AWS CDK自身も頻繁にバージョンアップされています。以下のページを見ると、1ヶ月に4回以上はザラにアップデートされています。

www.npmjs.com

CloudFormationのドキュメントにはあるのにAWS CDKにはない場合にはAWS CDKのバージョンアップを実施するとサクッと解決することが多いかなと思います。

実行

実行はnpm run testで実行できます。実行後、失敗するとどこで失敗したかがわかるように表示されます。ここらへんはJtestの機能です。

% npm run test

> cdk@0.1.0 test
> jest

 FAIL  test/cdk.test.ts
  ✕ ECRが1つ作成されること (82 ms)

  ● ECRが1つ作成されること

    Template has 1 resources with type AWS::ECR::Repository, but none match as expected.
    The 1 closest matches:
    Repository22E53BBD :: {
      "DeletionPolicy": "Delete",
      "Properties": {
    !!   Expected false but received true
        "EmptyOnDelete": true,
        "RepositoryName": "my-ruby-app"
      },
      "Type": "AWS::ECR::Repository",
      "UpdateReplacePolicy": "Delete"
    }

       9 |
      10 |   template.resourceCountIs('AWS::ECR::Repository', 1);
    > 11 |   template.hasResourceProperties('AWS::ECR::Repository', {
         |            ^
      12 |     RepositoryName: 'my-ruby-app',
      13 |     EmptyOnDelete: false,
      14 |   });

      at Template.hasResourceProperties (node_modules/aws-cdk-lib/assertions/lib/template.js:1:3101)
      at Object.<anonymous> (test/cdk.test.ts:11:12)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        1.696 s, estimated 2 s

成功すると、以下のように表示されます。

% npm run test            

> cdk@0.1.0 test
> jest

 PASS  test/cdk.test.ts
  ✓ ECRが1つ作成されること (83 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        1.712 s
Ran all test suites.

考察

AWS CDK自身は1ヶ月に複数回バージョンアップされています。クラウドの更新頻度を踏まえるとそれぐらいのバージョンアップは必然かなと思います。そのバージョンアップに追随するためにはテストコードを書くのは自然な発想と考えています。世の中、AWS CDKを使ってリソースを作ることは書かれていますが、テストコードの書き方は書かれていなかったので今回記事化しました。

実際には、AWS CDK、CloudFormation、Jestの知識がいるのでテストを書くとなるとハードルが高いなと感じます。ですが、一度に書き上げるのではなく徐々に作り上げていくとよいのかなと思いました。

ここで書いたのはあくまで基本的な記述方法で、上記のマニュアルにもいろんな検証方法が掲載されています。それらも実際の利用シーンとあわせて実装してみることが今後の課題です。

また、カバレッジを取得することはできないのかなと思ったりもしました。AWS CDKではそんなに複雑なことをしないケースがほとんどですのであまりニーズはないのかもしれません。

LambdaとRDSの連携をCDKで簡単実装する

はじめに

先日、Lambda上でコンテナイメージを動かしRDSに接続するということをやりました。

miyohide.hatenablog.com

このときは手作業でぽちぽちやりましたが、環境設定が面倒くさかったのでCDKで実装してみました。

VPCを作る

まずはVPCを作成します。こんな感じで。ちょっとでも料金節約のために、natGatewaysの数は1に設定します。

    // VPCの作成
    const vpc = new Vpc(this, "MyVPC", {
      enableDnsHostnames: true,
      enableDnsSupport: true,
      maxAzs: 2,
      natGateways: 1,
      subnetConfiguration: [
        {
          name: "PublicSubnet",
          subnetType: SubnetType.PUBLIC,
          cidrMask: 24,
          mapPublicIpOnLaunch: true,
        },
        {
          name: "PrivateSubnet",
          subnetType: SubnetType.PRIVATE_WITH_EGRESS,
          cidrMask: 24,
        },
        {
          name: "DBSubnet",
          subnetType: SubnetType.PRIVATE_ISOLATED,
          cidrMask: 24,
        }
      ]
    });

こんな感じでリソースが作られます。

作ってみて思いましたが、name属性にSubnetはいらなかったかなと思います。自動生成する名前にもSubnetがつくので冗長でした。

Lambdaを作る

コンテナイメージを作るLambdaを作成します。コンテナイメージはECRにあるので、こんな感じで実装します。

    // ECRのリポジトリを指定する
    const repository = Repository.fromRepositoryName(this, "MyRepository", "my-ruby-app");

    // Lambda用のセキュリティグループを作成する
    const lambdaSecurityGroup = new SecurityGroup(this, "LambdaSecurityGroup", {
      vpc: vpc,
      description: "Lambda Security Group",
      allowAllOutbound: true,
    });

    // ECRにあるコンテナイメージを利用してLambda関数を作成する
    const lambda = new Function(this, "Lambda", {
      code: Code.fromEcrImage(repository, {
        tag: "latest",
      }),
      functionName: "my-ruby-app",
      runtime: Runtime.FROM_IMAGE,
      handler: Handler.FROM_IMAGE,
      timeout: cdk.Duration.seconds(30),
      vpc: vpc,
      vpcSubnets: {
        subnetType: SubnetType.PRIVATE_WITH_EGRESS,
      },
      securityGroups: [lambdaSecurityGroup],
    });

既存のECRはRepository.fromRepositoryNameで取得できるので、それを使い、Functioncode属性にてCode.fromEcrImageにて対象のイメージを指定します。

RDSを作る

RDSを作成します。こんな感じで実装します。

    // RDS用のセキュリティグループの作成
    const rdsSecurityGroup = new SecurityGroup(this, "RDSSecurityGroup", {
      vpc: vpc,
      description: "RDS Security Group",
      allowAllOutbound: true,
    });

    const dbSubnetGroup = new SubnetGroup(this, "MyDBSubnetGroup", {
      vpc: vpc,
      description: "My DB Subnet Group",
      vpcSubnets: {
        subnetType: SubnetType.PRIVATE_ISOLATED,
        onePerAz: true,
      }
    });

    // RDSインスタンスの作成と設定を行う。今回はPostgreSQLを使用しているため、
    // DatabaseInstanceEngine.POSTGRESを指定する。
    const rdsInstance = new DatabaseInstance(this, "MyRDSInstance", {
      engine: DatabaseInstanceEngine.POSTGRES,
      instanceType: InstanceType.of(InstanceClass.T3, InstanceSize.MICRO),
      vpc: vpc,
      databaseName: "mypostgresdb",
      multiAz: false,
      subnetGroup: dbSubnetGroup,
      securityGroups: [rdsSecurityGroup],
    });

上記のCDK内でRDSのパスワードなどは指定していませんが、これらはSecret Managerに自動的に登録されます。

前回でのプログラムでは環境変数経由でユーザー名やパスワードの取得をしていましたが、Secret Managerから読み取らせる必要があります。実装についてはまた後日。

RDSの作成は、そこそこ時間がかかるのでのんびり待ちます。

セキュリティグループの設定

セキュリティグループの指定は以下の実装で適切なものが実装されます。

rdsInstance.connections.allowDefaultPortFrom(lambda, "Lambda to RDS");

おまけ

これでCDKで前回の環境を実装することができました。今回はテスト用だったので、一度動作確認をしたらcdk destroyで削除しようとしたのですが、実際の削除には30分ぐらい時間がかかりました。主な要因は、Lambdaが生成するネットワークインターフェースが20分ぐらい使っているという状況のまま消えなかったため。あまり気にせずにのんびり待ちます。

Lambdaで動くコンテナイメージ(Ruby)を作成し、RDS(PostgreSQL)と接続してみた

はじめに・動機

先日、RDS(PostgreSQL)に接続するLambda関数をRubyで実装しようとしたとき、pg gemの動作がうまく動きませんでした。このため、今回はLambda関数をコンテナイメージで動かすことをやってみます。

コンテナイメージを作る

AWSのドキュメントにLambda関数で動くコンテナイメージの作り方が記載されていたのでそれに従います。

docs.aws.amazon.com

ベースイメージとして、public.ecr.aws/lambda/ruby:3.2を使うのがポイントかと思います。pg gemを使いたいので、関連ライブラリをインストールする必要があります。実際に実装したDockerfileは以下のようなものになりました。

FROM public.ecr.aws/lambda/ruby:3.2

RUN yum install -y amazon-linux-extras && \
    amazon-linux-extras enable postgresql14 && \
    yum group install "Development Tools" -y

RUN yum install -y postgresql-devel

# Copy Gemfile and Gemfile.lock
COPY Gemfile Gemfile.lock ${LAMBDA_TASK_ROOT}/

# Install the specified gems
RUN bundle config set --local path 'vendor/bundle' && \
    bundle install

# Copy function code
COPY lambda_function.rb ${LAMBDA_TASK_ROOT}/

# Set the CMD to your handler (could also be done as a parameter override outside of the Dockerfile)
CMD [ "lambda_function.LambdaFunction::Handler.process" ]

必然的にコンテナイメージも大きくなります。マルチステージビルド化で多少小さくなるかもしれませんが、まずは動作確認のためにこのまま進めます。

コンテナイメージを作っておくと、ローカルで動作確認も取れます。docker runで動かして、別のターミナルからcurl "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}'を叩けばOK。今回は、以下のようなdocker-compose.ymlを作成してdocker compose upで起動して、

version: '3'
services:
  app:
    build: .
    image: my_lambda_app:0.0.1
    ports:
      - "9000:8080"
    environment:
      PG_HOSTNAME: db
      PG_USERNAME: "postgres"
      PG_PASSWORD: "postgres"

  db:
    image: postgres:15
    ports:
      - "5432:5432"
    environment:
      POSTGRES_USER: "postgres"
      POSTGRES_PASSWORD: "postgres"

先ほどのcurl "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}'を叩けば、動作確認も簡単にできました。

CodeBuildでコンテナイメージを作成し、ECRにpushする

次に、Lambda上で動かすことを考えます。CodeBuildでコンテナイメージを作成し、ECRにpushすることを実装します。

AWSのドキュメントにサンプルがあるのでそれをお手本に。

docs.aws.amazon.com

CodeBuildの作成時に、「特権付与」にチェックを入れるのを忘れずに。

また、ポリシーの追加も必要です。こんな感じで。

以下のbuildspec.ymlを作成してビルドを実行します。

version: 0.2

phases:
  pre_build:
    commands:
      - aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNTID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com
  build:
    commands:
      - docker build -t $IMAGE_REPO_NAME:$IMAGE_TAG .
      - docker tag $IMAGE_REPO_NAME:$IMAGE_TAG $AWS_ACCOUNTID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG
  post_build:
    commands:
      - docker push $AWS_ACCOUNTID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG

成功すると、作成していたECRにイメージがpushされています。

コンテナイメージをLambdaで動かす

あとはLambdaで動かします。Lambda作成時に「コンテナイメージ」を選択して、画面の指示通りに指定してあげればOK。

今回は、SELECT * FROM pg_stat_activityの結果を出力させるものを動かしました。RDSの接続設定をすれば、無事動くことが確認できました。

考察

今回の検証で、一番時間がかかったのはDockerfileの作成でした。ベースイメージのpublic.ecr.aws/lambda/ruby:3.2Amazon Linux 2ですのでgemのビルドに必要な前提ライブラリであるDevelopment Toolspostgresql-develを特定するのが一番時間がかかりました。特定さえできれば、あとはコピペで良いかなと考えています。

今回はRDS for PostgreSQLに接続することが目的でしたので、postgresql-develが前提ライブラリでしたが、RDS for MySQLなどはそれぞれ別の前提ライブラリが必要となることは注意点となります。

コンテナイメージを作ることでローカルでの動作確認が取れるというのは思わぬメリットでした。AWS上での開発も高速とはいえ、ローカルで動作させる速度には敵わないのでこれは大きなメリットかなと思います。

AWS Application ComposerのIDE拡張機能の試用と生成AIの挑戦

はじめに

AWS re:Invent 2023の内容を見てみると、AWS Application ComposerのIDE拡張機能が出たことを知りました。

aws.amazon.com

Application Composerはサーバーレスアプリケーションのインフラ部分を視覚的に作成できるサービスという説明が目についたのですが、個人的にはCloudFormationのテンプレート作成支援ツールって感じです。

aws.amazon.com

早速試してみました。

なお、このタイトルははてなブログのAI機能を使って生成してもらいました。

AWS Builder IDの作成

本件において必須ではありませんが、生成AIにIaCコードを生成させるためにAmazon CodeWhispererを使うことにします。そのためにはAWS Builder IDを作成します。AWS Builder ID profileに移動してAWS Builder IDを作成しておきます。

AWS Toolkit for Visual Studio Codeをインストールする

今回、Visual Studio CodeIDEとして使うため、その拡張機能であるAWS Toolkit for Visual Studio Codeをインストールします。

aws.amazon.com

Application Composerを操作する

適当なYAMLファイルを作成し、右クリックで「Open with Application Composer」を選択します。

すると以下のスクリーンショットのような画面が現れます。

拡張コンポーネントはかなり色々な設定項目をこの画面上で設定できます。以下はLambda関数の例。

他にも標準IaCリソースというものがあり、ここでは多くのリソースが用意されています。

標準IaCでは詳細な設定項目は用意されていません。リソース構成の部分でCloudFormationの内容を記述する感じです。

ここで「提案を生成」をクリックすると少し待った後に生成されます。

こんな感じでポチポチやれば、いつの間にかYAMLファイルが完成です。以下のものを作ってみました。

YAMLファイルは以下の通り。

Transform: AWS::Serverless-2016-10-31
Resources:
  Function:
    Type: AWS::Serverless::Function
    Properties:
      Description: !Sub
        - Stack ${AWS::StackName} Function ${ResourceName}
        - ResourceName: Function
      MemorySize: 1024
      Timeout: 30
      Tracing: Active
      PackageType: Image
      ImageUri: myrubyapp:0.0.1
  FunctionLogGroup:
    Type: AWS::Logs::LogGroup
    DeletionPolicy: Retain
    Properties:
      LogGroupName: !Sub /aws/lambda/${Function}
  Repository:
    Type: AWS::ECR::Repository
    Properties:
      RepositoryName: myrubyapp
      RepositoryPolicyText:
        Version: '2012-10-17'
        Statement:
          - Sid: AllowPushPull
            Effect: Allow
            Principal: '*'
            Action:
              - ecr:GetDownloadUrlForLayer
              - ecr:BatchGetImage
              - ecr:BatchCheckLayerAvailability
              - ecr:PutImage
              - ecr:InitiateLayerUpload
              - ecr:UploadLayerPart
              - ecr:CompleteLayerUpload
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsSupport: true
      EnableDnsHostnames: true
      InstanceTenancy: default
      Tags:
        - Key: Name
          Value: Primary_VPC
  PublicSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.0.0/24
      AvailabilityZone: !Select
        - 0
        - !GetAZs
          Ref: AWS::Region
  PrivateSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.1.0/24
      AvailabilityZone: !Select
        - 0
        - !GetAZs
          Ref: AWS::Region

生成AIのお約束ですが、完璧に正しいものがでてくるわけではないので過度な期待は危険かなと思います。とりあえず、よく使われるテンプレートが生成される感じです。このため、全くの初心者が生成AIでプロ並みにというわけではなく、ある程度わかっている人向けなのかなと感じました。

AWS LambdaからRDSへの接続設定が簡単になっていた

AWS LambdaからRDSへの接続設定をするのは地味に面倒くさいのですが、RDSのアクションメニューから「Lambda接続のセットアップ」から簡単に設定できるようになっていたので、試してみました。振り返ると2023年8月4日の更新が該当するようです。

aws.amazon.com

公式ドキュメントは以下のもの。

docs.aws.amazon.com

RDSのアクションから「Lambda接続のセットアップ」を選択して、画面の指示通りに入力したら作業は終わります。

が、私は以下の点でハマりました。

  • 既存のLambda関数はRDSと同じVPCに存在する必要があります。

Lambda関数をVPCに存在させるためには、以下のドキュメントを見ながら。

docs.aws.amazon.com

  • 新規にLambda関数を作成することもできるみたいですが、ランタイムはNode固定でした。
  • 最初はRubyPostgreSQLの構成で実行しようと思いましたが、実行時にcannot load such file -- pgが出力されて動かなかったので、諦めてJavaで書き直しました。
    • ちょっと検索してみると、以下のStackoverflowの記事に該当しそうなのですが、検証はできませんでした。

stackoverflow.com

設定画面に以下のような図が出て、これからやる内容が理解できます。