こんにちは、SCSK の広野です。
私は Amazon API Gateway と AWS Lambda 関数の CI/CD を学習する社内研修を開催しておりまして、研修用 CI/CD パイプラインを AWS Code シリーズのサービスと AWS SAM (Serverless Application Model)、AWS CloudFormation で作成しています。
本記事では、その環境を抜粋して AWS CloudFormation でデプロイできるようにしたものを紹介します。
アーキテクチャ
以下のように、AWS サービスを組み合わせて作成しています。
- 開発環境は AWS Cloud9 を使用。
- ソースコード管理に AWS CodeCommit を使用。Lambda 関数コードだけでなく、ビルド設定ファイル buildspec.yml と AWS SAM テンプレートファイル template.yml もセットで管理する。
- コードの変更検知に Amazon EventBridge を使用。AWS CodeCommit のソースコードが変更されると CI/CD パイプラインを開始させる。
- CI/CD パイプラインに AWS CodePipeline を使用。ビルドステージで AWS CodeBuild、AWS SAM を、デプロイステージで AWS CloudFormation を使用。AWS SAM で API Gateway と Lambda 関数をデプロイする。
- パイプラインの各ステージで作成される成果物 (アーティファクト) 置き場に Amazon S3 を使用。
※図は簡略化していますが 2つのバケットがあります。SAM テンプレート (API Gateway と Lambda 関数リソース作成) と Lambda 関数コードの ZIP で。
CI/CD パイプライン準備
CI/CD パイプラインは、以下の AWS CloudFormation テンプレートを流すことでデプロイできます。※ Cloud9 や VPC は除く
AWSTemplateFormatVersion: 2010-09-09 Description: The CloudFormation template that creates a S3 bucket, a CI/CD environment with Code service series, and relevant IAM roles. Parameters: # ------------------------------------------------------------# # Input Parameters # ------------------------------------------------------------# YourID: Type: String Description: Please fill your full name and today's date, or another unique name. (e.g. yujihirono20231202) You can not use any upper cases and special characters. MaxLength: 100 MinLength: 5 Resources: # ------------------------------------------------------------# # CodeCommit Repository # ------------------------------------------------------------# SampleProjectRep: Type: AWS::CodeCommit::Repository Properties: RepositoryName: !Sub SampleProject-${YourID} Tags: - Key: Cost Value: !Ref YourID # ------------------------------------------------------------# # EventBridge Rule for Starting CodePipeline # ------------------------------------------------------------# SampleProjectRepPipelineEventsRule: Type: AWS::Events::Rule Properties: Name: !Sub SampleProject-StartPipelineRule-${YourID} EventBusName: !Sub "arn:aws:events:${AWS::Region}:${AWS::AccountId}:event-bus/default" EventPattern: source: - aws.codecommit resources: - !GetAtt SampleProjectRep.Arn detail-type: - "CodeCommit Repository State Change" detail: event: - referenceCreated - referenceUpdated referenceName: - master State: ENABLED Targets: - Arn: Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":codepipeline:" - Ref: AWS::Region - ":" - Ref: AWS::AccountId - ":" - Ref: Pipeline Id: Target0 RoleArn: !GetAtt PipelineEventsRole.Arn DependsOn: - PipelineEventsRole - Pipeline # ------------------------------------------------------------# # CodeBuild Project Role (IAM) # ------------------------------------------------------------# BuildProjectRole: Type: AWS::IAM::Role Properties: RoleName: !Sub BldPrjRole-${YourID} AssumeRolePolicyDocument: Statement: - Action: sts:AssumeRole Effect: Allow Principal: Service: codebuild.amazonaws.com Version: "2012-10-17" # ------------------------------------------------------------# # CodeBuild Project Role Policy (IAM) # ------------------------------------------------------------# BuildProjectRoleDefaultPolicy: Type: AWS::IAM::Policy Properties: PolicyName: !Sub BldPrjRolePolicy-${YourID} PolicyDocument: Statement: - Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents Effect: Allow Resource: - Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":logs:" - Ref: AWS::Region - ":" - Ref: AWS::AccountId - :log-group:/aws/codebuild/ - Ref: BuildProject - :* - Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":logs:" - Ref: AWS::Region - ":" - Ref: AWS::AccountId - :log-group:/aws/codebuild/ - Ref: BuildProject - Action: - codebuild:BatchPutCodeCoverages - codebuild:BatchPutTestCases - codebuild:CreateReport - codebuild:CreateReportGroup - codebuild:UpdateReport Effect: Allow Resource: Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":codebuild:" - Ref: AWS::Region - ":" - Ref: AWS::AccountId - :report-group/ - Ref: BuildProject - -* - Action: s3:PutObject Effect: Allow Resource: Fn::Join: - "" - - !GetAtt PipelinePackageBucket.Arn - /* - Action: - s3:Abort* - s3:DeleteObject* - s3:GetBucket* - s3:GetObject* - s3:List* - s3:PutObject - s3:PutObjectLegalHold - s3:PutObjectRetention - s3:PutObjectTagging - s3:PutObjectVersionTagging Effect: Allow Resource: - !GetAtt PipelineArtifactBucket.Arn - Fn::Join: - "" - - !GetAtt PipelineArtifactBucket.Arn - /* Version: "2012-10-17" Roles: - Ref: BuildProjectRole DependsOn: - BuildProjectRole - PipelineArtifactBucket - PipelinePackageBucket # ------------------------------------------------------------# # CodeBuild Project # ------------------------------------------------------------# BuildProject: Type: AWS::CodeBuild::Project Properties: Name: !Sub SampleProjectBuild-${YourID} Artifacts: Type: CODEPIPELINE Environment: ComputeType: BUILD_GENERAL1_SMALL EnvironmentVariables: - Name: S3_BUCKET Type: PLAINTEXT Value: Ref: PipelinePackageBucket Image: "aws/codebuild/standard:7.0" ImagePullCredentialsType: CODEBUILD PrivilegedMode: false Type: LINUX_CONTAINER ServiceRole: !GetAtt BuildProjectRole.Arn Source: Type: CODEPIPELINE Cache: Type: NO_CACHE Tags: - Key: Cost Value: !Ref YourID DependsOn: - BuildProjectRole # ------------------------------------------------------------# # CodePipeline Build Package Bucket (S3) # ------------------------------------------------------------# PipelinePackageBucket: Type: AWS::S3::Bucket Properties: BucketName: !Sub codepipeline-package-${YourID} PublicAccessBlockConfiguration: BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true Tags: - Key: Cost Value: !Ref YourID # ------------------------------------------------------------# # CodePipeline Artifact Bucket (S3) # ------------------------------------------------------------# PipelineArtifactBucket: Type: AWS::S3::Bucket Properties: BucketName: !Sub codepipeline-artifact-${YourID} PublicAccessBlockConfiguration: BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true Tags: - Key: Cost Value: !Ref YourID # ------------------------------------------------------------# # CodePipeline Role (IAM) # ------------------------------------------------------------# PipelineRole: Type: AWS::IAM::Role Properties: RoleName: !Sub PlRole-${YourID} AssumeRolePolicyDocument: Statement: - Action: sts:AssumeRole Effect: Allow Principal: Service: codepipeline.amazonaws.com Version: "2012-10-17" # ------------------------------------------------------------# # CodePipeline Role Policy (IAM) # ------------------------------------------------------------# PipelineRoleDefaultPolicy: Type: AWS::IAM::Policy Properties: PolicyName: !Sub PlRolePolicy-${YourID} PolicyDocument: Statement: - Action: - s3:Abort* - s3:DeleteObject* - s3:GetBucket* - s3:GetObject* - s3:List* - s3:PutObject - s3:PutObjectLegalHold - s3:PutObjectRetention - s3:PutObjectTagging - s3:PutObjectVersionTagging Effect: Allow Resource: - !GetAtt PipelineArtifactBucket.Arn - Fn::Join: - "" - - !GetAtt PipelineArtifactBucket.Arn - /* - Action: sts:AssumeRole Effect: Allow Resource: - !GetAtt PipelineBuildCodeBuildActionRole.Arn - !GetAtt PipelineDeployCreateChangeSetActionRole.Arn - !GetAtt PipelineDeployExecuteChangeSetActionRole.Arn - !GetAtt PipelineSourceCodeCommitActionRole.Arn Version: "2012-10-17" Roles: - Ref: PipelineRole DependsOn: - PipelineRole - PipelineArtifactBucket - PipelineBuildCodeBuildActionRole - PipelineDeployCreateChangeSetActionRole - PipelineDeployExecuteChangeSetActionRole - PipelineSourceCodeCommitActionRole # ------------------------------------------------------------# # CodePipeline # ------------------------------------------------------------# Pipeline: Type: AWS::CodePipeline::Pipeline Properties: Name: !Sub SampleProjectPipeline-${YourID} RoleArn: !GetAtt PipelineRole.Arn Stages: - Actions: - ActionTypeId: Category: Source Owner: AWS Provider: CodeCommit Version: "1" Configuration: RepositoryName: !GetAtt SampleProjectRep.Name BranchName: master PollForSourceChanges: false Name: CodeCommit OutputArtifacts: - Name: Artifact_Source_CodeCommit RoleArn: !GetAtt PipelineSourceCodeCommitActionRole.Arn RunOrder: 1 Name: Source - Actions: - ActionTypeId: Category: Build Owner: AWS Provider: CodeBuild Version: "1" Configuration: ProjectName: Ref: BuildProject InputArtifacts: - Name: Artifact_Source_CodeCommit Name: CodeBuild OutputArtifacts: - Name: Artifact_Build_CodeBuild RoleArn: !GetAtt PipelineBuildCodeBuildActionRole.Arn RunOrder: 1 Name: Build - Actions: - ActionTypeId: Category: Deploy Owner: AWS Provider: CloudFormation Version: "1" Configuration: StackName: !Sub SampleProject-Stack-${YourID} Capabilities: CAPABILITY_NAMED_IAM RoleArn: !GetAtt PipelineDeployCreateChangeSetRole.Arn ActionMode: CHANGE_SET_REPLACE ChangeSetName: !Sub SampleProject-Deploy-${YourID} TemplatePath: Artifact_Build_CodeBuild::packaged.yaml ParameterOverrides: !Sub '{"YourID": "${YourID}"}' InputArtifacts: - Name: Artifact_Build_CodeBuild Name: CreateChangeSet RoleArn: !GetAtt PipelineDeployCreateChangeSetActionRole.Arn RunOrder: 1 - ActionTypeId: Category: Deploy Owner: AWS Provider: CloudFormation Version: "1" Configuration: StackName: !Sub SampleProject-Stack-${YourID} ActionMode: CHANGE_SET_EXECUTE ChangeSetName: !Sub SampleProject-Deploy-${YourID} Name: ExecuteChangeSet RoleArn: !GetAtt PipelineDeployExecuteChangeSetActionRole.Arn RunOrder: 2 Name: Deploy ArtifactStore: Location: Ref: PipelineArtifactBucket Type: S3 Tags: - Key: Cost Value: !Ref YourID DependsOn: - SampleProjectRep - PipelineRoleDefaultPolicy - PipelineRole - PipelineSourceCodeCommitActionRole - PipelineBuildCodeBuildActionRole - PipelineDeployCreateChangeSetActionRole - PipelineDeployExecuteChangeSetActionRole - PipelineArtifactBucket # ------------------------------------------------------------# # CodePipeline Source Code Commit Action Role (IAM) # ------------------------------------------------------------# PipelineSourceCodeCommitActionRole: Type: AWS::IAM::Role Properties: RoleName: !Sub PlSrcCcActionRole-${YourID} AssumeRolePolicyDocument: Statement: - Action: sts:AssumeRole Effect: Allow Principal: AWS: Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":iam::" - Ref: AWS::AccountId - :root Version: "2012-10-17" # ------------------------------------------------------------# # CodePipeline Source CodeCommit Action Role Policy (IAM) # ------------------------------------------------------------# PipelineSourceCodeCommitActionRoleDefaultPolicy: Type: AWS::IAM::Policy Properties: PolicyName: !Sub PlSrcCcActionRolePolicy-${YourID} PolicyDocument: Statement: - Action: - s3:Abort* - s3:DeleteObject* - s3:GetBucket* - s3:GetObject* - s3:List* - s3:PutObject - s3:PutObjectLegalHold - s3:PutObjectRetention - s3:PutObjectTagging - s3:PutObjectVersionTagging Effect: Allow Resource: - !GetAtt PipelineArtifactBucket.Arn - Fn::Join: - "" - - !GetAtt PipelineArtifactBucket.Arn - /* - Action: - codecommit:CancelUploadArchive - codecommit:GetBranch - codecommit:GetCommit - codecommit:GetUploadArchiveStatus - codecommit:UploadArchive Effect: Allow Resource: !GetAtt SampleProjectRep.Arn Version: "2012-10-17" Roles: - Ref: PipelineSourceCodeCommitActionRole DependsOn: - PipelineArtifactBucket - SampleProjectRep - PipelineSourceCodeCommitActionRole # ------------------------------------------------------------# # CodePipeline Events Role (IAM) # ------------------------------------------------------------# PipelineEventsRole: Type: AWS::IAM::Role Properties: RoleName: !Sub PlEventsRole-${YourID} AssumeRolePolicyDocument: Statement: - Action: sts:AssumeRole Effect: Allow Principal: Service: events.amazonaws.com Version: "2012-10-17" # ------------------------------------------------------------# # CodePipeline Events Role Policy (IAM) # ------------------------------------------------------------# PipelineEventsRoleDefaultPolicy: Type: AWS::IAM::Policy Properties: PolicyName: !Sub PlEventsRolePolicy-${YourID} PolicyDocument: Statement: - Action: codepipeline:StartPipelineExecution Effect: Allow Resource: Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":codepipeline:" - Ref: AWS::Region - ":" - Ref: AWS::AccountId - ":" - Ref: Pipeline Version: "2012-10-17" Roles: - Ref: PipelineEventsRole DependsOn: - PipelineEventsRole # ------------------------------------------------------------# # CodePipeline Build CodeBuild Action Role (IAM) # ------------------------------------------------------------# PipelineBuildCodeBuildActionRole: Type: AWS::IAM::Role Properties: RoleName: !Sub PlBldCbActionRole-${YourID} AssumeRolePolicyDocument: Statement: - Action: sts:AssumeRole Effect: Allow Principal: AWS: Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":iam::" - Ref: AWS::AccountId - :root Version: "2012-10-17" # ------------------------------------------------------------# # CodePipeline Build CodeBuild Action Role Policy (IAM) # ------------------------------------------------------------# PipelineBuildCodeBuildActionRoleDefaultPolicy: Type: AWS::IAM::Policy Properties: PolicyName: !Sub PlBldCbActionRolePolicy-${YourID} PolicyDocument: Statement: - Action: - codebuild:BatchGetBuilds - codebuild:StartBuild - codebuild:StopBuild Effect: Allow Resource: !GetAtt BuildProject.Arn Version: "2012-10-17" Roles: - Ref: PipelineBuildCodeBuildActionRole DependsOn: - BuildProject - PipelineBuildCodeBuildActionRole # ------------------------------------------------------------# # CodePipeline Deploy Create ChangeSet Action Role (IAM) # ------------------------------------------------------------# PipelineDeployCreateChangeSetActionRole: Type: AWS::IAM::Role Properties: RoleName: !Sub PlDepCrChsetActionRole-${YourID} AssumeRolePolicyDocument: Statement: - Action: sts:AssumeRole Effect: Allow Principal: AWS: Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":iam::" - Ref: AWS::AccountId - :root Version: "2012-10-17" # ------------------------------------------------------------# # CodePipeline Deploy Create ChangeSet Action Role Policy (IAM) # ------------------------------------------------------------# PipelineDeployCreateChangeSetActionRoleDefaultPolicy: Type: AWS::IAM::Policy Properties: PolicyName: !Sub PlDepCrChsetActionRolePolicy-${YourID} PolicyDocument: Statement: - Action: iam:PassRole Effect: Allow Resource: !GetAtt PipelineDeployCreateChangeSetRole.Arn - Action: - s3:GetBucket* - s3:GetObject* - s3:List* Effect: Allow Resource: - !GetAtt PipelineArtifactBucket.Arn - Fn::Join: - "" - - !GetAtt PipelineArtifactBucket.Arn - /* - Action: - cloudformation:CreateChangeSet - cloudformation:DeleteChangeSet - cloudformation:DescribeChangeSet - cloudformation:DescribeStacks Condition: StringEqualsIfExists: cloudformation:ChangeSetName: !Sub SampleProject-Deploy-${YourID} Effect: Allow Resource: Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":cloudformation:" - Ref: AWS::Region - ":" - Ref: AWS::AccountId - !Sub :stack/SampleProject-Stack-${YourID}/* Version: "2012-10-17" Roles: - Ref: PipelineDeployCreateChangeSetActionRole DependsOn: - PipelineDeployCreateChangeSetRole - PipelineArtifactBucket - PipelineDeployCreateChangeSetActionRole # ------------------------------------------------------------# # CodePipeline Deploy Create ChangeSet Role (IAM) # ------------------------------------------------------------# PipelineDeployCreateChangeSetRole: Type: AWS::IAM::Role Properties: RoleName: !Sub PlDepCrChsetRole-${YourID} AssumeRolePolicyDocument: Statement: - Action: sts:AssumeRole Effect: Allow Principal: Service: cloudformation.amazonaws.com Version: "2012-10-17" # ------------------------------------------------------------# # CodePipeline Deploy Create ChangeSet Role Policy (IAM) # ------------------------------------------------------------# PipelineDeployCreateChangeSetRoleDefaultPolicy: Type: AWS::IAM::Policy Properties: PolicyName: !Sub PlDepCrChsetRolePolicy-${YourID} PolicyDocument: Statement: - Action: - s3:GetBucket* - s3:GetObject* - s3:List* Effect: Allow Resource: - !GetAtt PipelineArtifactBucket.Arn - Fn::Join: - "" - - !GetAtt PipelineArtifactBucket.Arn - /* - Action: "*" Effect: Allow Resource: "*" Version: "2012-10-17" Roles: - Ref: PipelineDeployCreateChangeSetRole DependsOn: - PipelineArtifactBucket - PipelineDeployCreateChangeSetRole # ------------------------------------------------------------# # CodePipeline Deploy Execute ChangeSet Action Role (IAM) # ------------------------------------------------------------# PipelineDeployExecuteChangeSetActionRole: Type: AWS::IAM::Role Properties: RoleName: !Sub PlDepExecChsetActionRole-${YourID} AssumeRolePolicyDocument: Statement: - Action: sts:AssumeRole Effect: Allow Principal: AWS: Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":iam::" - Ref: AWS::AccountId - :root Version: "2012-10-17" # ------------------------------------------------------------# # CodePipeline Deploy Execute ChangeSet Action Role Policy (IAM) # ------------------------------------------------------------# PipelineDeployExecuteChangeSetActionRoleDefaultPolicy: Type: AWS::IAM::Policy Properties: PolicyName: !Sub PlDepExecChsetActionRolePolicy-${YourID} PolicyDocument: Statement: - Action: - cloudformation:DescribeChangeSet - cloudformation:DescribeStacks - cloudformation:ExecuteChangeSet Condition: StringEqualsIfExists: cloudformation:ChangeSetName: !Sub SampleProject-Deploy-${YourID} Effect: Allow Resource: Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":cloudformation:" - Ref: AWS::Region - ":" - Ref: AWS::AccountId - !Sub :stack/SampleProject-Stack-${YourID}/* Version: "2012-10-17" Roles: - Ref: PipelineDeployExecuteChangeSetActionRole DependsOn: - PipelineDeployExecuteChangeSetActionRole
CI/CD パイプライン使用方法
AWS Cloud9 準備
今回は、API Gateway と Lambda 関数をコードで管理します。コードは AWS CodeCommit で管理し、コードの編集は AWS Cloud9 を使用します。あらかじめ CodeCommit の該当するリポジトリ と Cloud9 を連携する必要があります。ここでは、この準備の説明は割愛します。以下の AWS 公式ドキュメントを参考に準備頂けると幸いです。
コードの準備
API Gateway と Lambda 関数をデプロイするために、以下 3 種類のコードファイルを準備します。ファイル名はこの例のまま使用頂いた方が良いです。(CI/CD パイプライン内で指定している都合でw)
- lambda_function.py
- buildspec.yml
- template.yml
以下、それぞれについて解説します。
lambda_function.py
Lambda 関数の実体です。ここでは、サンプルなので現在時刻を返すだけの Python コードになっています。
from datetime import datetime def lambda_handler(event, context): # Get the current date and time now = datetime.now() # Format the date and time in a readable format (e.g., YYYY-MM-DD HH:MM:SS) current_time = now.strftime("%Y-%m-%d %H:%M:%S") # Return the current date and time return { "statusCode": 200, "body": current_time }
buildspec.yml
ビルドステージで何をするか、を定義したファイルです。
実際のところ、Lambda 関数コードは上述の lambda_function.py をそのまま使用するのでコンパイルすることはありません。API Gateway や Lambda 関数リソースをこの CI/CD パイプラインでデプロイするため、sam build や sam package というコマンドを使用して AWS SAM テンプレートを AWS 側で処理しやすいフォーマットに?若干変更するようです。(変更後ファイルは packaged.yaml)
version: 0.2 phases: install: runtime-versions: python: 3.11 commands: pre_build: commands: - sam build build: commands: - sam package --s3-bucket $S3_BUCKET --output-template-file packaged.yaml artifacts: files: - packaged.yaml
template.yml
AWS SAM テンプレートファイルです。この中で、デプロイしたい API Gateway と Lambda 関数のリソースを定義しています。
AWS CloudFormation と比べるとかなり少ない行数です。標準的な設定を使用して動くリソースをデプロイしてくれます。
AWSTemplateFormatVersion: 2010-09-09 Description: >- SampleProject Transform: - AWS::Serverless-2016-10-31 Parameters: YourID: Type: String Default: dummy Resources: SampleFunction: Type: AWS::Serverless::Function Properties: Handler: lambda_function.lambda_handler Runtime: python3.11 Policies: - DynamoDBReadPolicy: TableName: YourTableName Environment: Variables: YourID: !Ref YourID Events: Api: Type: Api Properties: Path: /test Method: POST Outputs: ApiEndpoint: Description: "APIG Endpoint" Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/"
SAM (Serverless Application Model) は AWS CloudFormation よりも簡易にリソースを定義できる分、カスタマイズ性に欠けるので要件によって CloudFormation との使い分けを考える必要があります。
ここでは、全く使用しないのですが Lambda 関数に YourTableName という Amazon DynamoDB テーブルの Read Only 権限を与えています。このように AWS があらかじめ用意した権限パターンセットを使うと簡単な権限定義ができます。
最終的に、前述した通り SAM テンプレートはビルドステージで内部的に CloudFormation テンプレートに変換され、デプロイに使用されます。
実際にデプロイしてみる
CodeCommit と連携した状態の Cloud9 で、以下のようにプロジェクトのルートディレクトリに 3 つのコードを配置します。
配置後、CodeCommit にコードをプッシュします。(以下、コマンド例)
git commit -A git commit -m "initial commit" git push origin master
プッシュすると、自動的に CI/CD パイプライン (AWS CodePipeline) が動き出します。
Deploy ステージまで完了。
全てのステージが完了すると、API Gateway と Lambda 関数が連携された状態でデプロイされています。
Lambda 関数の IAM ロールも、デフォルトのポリシー + DynamoDB Read only 系の権限が自動的に作成されてますね。
AWS CloudFormation のコンソールを見ると、CI/CD パイプラインから実行された CloudFormation スタックがあることが確認できます。
説明は省略しますが、API Gateway や Lambda 関数を更新するときは Cloud9 のコードを更新して上記手順を繰り返します。
注意点ですが、一連の環境を削除するときには先にこの CI/CD パイプラインから呼び出された CloudFormation スタックを削除する必要があります。その後、CI/CD パイプラインをデプロイしたときのスタック削除になります。
まとめ
いかがでしたでしょうか?
API Gateway と Lambda 関数をコードでバージョン管理するときにはこのような方法を採るのが今時点のソリューションかと思います。あくまでも簡易な一例ですので、ディテールは書き換えて下さい。
本記事が皆様のお役に立てれば幸いです。