参考
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-code.html
AWSTemplateFormatVersion : '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: Sample Lambda Parameters: BucketName: Type: "String" #Default: !Sub 'my-cloudformation-templates-${AWS::AccountId}' # 文字列以外は指定できない BucketKey: Type: "String" #Default: !Sub "${AWS::StackName}.zip" # 文字列以外は指定できない Resources: SampleLambda: Type: "AWS::Lambda::Function" Properties: FunctionName: "CloudFormationLambda1" Description: "CloudFormationで作成したLambda1" Runtime: python3.6 MemorySize: 128 Timeout: 60 Handler: index.handler Code: S3Bucket: !Ref BucketName S3Key: !Ref BucketKey # ZipFile: コードを直接記述する事もできる(ただし最大4096文字) Role: !GetAtt SampleLambdaRole.Arn SampleLambdaRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole Path: / Policies: - PolicyName: SampleLambdaPolicy PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: # 必要な権限を記載 - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents Resource: '*'
build.sh
#!/bin/bash MODE=$1 echo "" # テンプレートファイル TEMPLATE=template.yml # スタック名 cd `dirname $0` STACK_NAME=`basename \`pwd\`` if [ -e ".git" ]; then STACK_NAME=`cat .git/config | grep url | head -1 | awk -F"/" '{print $NF}'` fi STACK_NAME=`echo $STACK_NAME | sed 's/_/-/g' | sed 's/Repo$/Stack/'` echo "Stack: ${STACK_NAME}" # アカウントIDの取得 ACCOUNT_ID=`aws sts get-caller-identity | grep Account | awk '{print $2}' | sed -e "s/[^0-9]//g"` # スタック作成時のイベント確認 if [ "${MODE}" == "desc" ]; then aws cloudformation describe-stack-events --stack-name $STACK_NAME exit 0 fi # 削除 if [ "${MODE}" == "del" ]; then aws cloudformation delete-stack --stack-name $STACK_NAME aws cloudformation wait stack-delete-complete --stack-name $STACK_NAME exit 0 fi # S3バケットがない場合は作る(バケット名は世界で唯一である必要がある為、末尾にアカウントID等を付与しておく) BUCKET_NAME=my-cloudformation-templates-${ACCOUNT_ID} BUCKET_COUNT=`aws s3api list-buckets | grep -e "\"${BUCKET_NAME}\"" | wc -l` if [ "${BUCKET_COUNT}" == "0" ]; then echo aws s3api create-bucket --create-bucket-configuration '{"LocationConstraint": "ap-northeast-1"}' --bucket $BUCKET_NAME fi # ソースコードをzip圧縮しS3にアップロード rm -rf src.zip cd src && zip ../src.zip * && cd ../ aws s3api put-object --bucket $BUCKET_NAME --key ${STACK_NAME}.zip --body src.zip # 検証&パッケージング&デプロイ aws cloudformation validate-template --template-body file://${TEMPLATE} \ && aws cloudformation package --template-file $TEMPLATE --s3-bucket $BUCKET_NAME --output-template-file packaged-template.yml \ && aws cloudformation deploy --template-file packaged-template.yml --parameter-overrides BucketName=${BUCKET_NAME} BucketKey=${STACK_NAME}.zip \ && --stack-name $STACK_NAME --capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM \ && echo ""
# デプロイ ./build.sh # テスト実行 aws lambda invoke --function-name CloudFormationLambda1 result.json && cat result.json && rm -rf result.json && echo ""
参考
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/transform-aws-serverless.html
https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
AWSTemplateFormatVersion : '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: Sample Lambda Resources: CloudFormationLambda2: # https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction Type: "AWS::Serverless::Function" Properties: FunctionName: CloudFormationLambda2 Description: "CloudFormationで作成したLambda2(AWS::Serverless変換)" Runtime: python3.6 Handler: index.handler # CodeUri に指定したパス配下がアップロードされる # ※S3のPATHを指定する事も可能。(自分でS3にアップロードする必要あり) # ※省略した場合はカレント配下のファイルが全てアップロード対象となる。 CodeUri: ./src MemorySize: 128 Timeout: 60 Role: !GetAtt CloudFormationLambda2Role.Arn CloudFormationLambda2Role: Type: "AWS::IAM::Role" Properties: RoleName: CloudFormationLambda2Role AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Principal: Service: "lambda.amazonaws.com" Action: "sts:AssumeRole" Policies: - PolicyName: "CloudFormationLambda2Policy" PolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents Resource: "*"
ソースコードのzip圧縮とS3アップロードを自前で行わなくて良いこと以外は、Serverless変換を使用しない場合とほぼ同じ。
build.sh
#!/bin/bash MODE=$1 echo "" # テンプレートファイル TEMPLATE=template.yml # スタック名 cd `dirname $0` STACK_NAME=`basename \`pwd\`` if [ -e ".git" ]; then STACK_NAME=`cat .git/config | grep url | head -1 | awk -F"/" '{print $NF}'` fi STACK_NAME=`echo $STACK_NAME | sed 's/_/-/g' | sed 's/Repo$/Stack/'` echo "Stack: ${STACK_NAME}" # アカウントIDの取得 ACCOUNT_ID=`aws sts get-caller-identity | grep Account | awk '{print $2}' | sed -e "s/[^0-9]//g"` # スタック作成時のイベント確認 if [ "${MODE}" == "desc" ]; then aws cloudformation describe-stack-events --stack-name $STACK_NAME exit 0 fi # 削除 if [ "${MODE}" == "del" ]; then aws cloudformation delete-stack --stack-name $STACK_NAME aws cloudformation wait stack-delete-complete --stack-name $STACK_NAME exit 0 fi # S3バケットがない場合は作る(バケット名は世界で唯一である必要がある為、末尾にアカウントID等を付与しておく) BUCKET_NAME=my-cloudformation-templates-${ACCOUNT_ID} BUCKET_COUNT=`aws s3api list-buckets | grep -e "\"${BUCKET_NAME}\"" | wc -l` if [ "${BUCKET_COUNT}" == "0" ]; then echo aws s3api create-bucket --create-bucket-configuration '{"LocationConstraint": "ap-northeast-1"}' --bucket $BUCKET_NAME fi # 検証&パッケージング&デプロイ aws cloudformation validate-template --template-body file://${TEMPLATE} \ && aws cloudformation package --template-file $TEMPLATE --s3-bucket $BUCKET_NAME --output-template-file packaged-template.yml \ && aws cloudformation deploy --template-file packaged-template.yml --stack-name $STACK_NAME --capabilities CAPABILITY_NAMED_IAM \ && echo ""
# デプロイ ./build.sh # テスト実行 aws lambda invoke --function-name CloudFormationLambda2 result.json && cat result.json && rm -rf result.json && echo ""
AWSTemplateFormatVersion : '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: "Sample API Gateway, Lambda" XXXX
AWS::Serverless 変換を使用しない場合と比べるとかなりシンプルに書ける。
AWSTemplateFormatVersion : '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: Test serverless application. Resources: SampleApi: Type: AWS::Serverless::Function Properties: FunctionName: CloudFormationApiLambda2 Description: "CloudFormationApiLambda2" Handler: index.handler Runtime: python3.6 CodeUri: ./src Events: ListApi: Type: Api Properties: Path: / Method: get GetApi: Type: Api Properties: Path: /{id} Method: get Role: !GetAtt CloudFormationApiLambda2Role.Arn CloudFormationApiLambda2Role: Type: "AWS::IAM::Role" Properties: RoleName: CloudFormationApiLambda2Role AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Principal: Service: "lambda.amazonaws.com" Action: "sts:AssumeRole" Policies: - PolicyName: "CloudFormationApiLambda2Policy" PolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents Resource: "*" Outputs: SampleBookApiUri: # 作成したAPIのURIをエクスポートしておく(AWS::Serverless::Function を使用した場合、ステージは Stage,Prod の2つが作成される) Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/" Export: Name: CloudFormationApiLambda2Uri
※実際の運用ではカスタムドメインを使用してベースパスマッピングを設定する事になるが、ここでは割愛する。(関連: CloudFormationでカスタムドメイン対応の API Gateway を作成する)