この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので十分ご注意ください。
はじめに
Lambdaを毎度手動デプロイも慣れてきましたが、オペミス等の観点からデプロイを自動化するCICDパイプラインを構築してみたいと思います。
構成は、CodePipelineを利用して、SourceはCodeCommit
、BuildはCodeBuild
、DeployはCloudFormation
を利用します。
コミットによる変更後、CodePipeline
の変更をリリースする
を押下することで、Lambdaが自動的にデプロイされます。
構成図
ハンズオン
構築のながれ
1.S3作成:CodeCommitリポジトリに反映させるZipファイルを保存
2.CodeCommit作成:CFnを利用してCodeCommit構築
3.CodePipeline作成:CFnを利用してCodePipeline構築
1.S3作成:CodeCommitリポジトリに反映させるZipファイルを保存用
S3を構築するためのテンプレートは以前のブログ CloudFormationでCodeCommit 作成時にリポジトリを反映する構築ハンズオンを参照ください。
ここではS3
を作成した後、S3
に配置するオブジェクトの説明をします。
保存するのはpipeline_settings
をZip化したcicd.zip
をS3に配置します。
【Zip化するファイル概要説明】
pipeline_settings
|_①buildspec.yml # CodeBuildでビルド実行するコマンドが記述されている
|_②index.py # Lambdaで実行されるコードを記述している
|_③param.json # ビルド実行で構築されるLambdaのパラメータを記述している
|_④template_deploy.yml # ビルド実行で構築されるLambdaがyamlで記述されている
①buildspec.yml について
CodeBuildでビルドを実行する際のコマンドが記述されています。
aws aws cloudformation package
を利用することで、指定した場所にあるpipeline_settings/template_deploy.yml
や、S3バケット$S3_BUCKET
をとりまとめて、テンプレートファイルを出力してくれます。
環境変数の$S3_BUCKET
は、CodePipeline
をCFn構築する際に設定をしていきます。
version: 0.2
phases:
build:
commands:
- |
aws cloudformation package \
--template-file pipeline_settings/template_deploy.yml \
--s3-bucket $S3_BUCKET \
--output-template-file $PACKAGED_TEMPLATE_FILE_PATH
artifacts:
files:
- $PACKAGED_TEMPLATE_FILE_PATH
- pipeline_settings/*
discard-paths: yes
②index.pyについて
CodeBuildして構築されたLambdaで利用するコードを記載しています。
今回は最終的にCodeCommitの画面でindex.py
を編集 → CodePipelineの変更をリリースする
押下 → 編集が反映される で一連の流れを確認していきたいと思います。
※CodeCommitのGUIに直接アクセスする方法以外は下記ブログを参照ください
CodeCommit で利用できる3種類のアクセス方法ハンズオン
import json
def lambda_handler(event, context):
# TODO implement
print(event)
return {
'statusCode': 200,
'body': json.dumps('Hello Lambda!')
}
③param.jsonについて
ビルド実行後、CFnでデプロイの際に利用するLambdaのパラメータ値を記述しています。
Lambdaに変更(コード以外の部分)が生じた場合、こちらのjsonを修正するだけで④template_deploy.ymlは手を加えずに済みます。
{
"Parameters": {
"FunctionName": "cfn-lmd-inamura",
"Description": "cfn-lmd-inamura",
"Handler": "index.lambda_handler",
"MemorySize": "128",
"Runtime": "python3.9",
"Timeout": "10",
"TagsName": "inamura"
}
}
④template_deploy.yml
ビルド実行後、CFnでデプロイの際に利用するテンプレートが記述されています。
AWSTemplateFormatVersion: '2010-09-09'
Description:
Lambda Create
# ------------------------------------------------------------#
# InputParameters
# ------------------------------------------------------------#
Parameters:
FunctionName:
Type: String
Description:
Type: String
Handler:
Type: String
MemorySize:
Type: String
Runtime:
Type: String
Timeout:
Type: String
TagsName:
Type: String
# ------------------------------------------------------------#
# Resources
# ------------------------------------------------------------#
Resources:
# ------------------------------------------------------------#
# Lambda
# ------------------------------------------------------------#
Lambda:
Type: 'AWS::Lambda::Function'
Properties:
Description: !Ref Description
FunctionName: !Ref FunctionName
Handler: !Ref Handler
MemorySize: !Ref MemorySize
Runtime: !Ref Runtime
Timeout: !Ref Timeout
Role: !GetAtt LambdaRole.Arn
Tags:
- Key: "User"
Value: !Ref TagsName
LambdaRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub "${FunctionName}-role"
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Action: "sts:AssumeRole"
Principal:
Service: lambda.amazonaws.com
Policies:
- PolicyName: !Sub "${FunctionName}-policy"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Action:
- "logs:CreateLogStream"
- "logs:PutLogEvents"
- "logs:CreateLogGroup"
Resource: !Sub "arn:${AWS::Partition}:logs:*:*:*"
# ------------------------------------------------------------#
# Output Parameters
#------------------------------------------------------------#
Outputs:
LambdaArn:
Value: !GetAtt Lambda.Arn
Export:
Name: !Sub "${FunctionName}-arn"
LambdaName:
Value: !Ref FunctionName
Export:
Name: !Sub "${FunctionName}-name"
2.CodeCommit作成:CFnを利用してCodeCommit構築
手順1で用意したZipファイルをS3
に保存後、CFnを利用してCodeCommitを構築します。
CodeCommitを構築するためのテンプレートは以前のブログ CloudFormationでCodeCommit 作成時にリポジトリを反映する構築ハンズオンを参照ください。
構築後CodeCommit
の画面に遷移して下記リポジトリが作成されているかを確認する
リポジトリを押下後、配下の資材も構築されていることが確認できます。
3.CodePipeline作成:CFnを利用してCodePipeline構築
3.1.CodePipelineで構築するリソース群
リソース名 | 説明 |
---|---|
CodePipeline | CodePipeline構築(CodeCommit → CodeBuild → CFn(デプロイ) |
CodeBuil | CodeBuild構築 |
IAM Role | CodePipeline用ロール |
IAM Role | CodeBuild用ロール |
IAM Role | CFn(デプロイ)用ロール |
3.2.CodePipelineの流れ
Sourceフェイズ:手順2で構築したCodeCommit
のリポジトリ情報をCodeBuild
に渡す
Buildフェイズ:①buildspec.yml
の内容から④template_deploy.yml + ③param.json
をとりまとめ、S3(CodePipelineテンプレートのArtifactStoreBucket
で指定)に CFnテンプレート(packaged.yml)を出力する
Deployフェイズ:出力されたCFnテンプレートから、新規CFnリソースを構築する
【再掲 CodeCommit リポジトリに含まれているファイル群】
pipeline_settings
|_①buildspec.yml # CodeBuildでビルド実行するコマンドが記述されている
|_②index.py # Lambdaで実行されるコードを記述している
|_③param.json # ビルド実行で構築されるLambdaのパラメータを記述している
|_④template_deploy.yml # ビルド実行で構築されるLambdaがyamlで記述されている
3.3.CodePipeline CFn テンプレート
AWSTemplateFormatVersion: '2010-09-09'
Description:
CodeCommit Create
# ------------------------------------------------------------#
# Metadata
# ------------------------------------------------------------#
Metadata:
"AWS::CloudFormation::Interface":
ParameterGroups:
- Label:
default: "Lambda Configuration"
Parameters:
- PipelineName
- BuildName
- PackagedTemplateFile
- BuildSpec
- ArtifactStoreBucket
- ModuleStackName
- DeployParamFile
# ------------------------------------------------------------#
# InputParameters
# ------------------------------------------------------------#
Parameters:
PipelineName:
Type: String
Default: cfn-codepipeline-inamura
BuildName:
Type: String
Default: cfn-codebuild-inamura
PackagedTemplateFile:
Type: String
Default: packaged.yml
ArtifactStoreBucket:
Type: String
Default: cfn-s3-20230103-inamura
BuildSpec:
Type: String
Default: pipeline_settings/buildspec.yml
ModuleStackName:
Type: String
Default: cfn-codepipeline-lambda-inamura
DeployParamFile:
Type: String
Default: param.json
# ------------------------------------------------------------#
# Resources
# ------------------------------------------------------------#
Resources:
# ------------------------------------------------------------#
# CodeBuild
# ------------------------------------------------------------#
CodeBuildProject:
Type: AWS::CodeBuild::Project
Properties:
Artifacts:
Type: CODEPIPELINE
Environment:
Type: LINUX_CONTAINER
ComputeType: BUILD_GENERAL1_SMALL
Image: aws/codebuild/amazonlinux2-x86_64-standard:4.0
EnvironmentVariables:
- Name: PACKAGED_TEMPLATE_FILE_PATH
Value: !Ref PackagedTemplateFile
- Name: S3_BUCKET
Value: !Ref ArtifactStoreBucket
Name: !Ref BuildName
ServiceRole: !GetAtt CodeBuildRole.Arn
Source:
Type: CODEPIPELINE
BuildSpec: !Ref BuildSpec
# ------------------------------------------------------------#
# CodeBuild Role
# ------------------------------------------------------------#
CodeBuildRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Action: sts:AssumeRole
Effect: Allow
Principal:
Service: codebuild.amazonaws.com
Path: /
Policies:
- PolicyName: CodeBuildAccess
PolicyDocument:
Version: 2012-10-17
Statement:
- Sid: CloudWatchLogsAccess
Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource:
- !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/*
- Sid: S3Access
Effect: Allow
Action:
- s3:PutObject
- s3:GetObject
- s3:GetObjectVersion
Resource:
- !Sub arn:aws:s3:::${ArtifactStoreBucket}
- !Sub arn:aws:s3:::${ArtifactStoreBucket}/*
- Sid: CloudFormationAccess
Effect: Allow
Action: cloudformation:ValidateTemplate
Resource: "*"
# ------------------------------------------------------------#
# CodePipeline
# ------------------------------------------------------------#
CodePipeline:
Type: AWS::CodePipeline::Pipeline
Properties:
Name: !Ref PipelineName
RoleArn: !GetAtt CodePipelineRole.Arn
ArtifactStore:
Type: S3
Location: !Ref ArtifactStoreBucket
Stages:
- Name: Source
Actions:
- Name: Source
ActionTypeId:
Category: Source
Owner: AWS
Version: 1
Provider: CodeCommit
Configuration:
RepositoryName: !ImportValue cfn-codecommit-inamura-name
BranchName: main
PollForSourceChanges: false
OutputArtifacts:
- Name: SourceOutput
- Name: Build
Actions:
- InputArtifacts:
- Name: SourceOutput
Name: Package
ActionTypeId:
Category: Build
Provider: CodeBuild
Owner: AWS
Version: 1
OutputArtifacts:
- Name: BuildOutput
Configuration:
ProjectName: !Ref BuildName
# ------------------------------------------------------------#
# CFnDeploy
# ------------------------------------------------------------#
- Name: Deploy
Actions:
- Name: CreateChangeSet
ActionTypeId:
Category: Deploy
Owner: AWS
Provider: CloudFormation
Version: '1'
InputArtifacts:
- Name: BuildOutput
Configuration:
ActionMode: CHANGE_SET_REPLACE
RoleArn: !GetAtt PipelineDeployRole.Arn
StackName: !Ref ModuleStackName
ChangeSetName: !Sub ${ModuleStackName}-changeset
Capabilities: CAPABILITY_NAMED_IAM
TemplatePath: !Sub BuildOutput::${PackagedTemplateFile}
TemplateConfiguration: !Sub BuildOutput::${DeployParamFile}
RunOrder: '1'
- Name: ExecuteChangeSet
ActionTypeId:
Category: Deploy
Owner: AWS
Provider: CloudFormation
Version: '1'
InputArtifacts:
- Name: BuildOutput
Configuration:
ActionMode: CHANGE_SET_EXECUTE
ChangeSetName: !Sub ${ModuleStackName}-changeset
StackName: !Ref ModuleStackName
RunOrder: '2'
# ------------------------------------------------------------#
# CodePipeline Role
# ------------------------------------------------------------#
CodePipelineRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Action: sts:AssumeRole
Effect: Allow
Principal:
Service: codepipeline.amazonaws.com
Path: /
Policies:
- PolicyName: CodePipelineAccess
PolicyDocument:
Version: 2012-10-17
Statement:
- Sid: S3GetObject
Effect: Allow
Action: s3:*
Resource:
- !Sub arn:aws:s3:::${ArtifactStoreBucket}
- !Sub arn:aws:s3:::${ArtifactStoreBucket}/*
- Sid: S3PutObject
Effect: Allow
Action: s3:*
Resource:
- !Sub arn:aws:s3:::${ArtifactStoreBucket}
- !Sub arn:aws:s3:::${ArtifactStoreBucket}/*
- Sid: CodeCommit
Effect: Allow
Action: codecommit:*
Resource: !ImportValue cfn-codecommit-inamura-arn
- Sid: CodeBuildStartBuild
Effect: Allow
Action:
- codebuild:StartBuild
- codebuild:BatchGetBuilds
Resource: !Sub arn:aws:codebuild:${AWS::Region}:${AWS::AccountId}:project/${BuildName}
- Sid: CFnActions
Effect: Allow
Action:
- cloudformation:DescribeStacks
- cloudformation:DescribeChangeSet
- cloudformation:CreateChangeSet
- cloudformation:ExecuteChangeSet
- cloudformation:DeleteChangeSet
Resource:
- !Sub arn:aws:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/${ModuleStackName}/*
- Sid: PassRole
Effect: Allow
Action:
- iam:PassRole
Resource: !GetAtt PipelineDeployRole.Arn
# ------------------------------------------------------------#
# CFnDeploy Role
# ------------------------------------------------------------#
PipelineDeployRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action: sts:AssumeRole
Principal:
Service: cloudformation.amazonaws.com
Path: /
Policies:
- PolicyName: !Sub ${PipelineName}DeployPolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- lambda:*
Resource: !Sub arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:*
- Effect: Allow
Action:
- iam:CreateRole
- iam:DeleteRole
- iam:GetRole
- iam:PassRole
- iam:DeleteRolePolicy
- iam:PutRolePolicy
- iam:GetRolePolicy
Resource: !Sub arn:aws:iam::${AWS::AccountId}:role/*
- Effect: Allow
Action: s3:GetObject
Resource:
- !Sub arn:aws:s3:::${ArtifactStoreBucket}
- !Sub arn:aws:s3:::${ArtifactStoreBucket}/*
挙動の確認
①CodePipeline の Source / Build / Deploy が成功している
※失敗する場合は詳細
を押下することで、エラー解決への糸口にしましょう
②CFn を 確認して CodePipeline 経由での自動デプロイがされていることを確認する
手順2で実施した cfn-codepipeline-inamura
と、手順3で実施した cfn-codepipeline-inamura
の他に赤枠で囲った部分が、CodePipelineによって自動デプロイされた部分です。
③Lambda を確認する
index.py
を選択することで Lambda
を実行可能なことを確認する
④CodeCommit で index.py
を修正して、再度パイプラインを実行する
④-1 リポジトリへ移動する
CodeCommit
> 左ペイン:ソース
から リポジトリ
を選択 > 作成したリポジトリを選択(今回は cfn-codecommit-inamura
)
④-2 index.py
を編集画面へ移動する
リポジトリ選択後 > pipeline_settings
を押下 > index.py
を押下 > 編集
を押下
④-3 index.py
を編集し変更のコミット
する
8行目:Hello Lambda!
からHello CodePipeline!
に修正
作成者名・メールアドレスを入力して変更のコミット
を押下する
⑤CodePipeline の変更をリリースする
を実行する
CodePipeline
> 左ペイン:パイプライン
> 作成したパイプラインを選択(今回は cfn-codepipeline-inamura
) > 変更をリリースする
を押下
CodePipelineを押下することで、挙動①スクショのように再度、Source
→Build
→Deploy
とパイプラインが動いていることが確認できる。
⑥Lambda を確認する
CodePipelineが全て成功したことを確認後、Lambdaを確認してコードが変更されていることを確認する(赤枠部分)
さいごに
CodeCommit でソースコードを集約して CodeBuild でビルドしてアーティファクトにするイメージが掴めていなかったため、検索しても「何が何を構成するのに必要なのか?」が分からず、無意な時間を過ごしました。
構築して動作した後に、どこのパラメータがどこに反映しているかなど逆輸入的な理解の穴埋めなどが多々あり、時間をかけた意味はあったのかなと個人的には思います。
なにが分かるわけではないので、分からないものに蓋をするのではなく検証しながら今年も学んでいこうと思います。
参考URL
CloudFormationでLambdaの自動デプロイ環境を構築する
AWS Code シリーズ