【AWS】CodePipelineを使ってcodeCommitのプルリクでLamdaをデプロイ

自分の備忘録的なものです。AWS公式をキャプチャ付きに簡単にまとめたものです。文章をだらだら読むより視覚的に理解したい人用です。
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/build-pipeline.html


1. AWS CloudFormation ロールを作成する

ここで予め、デプロイ時に必要となるロールを作成します。

コンソールからIAMへ行きます。

IAM_console
コンソールからIAMを検索

メニューから【Roles】を選択します。

console_IAM_Roles
IAMでRoles選択


trusted EntityでAWS Serviceを選択し、use Caseとして、下の方にある【Cloud formation】を選択し、【Next Permission】を選択
console_IAM_Role_entity

console_IAM_Role_CloudFormation
CloudFormationを選択


【Create policy】を選択し、ポリシーを作成します。

console_IAM_Roles_create_policy
【Create policy】からポリシーを作成


JSON】タブを選択して以下をコピペします。

{ 
    "Statement": [ 
           { "Action": [ "apigateway:*", 
                                "codedeploy:*",
                                "lambda:*", 
                                "cloudformation:CreateChangeSet", 
                                "iam:GetRole",
                                "iam:CreateRole",
                                "iam:DeleteRole",
                                "iam:PutRolePolicy",
                                "iam:AttachRolePolicy",
                                "iam:DeleteRolePolicy", 
                                "iam:DetachRolePolicy", 
                                "iam:PassRole", 
                                "s3:GetObject", 
                                "s3:GetObjectVersion", 
                                "s3:GetBucketVersioning" 
                           ], 
                          "Resource": "*", 
                          "Effect": "Allow"
      }
    ],
 "Version": "2012-10-17" 
}

console_IAM_Roles_edit_policy
JSON選択し、ポリシー作成

ポリシーに名前を付けます。

AWS公式の例だとcfn-lambda-pipelineとなっています。
console_IAM_Role_policy_made
ポリシーに名前を付けて保存

2.リポジトリをセットアップする

codeCommitで例としてlambda-pipeline-repoというリポジトリを作成しているとします。
そこの直下に以下のファイルを入れます。

index.js 

var time = require('time');
exports.handler = (event, context, callback) => {
    var currentTime = new time.Date();
    currentTime.setTimezone("America/Los_Angeles");
    callback(null, {
        statusCode: '200',
        body: 'The time in Los Angeles is: ' + currentTime.toString(),
    });
};

ソースファイルになり、現在の時刻を返すLambda関数になります。


buildspec.yml 

version: 0.2
phases:
  install:
    runtime-versions:
        nodejs: 10
  build:
    commands:
      - npm install time
      - export BUCKET=ここは自身のS3バケットを指定する
      - aws cloudformation package --template-file template.yml --s3-bucket $BUCKET --output-template-file outputtemplate.yml
artifacts:
  type: zip
  files:
    - template.yml
    - outputtemplate.yml

ビルド時に必要なパッケージをインストールしたりするファイル ※BUCKETの部分は自身のS3のバケット名に置き換えてください。


template.yml

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Outputs the time
Resources:
  TimeFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: index.handler
      Runtime: nodejs10.x
      CodeUri: ./
      Events:
        MyTimeApi:
          Type: Api
          Properties:
            Path: /TimeResource
            Method: GET

デプロイ時の環境を定義するファイル。APIゲートウェイにURLを指定して展開するとこまで書かれています。
故にこのファイルが無事実行されれば、URLを叩けば↑のLambdaが実行されることになります。

全て直下に置くので、ファイル構成をまとめると以下のようになります。
※ソースは別に直下であればどんな構成でも構いません。

folder_cloud9
フォルダ構成例(Cloud9でリポジトリをcloneした場合)


3. CodepipelineでPipelineを作成する

コンソールから【CodePipeline】を検索して選択します。

console_CodePipeline
CodePipelineを選択

【Create Pipeline】を選択します。

CodePipeline_menu
Create Pipelineを選択

Pipelineの名前を入力します。例ではlambda-pipelineとなっています。
また、ロールは新しく作ることにしますので、【New service role】を選択します。既存のロールがある場合は【Existing service role】選択して下さい。
CodePipeline_pipelinename
pipeline名を入力

ソースの詳細を選択していきます。
まず、Source providerとして例としてAWS Code Commitを選択します。選択すると自動的にリポジトリ名入力などの入力欄が出てきます。
クリックするとドロップダウンで存在するレポジトリやブランチを選択できます。
今回は既に作成しているlambda-pipeline-repoとブランチとしてmasterを選択します。
Change detection optionsとしてCloud Watch Eventを選択することで、リポジトリの更新でCodePipelineが走るようになります。

CodePipeline_source
ソースの詳細を入力

ビルドの詳細を選択していきます。ソース同様、Build providerでAWS CodeBuildを選択するとリージョンの選択とプロジェクト名の入力が出ます。
プロジェクトはまだ作成していないので、【Create project】を選択します。

CodePipeline_build
ビルド詳細

ビルドの設定を作成します。

Buildの名前を入力します。例ではlambda-pipeline-buildとなっています。
CodePipeline_build_project
プロジェクト名を入力

Environmentを以下のように設定
・Operating system ・・・ Ubuntu
・Runtimes ・・・ Standard
・image ・・・ aws/codebuild/standard:2.0
・image version ・・・ 最新
・Environment type ・・・ Linux
他はデフォルトで構いません。ロールも新しく作成する設定にしておきます。

CodePipeline_build_project_environment
buildの詳細設定

ビルドファイルの名前を設定する。git上のフォルダ直下に存在するファイル名にします。例だとbuildspec.ymlです。
CodePipeline_build__project_buildspec
ビルドファイル名を設定

CodePipelineに戻ります。先ほどのBuild provider選択に作成したlambda-pipeline-buildが選択出来るようになるので選択します。
※表示されない場合は更新

デプロイの設定をします。
それぞれ以下のように設定します。
・Deploy provider ・・・ CloudFormation
・Region ・・・ お好きなリージョン
・Action mode ・・・ Create or replace a changeset
・Stack name ・・・ lambda-pipeline-stack
・Change set name ・・・ lambda-pipeline-changeset

Stack nameとChange set nameは入力した名前で作成されます。
CodePipeline_deploy_1

Templateの項目を埋めます。指定した名前のファイルがS3上に作成されます。
・Artifact name ・・・ BuildArtifact
・File name ・・・ outputtemplate.yml

Capabilities - optionalは【CAPABILITY_IAM】を選択します。

Roleは一番最初にIAMで作成したcfn-lambda-pipelineを選択します。
CodePipeline_deploy_2
Deployの設定

4.ビルドステージロールを更新する

IAMコンソールのRoleからビルドプロジェクト作成時に作成したロールcode-build-lambda-pipeline-service-roleを選択します。
codebuild_edit_Role
作成済のロールを選択

ポリシーをアタッチします。S3にファイルを添付するのでS3のフルアクセスをアタッチします。

console_IAM_Role_S3full
S3フルアクセスをアタッチ

5.デプロイステージの完了

CodePipelineに戻り、作成済のパイプラインであるlambda-pipelineを選択します。
CodePipeline_choose_pipeline
パイプラインを選択

メニューにある【edit】を選択し、編集していきます。

CodePipeline_edit_pipeline
パイプラインを編集

デプロイにある【edit deploy】を選択してデプロイを編集していきます。

CodePipeline_edit_deploy
デプロイを編集

【Add action group】を選択します。

CodePipeline_add_action_group
アクショングループを追加

以下のように設定します。
・Action name ・・・ excute-changeset
・Action provider ・・・ AWS Cloudformation
・Region ・・・ お好きなリージョン
・Input artifacts ・・・ BuildArtifact
・Action mode ・・・ Excute a changeset
・Stack name ・・・ lambda-pipeline-stack
・Change set name ・・・ lambda-pipeline-changeset

CodePipeline_deploy_edit_changeset
変更セットの実行デプロイステージの設定

6.アプリケーションのテスト

ここまでで、CodePipelineの設定は終了です。ここまでで、エラー等あれば、指定しているproviderや操作しているIAMユーザーのロールなどを確認してください。基本的にエラー内容に従えば解決するはずです。
アプリケーションのテストの前にCodePipelineの実行を行います。【Release Change】を選択して実行します。

CodePipeline_Release_Change
CodePipelineを実行

※初回だと変更セット実行で変更セットがないというエラーが出ることがあるが、再実行で解決します。


アプリケーションのテストを行う為、コンソールからLamdaへ移ります。

Console_Lambda
コンソールからLambdaへ行く

サイドメニューから【Application】を選択すると、CodePipelineで作成したlambda-pipeline-stackが表示されます。

下の方へ行き、Resourcesにある【Serverless RestApi】を展開し、【Prod API endpoint】を選択します。

Lambda_choose_prod_APIEndpoint
Prod API endpointを選択

エラーメッセージが出ますので、URLのパスにTimeResourceを追加します。
すると、時間が表示されるのが確認できます。
Lambda_show_time
時刻表示の確認


以上で、CodePipelineでのLambdaのデプロイは終わりです。複数ラムダを展開したい場合は、template.ymlをいじればできます。
その際、ラムダ毎にインストールするパッケージを変えたい場合は、buildspec.ymlを上手くいじる必要あります。
何かアプリを作る時など機会があれば備忘録として書こうと思います。

※2020/3/22現在、デプロイステージで変更セットの実行がたまに失敗します。原因が分かれば追記します。再実行で解決するので今のとこ個人での使用であればそんなに影響はないと思います。
※2020/4/21追記
 今更ながらしっかりエラー見て気づきましたが、Deployの同ステージ内で変更セットの作成と実行を同時にやってしまっているようでした。
 正しくは【Add action group】で、変更セット実行は後にすると失敗はしませんでした。