はじめに
KG-7thの槙島です。
以前作成したTypeScriptベースのWebAPIをリメイクして手早く公開したいです。
調べてみてHonoフレームワークが一番適していると感じたため、試してみました。
Honoのセットアップ
たま~に聞くHonoフレームワーク。
どうやら爆速で開発できるみたいなのでやってみよう。
注意
デプロイでDockerが必要になるので、自分はVirtulBoxのUbuntuで実施してます。
aws configure ssoで認証情報を設定済みです。多分これしないとデプロイできないです。
AWS CDK CLIをインストール
Honoライブラリの手順の中で出てきた。便利そうなのでこの機会に入れてみる
# インストール
npm install -g aws-cdk
# CDKのAWS環境内のセットアップ
cdk bootstrap
lambda関数のテンプレを生成
cdk init app -l typescript
Honoのインストール
npm i hono
Lambda実行ファイルの作成
mkdir lambda
lambdaフォルダの中にindex.tsを作成
index.tsの中身
import { Hono } from 'hono'
import { handle } from 'hono/aws-lambda'
const app = new Hono()
app.get('/', (c) => c.text('Hello Hono!'))
export const handler = handle(app)
lib/ans-automate-stack.tsの中身
import * as path from 'path';
import * as cdk from 'aws-cdk-lib'
import { Construct } from 'constructs'
import * as lambda from 'aws-cdk-lib/aws-lambda'
import * as apigw from 'aws-cdk-lib/aws-apigateway'
import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs'
export class SnsAutomateStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props)
// Lambda Layerの作成 (assets を指定)
const layer = new lambda.LayerVersion(this, 'arn:aws:lambda:ap-northeast-1:123456789012:layer:SnsAutomateLayer:2', {
code: lambda.Code.fromAsset(path.join(__dirname, '../assets')),
compatibleRuntimes: [lambda.Runtime.NODEJS_20_X], // Node.jsランタイムを指定
description: 'Lambda Layer for SNS Automate project',
});
const fn = new NodejsFunction(this, 'lambda', {
functionName: "SnsAutomateFunction",
entry: 'src/index.ts',
handler: 'handler',
runtime: lambda.Runtime.NODEJS_20_X,
layers: [layer], // 作成したレイヤーを追加
timeout: cdk.Duration.seconds(20), // 少し長め
memorySize: 256, // 128だと動かなかった
role: cdk.aws_iam.Role.fromRoleArn(this, 'SnsAutomateFunctionRole', 'arn:aws:iam::123456789012:role/SnsAutomateFunctionRole'),
environment: {
ROOT_URL: '/opt', // レイヤー内のアセットを参照するために設定
},
})
fn.addFunctionUrl({
authType: lambda.FunctionUrlAuthType.NONE,
})
new apigw.LambdaRestApi(this, 'myapi', {
handler: fn,
})
// CloudWatch Eventsルールを作成
new cdk.aws_events.Rule(this, 'SnsAutomateWeatherTweetScheduleRule', {
ruleName: "SnsAutomateWeatherTweetScheduleRule",
// 毎朝7時に実行
schedule: cdk.aws_events.Schedule.cron({ minute: '0', hour: '22' }),
targets: [new cdk.aws_events_targets.LambdaFunction(fn)],
});
}
}
Lambda Layerについて
画像やフォントなどの静的ファイルはそのままデプロイしてもついてきません。
Layerに入れることでLambda関数から扱うことができます。
今回はすでに作成済みのため、作成したLayerのARNを指定しています
(デプロイすることでLayerに静的ファイルがアップロードされるみたい)
const layer = new lambda.LayerVersion(this, 'arn:aws:lambda:ap-northeast-1:123456789012:layer:SnsAutomateLayer:2', {
なお、まだ作成していない場合は適当な名前を入れるとLayerが作成されます
const layer = new lambda.LayerVersion(this, 'SnsAutomateLayer', {
関数にアタッチするロールについて
SnsAutomateFunctionRoleには以下のポリシーを許可しています。
SSMでパラメタを取得してきているのでSSMのread用のパーミッションを、
Cloudwatchのログを確認したいのでBasicExecute・・・を適用しています。
関数に紐づけているのは以下の箇所です。
role: cdk.aws_iam.Role.fromRoleArn(this, 'SnsAutomateFunctionRole', 'arn:aws:iam::123456789012:role/SnsAutomateFunctionRole'),
デプロイ
cdk deploy
デプロイ成功!
出てきたURLにアクセスして問題ないことを確認
結論
早い・・・
RemixのLambda-web-adapterで右往左往していた時の30倍は早いぞ・・・
今回のコードはこちら
これから使っていく予定なので、コミットのURLを載せておきます。。
感想
CDKを使ったので、裏側で何が起きてるのか正直よくわかってない。
これからドキュメント見直してみます。
ところで、これ別の端末からデプロイしたら別のLambda関数としてデプロイされてしまうのでは。。
追記
気になったところをperplexityに聞いてみた
質問①
この場合、環境変数はどこで管理すればよいでしょうか?
回答
CDKで環境変数を管理する主な方法は3通りあります:
- CDKスタック内での直接設定(非機密情報向け)
const fn = new NodejsFunction(this, 'lambda', {
entry: 'lambda/index.ts',
environment: {
API_KEY: 'your_api_key',
STAGE: 'production'
}
});
- AWS Systems Manager Parameter Store(推奨)
import * as ssm from 'aws-cdk-lib/aws-ssm';
const fn = new NodejsFunction(this, 'lambda', {
entry: 'lambda/index.ts',
environment: {
DB_PASSWORD: ssm.StringParameter.valueForStringParameter(this, '/config/DB_PASSWORD'),
}
});
- AWS Secrets Manager(機密情報向け)
import * as secrets from 'aws-cdk-lib/aws-secretsmanager';
const secret = secrets.Secret.fromSecretNameV2(this, 'Secret', 'my-secret');
const fn = new NodejsFunction(this, 'lambda', {
entry: 'lambda/index.ts',
environment: {
SECRET_VALUE: secret.secretValue.toString(),
}
});
質問②
デプロイ時のLambdaの設定
(なんという名前の関数としてデプロイするのか、どのVPCに接続するのかなど)を行うにはどうすればよいですか?
回答
CDKスタックの設定例:
import * as ec2 from 'aws-cdk-lib/aws-ec2';
const fn = new NodejsFunction(this, 'lambda', {
entry: 'lambda/index.ts',
functionName: 'MyHonoFunction', // 関数名指定
runtime: lambda.Runtime.NODEJS_20_X,
memorySize: 512, // メモリサイズ
timeout: cdk.Duration.seconds(10), // タイムアウト
architecture: lambda.Architecture.ARM_64, // ARMアーキテクチャ
// VPC設定
vpc: ec2.Vpc.fromLookup(this, 'VPC', { vpcId: 'vpc-12345' }),
vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS },
securityGroups: [/* セキュリティグループ配列 */]
});
主要な設定項目:
- プロパティ 説明 デフォルト値
- functionName Lambda関数名 CDK自動生成
- memorySize メモリ割当量(MB) 128
- timeout 実行制限時間 3秒
- architecture CPUアーキテクチャ X86_64
- vpc 接続するVPC なし
- securityGroups 適用するセキュリティグループ 自動生成
- ベストプラクティス:
- 関数名はfunctionNameで明示的に指定(CDKの自動生成名は可変)
VPC接続時はPrivate Subnet + NAT Gateway構成を推奨
開発環境と本番環境で設定を分ける場合:
const isProduction = process.env.STAGE === 'production';
new NodejsFunction(this, 'lambda', {
memorySize: isProduction ? 1024 : 256,
timeout: isProduction ? 30 : 10
});
補足
記事のサンプルコードを拡張する場合は、CDKスタックファイル(lib/*-stack.ts)のLambda関数定義部分を修正します。デプロイ時はcdk deployを再実行すれば、変更内容が自動反映されます。
とのこと。まだ試してないので参考程度に。