カテゴリー
Serverless FrameworkでもAWS で「APIGateway」→「VPC Lambda」→「EFS」を一発で構築してみる
※ 当ページには【広告/PR】を含む場合があります。
2023/04/20
2024/01/19
通常のSAMをServerless Framework(SLS)で一発構築
SLSをnodejsプロジェクトに導入する
yarn init
$ yarn add serverless -D
$ npx serverless --version
Framework Core: 3.38.0 (local)
Plugin: 7.2.0
SDK: 4.5.1
package.json
scripts
{
...
"scripts": {
"serverless": "serverless",
"sls": "sls",
...
},
...
}
handler.mjs
serverless.yml
$ touch handler.mjs serverless.yml
$ tree
.
├── package.json
├── handler.mjs
└── serverless.yml
SLSでLambdaをデプロイする
service: apigw-vpclmb-lab
frameworkVersion: '3'
provider:
name: aws
runtime: nodejs20.x
stage: dev
region: ap-northeast-1
package:
patterns:
- '!**'
- handler.mjs
functions:
hello:
handler: handler.handler
events:
- httpApi:
path: /
method: '*'
nodejs20
export const handler = async(event) => {
const response = {
statusCode: 200,
body: JSON.stringify('こんにちは!はじめてのVPC Lambda From Serverless!!'),
};
return response;
};
nodejs18
Commonjs
handler.js
ESModule
handler.mjs
$ npx sls deploy --verbose
$ npx sls invoke --function hello --verbose
{
"statusCode": 200,
"body": "\"こんにちは!はじめてのVPC Lambda From Serverless!!\""
}
$ curl -XGET https://*************.execute-api.ap-northeast-1.amazonaws.com/
"こんにちは!はじめてのVPC Lambda From Serverless!!"
Http API
1. serverless.ymlから.envファイルを使えるようにする
2. VPC Lambdaに対応したIAMロールを指定する
3. VPC Lambdaに必要な関数設定を作成する
4. リソースでVPCの設定(セキュリティグループ)を行う
5. リソースでEFSの設定(FS本体・マウントターゲット・アクセスポイント)を行う
VPC LambdaをServerlessでも一括構築する
serverless.yml
serverless.yml
service: apigw-vpclmb-lab
frameworkVersion: '3'
#👇解説ポイント①
useDotenv: true
provider:
name: aws
runtime: nodejs20.x
stage: dev
region: ap-northeast-1
#👇解説ポイント②
iam:
role: !Sub arn:aws:iam::${AWS::AccountId}:role/${env:LAMBDA_CUSTOM_ROLE}
package:
patterns:
- '!**'
- handler.mjs
functions:
hello:
handler: handler.handler
#👇解説ポイント③
environment:
EFS_MOUNT_DIR: ${env:EFS_MOUNT_DIR}
fileSystemConfig:
localMountPath: ${env:EFS_MOUNT_DIR}
arn: !GetAtt ["EFSAccessPoint", "Arn"]
vpc:
securityGroupIds:
- !GetAtt ["LambdaSecurityGroup", "GroupId"]
subnetIds:
- ${env:LAMBDA_SUBNET_ID}
dependsOn:
- EFSMountTargetA
- EFSMountTargetB
- EFSMountTargetC
events:
- httpApi:
path: /
method: '*'
resources:
Resources:
#👇解説ポイント④
LambdaSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
#GroupName: sg-lambda 👈 スタックエラーを起こすので、固定でグループ名を与えてはNG
GroupDescription: Lambda Access for EFS
VpcId: ${env:VPC_ID}
SecurityGroupIngress:
- IpProtocol: "-1"
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
IpProtocol: tcp
FromPort: 2049
ToPort: 2049
Tags:
- Key: Name
Value: LambdaEFSSecurityGroup
EFSSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
#GroupName: sg-efs 👈 スタックエラーを起こすので、固定でグループ名を与えてはNG
GroupDescription: EFS Allowed Ports
VpcId: ${env:VPC_ID}
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 2049
ToPort: 2049
SourceSecurityGroupId: !GetAtt ["LambdaSecurityGroup", "GroupId"]
Description: from Lambda
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
IpProtocol: "-1"
Tags:
- Key: Name
Value: EFSSecurityGroup
#👇解説ポイント⑤
EFSFileSystem:
Type: AWS::EFS::FileSystem
Properties:
FileSystemTags:
- Key: Name
Value: MyFileSystem
BackupPolicy:
Status: ENABLED
Encrypted: true
LifecyclePolicies:
- TransitionToIA: AFTER_30_DAYS
PerformanceMode: generalPurpose
#👇解説ポイント⑥
#MountTargetをアベイラビリティゾーンに全て置く場合には複数を個別に書く
EFSMountTargetA:
Type: AWS::EFS::MountTarget
Properties:
FileSystemId: !Ref EFSFileSystem
SecurityGroups:
- !Ref EFSSecurityGroup
SubnetId: ${env:LAMBDA_SUBNET_ID_1}
DependsOn: EFSFileSystem
EFSMountTargetB:
Type: AWS::EFS::MountTarget
Properties:
FileSystemId: !Ref EFSFileSystem
SecurityGroups:
- !Ref EFSSecurityGroup
SubnetId: ${env:LAMBDA_SUBNET_ID_2}
DependsOn: EFSFileSystem
EFSMountTargetC:
Type: AWS::EFS::MountTarget
Properties:
FileSystemId: !Ref EFSFileSystem
SecurityGroups:
- !Ref EFSSecurityGroup
SubnetId: ${env:LAMBDA_SUBNET_ID_3}
DependsOn: EFSFileSystem
#👇解説ポイント⑦
EFSAccessPoint:
Type: AWS::EFS::AccessPoint
Properties:
FileSystemId: !Ref EFSFileSystem
PosixUser:
Uid: "1001"
Gid: "1001"
RootDirectory:
Path: ${env:EFS_ROOT_DIR}
CreationInfo:
OwnerGid: "1001"
OwnerUid: "1001"
Permissions: "770"
AccessPointTags:
- Key: Name
Value: hello-func-ap
DependsOn: EFSFileSystem
解説ポイント① 〜 .envファイルで個人情報の漏洩をガードする
serverless
.envファイル
.env
HOGE_SECERT=hogeno_himitu
.env
serverless.yml
...
useDotenv: true
...
#👇ENV変数を呼び出す
USER: ${env:HOGE_SECERT}
.env
VPC_ID=vpc-<あなたのVPC ID>
AWS_REGION=ap-northeast-1
LAMBDA_SUBNET_ID_1=subnet-<1つ目のアベイラビリティゾーンのサブネットID>
LAMBDA_SUBNET_ID_2=subnet-<2つ目のアベイラビリティゾーンのサブネットID>
LAMBDA_SUBNET_ID_3=subnet-<3つ目のアベイラビリティゾーンのサブネットID>
EFS_MOUNT_DIR=/mnt/efs
EFS_ROOT_DIR=/hello-func
LAMBDA_CUSTOM_ROLE=my-vpclambda-efs-role
解説ポイント② 〜 登録済みのIAMロールをアタッチする
[provider] > [iam] > [role]
my-vpclambda-efs-role
...
provider:
...
iam:
role: !Sub arn:aws:iam::${AWS::AccountId}:role/${env:LAMBDA_CUSTOM_ROLE}
「!Sub」
${AWS::AccountId}
${env:LAMBDA_CUSTOM_ROLE}
!Sub
解説ポイント③ 〜 VPC Lambdaに仕上げる
fileSystemConfig
vpc
...
functions:
hello:
handler: handler.handler
#👇Lambdaが使う環境変数を登録
environment:
EFS_MOUNT_DIR: ${env:EFS_MOUNT_DIR}
#👇EFSの指定
fileSystemConfig:
localMountPath: ${env:EFS_MOUNT_DIR}
arn: !GetAtt ["EFSAccessPoint", "Arn"]
#👇VPC設定
vpc:
securityGroupIds:
- !GetAtt ["LambdaSecurityGroup", "GroupId"]
subnetIds:
- ${env:LAMBDA_SUBNET_ID}
#👇リソースへの依存性
dependsOn:
- EFSMountTargetA
- EFSMountTargetB
- EFSMountTargetC
#...
fileSystemConfig
vpc
+ LambdaSecurityGroup
+ EFSSecurityGroup
+ EFSFileSystem
+ EFSAccessPoint
+ EFSMountTargetA
+ EFSMountTargetB
+ EFSMountTargetC
dependsOn
dependsOn
[resources] > [Resources]
解説ポイント④ 〜 VPCのセキュリティグループを作成する
...
resources:
Resources:
LambdaSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
#GroupName: sg-lambda 👈 スタックエラーを起こすので、固定でグループ名を与えてはNG
GroupDescription: Lambda Access for EFS
VpcId: ${env:VPC_ID}
SecurityGroupIngress:
- IpProtocol: "-1"
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
IpProtocol: tcp
FromPort: 2049
ToPort: 2049
Tags:
- Key: Name
Value: LambdaEFSSecurityGroup
EFSSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
#GroupName: sg-efs 👈 スタックエラーを起こすので、固定でグループ名を与えてはNG
GroupDescription: EFS Allowed Ports
VpcId: ${env:VPC_ID}
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 2049
ToPort: 2049
SourceSecurityGroupId: !GetAtt ["LambdaSecurityGroup", "GroupId"]
Description: from Lambda
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
IpProtocol: "-1"
Tags:
- Key: Name
Value: EFSSecurityGroup
#...
LambdaSecurityGroup
EFSSecurityGroup
SecurityGroupIngress
SecurityGroupEgress
GroupName
解説ポイント⑤ 〜 EFSを準備する
EFSFileSystem
...
resources:
Resources:
#...
EFSFileSystem:
Type: AWS::EFS::FileSystem
Properties:
FileSystemTags:
- Key: Name
Value: MyFileSystem
BackupPolicy:
Status: ENABLED
Encrypted: true
LifecyclePolicies:
- TransitionToIA: AFTER_30_DAYS
PerformanceMode: generalPurpose
#...
解説ポイント⑥ 〜 マウントターゲットを作成する
DependsOn
EFSFileSystem
...
resources:
Resources:
#...
EFSMountTargetA:
Type: AWS::EFS::MountTarget
Properties:
FileSystemId: !Ref EFSFileSystem
SecurityGroups:
- !Ref EFSSecurityGroup
SubnetId: ${env:LAMBDA_SUBNET_ID_1}
DependsOn: EFSFileSystem
EFSMountTargetB:
Type: AWS::EFS::MountTarget
Properties:
FileSystemId: !Ref EFSFileSystem
SecurityGroups:
- !Ref EFSSecurityGroup
SubnetId: ${env:LAMBDA_SUBNET_ID_2}
DependsOn: EFSFileSystem
EFSMountTargetC:
Type: AWS::EFS::MountTarget
Properties:
FileSystemId: !Ref EFSFileSystem
SecurityGroups:
- !Ref EFSSecurityGroup
SubnetId: ${env:LAMBDA_SUBNET_ID_3}
DependsOn: EFSFileSystem
#...
解説ポイント⑦ 〜 アクセスポイントの追加
...
resources:
Resources:
#...
EFSAccessPoint:
Type: AWS::EFS::AccessPoint
Properties:
FileSystemId: !Ref EFSFileSystem
PosixUser:
Uid: "1001"
Gid: "1001"
RootDirectory:
Path: ${env:EFS_ROOT_DIR}
CreationInfo:
OwnerGid: "1001"
OwnerUid: "1001"
Permissions: "770"
AccessPointTags:
- Key: Name
Value: hello-func-ap
DependsOn: EFSFileSystem
EFSFileSystem
DependOn
デプロイと実行
$ npx sls deploy --verbose
Deploying apigw-vpclmb-lab to stage dev (ap-northeast-1)
#...スタックが沢山構成される
✔ Service deployed to stack apigw-vpclmb-lab-dev (113s)
endpoint: ANY - https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/
functions:
hello: apigw-vpclmb-lab-dev-hello (79 kB)
Stack Outputs:
HelloLambdaFunctionQualifiedArn: arn:aws:lambda:ap-northeast-1:123456789012:function:apigw-vpclmb-lab-dev-hello:1
HttpApiId: xxxxxxxxxx
ServerlessDeploymentBucketName: apigw-vpclmb-lab-dev-serverlessdeploymentbucket-xxxxxxxxxxxx
HttpApiUrl: https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com
sls invoke
$ npx sls invoke --function hello --verbose
{
"statusCode": 200,
"body": "\"こんにちは!はじめてのVPC Lambda From Serverless!!\""
}
curl
$ curl -XGET https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com
{
"statusCode": 200,
"body": "\"こんにちは!はじめてのVPC Lambda From Serverless!!\""
}
まとめ
1. serverless.ymlから.envファイルを使えるようにする
2. VPC Lambdaに対応したIAMロールを指定する
3. VPC Lambdaに必要な関数設定を作成する
4. リソースでVPCの設定(セキュリティグループ)を行う
5. リソースでEFSの設定(FS本体・マウントターゲット・アクセスポイント)を行う
参考サイト
記事を書いた人
ナンデモ系エンジニア
主にAngularでフロントエンド開発することが多いです。 開発環境はLinuxメインで進めているので、シェルコマンドも多用しております。 コツコツとプログラミングするのが好きな人間です。
カテゴリー