CodeDeployとSAMを利用してLambdaを更新するチュートリアルを試してみた

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

GWは釣りデビューしたいと考えています。AWS事業本部コンサルティング部の後藤です。

今回は表題通り、CodeDeployのAWS公式ドキュメント内にあるCodeDeployとSAMを使用してLambdaを更新するチュートリアルを試してみました。Lambda関数の更新にはCodeDeploy単体で出来ると思い込んでいた私ですが、CodeDeployがLambdaに対して行えるデプロイ内容等が分かるチュートリアルとなっておりました。

それではやっていきましょう!

事前準備

このチュートリアルを始める前に、以下準備が必要となります。

  • AWS Serverless Application Model(SAM) CLIの導入
  • S3 Bucketの作成

Step.1 AWS SAMを使用してチュートリアル環境構築

早速AWS SAMを使用してチュートリアルで使用するAWS環境を構築していきます。

各ファイルの作成

AWS SAMを導入した環境にてディレクトリ 'SAM-Tutorial' を作成し、以下ファイルを作成していきます。

  • template.yml(SAMテンプレートファイル)
  • myDateTimeFunction.js(Lambda関数)
  • afterAllowTraffic.js(CodeDeployAfterAllowTraffic処理で実行するLambda関数、詳細は後述)
  • beforeAllowTraffic.js(CodeDeployのBeforeAllowTraffic処理で実行するLambda関数、詳細は後述)

各ファイルの中身は長くなるため省略します。こちらから確認頂けます。

AWS SAMのパッケージ処理

上記ファイル作成後、以下コマンドでパッケージ化を行います。最近であれば sam deploy のコマンドでパッケージ化も自動的に行ってくれるようになりましたが、ここはチュートリアルに従って理解を深めていきましょう。

パッケージ処理のコマンドは以下の通りです。

sam package \
  --template-file template.yml \
  --output-template-file package.yml \
  --s3-bucket your-S3-bucket

your-S3-bucket部分は事前準備で作成したS3バケット名に変更しましょう。

上記コマンドが正常に作動すると、指定したS3バケットにアーティファクトが格納され、Lambdaコードの参照先がローカル環境からS3に変更されたSAMテンプレートファイルが生成されます。

AWS SAMのデプロイ処理

次はデプロイです。デプロイは以下コマンドで実行します。

sam deploy \
  --template-file package.yml \
  --stack-name my-date-time-app \
  --capabilities CAPABILITY_IAM

--capabilities CAPABILITY_IAMはIAMロールを作成する際に与える必要があるパラメータになります。今回Lambdaを作成するため、Lambdaに付与するIAMロールを作成しています。

デプロイ実行中、Lambda関数作成でエラーが出ました。

CREATE_FAILED                           AWS::Lambda::Function                   myDateTimeFunction                      Resource handler returned message:    
                                                                                                                        "The runtime parameter of nodejs10.x  
                                                                                                                        is no longer supported for creating   
                                                                                                                        or updating AWS Lambda functions. We  
                                                                                                                        recommend you use the new runtime     
                                                                                                                        (nodejs14.x) while creating or        
                                                                                                                        updating functions. (Service: Lambda, 
                                                                                                                        Status Code: 400, Request ID: 7574358 
                                                                                                                        6-9526-4e73-bdbb-f4f499dfbdce)"       
                                                                                                                        (RequestToken:                        
                                                                                                                        3c27a67d-725f-3ee7-4b79-fff0ca229248, 
                                                                                                                        HandlerErrorCode: InvalidRequest)     
ROLLBACK_IN_PROGRESS                    AWS::CloudFormation::Stack              my-date-time-app                        The following resource(s) failed to   
                                                                                                                        create: [myDateTimeFunction].         
                                                                                                                        Rollback requested by user.

エラー原因はチュートリアルで用意されていたtemplate.ymlにて、LambdaのRuntimeがnodejs10.xと設定されていた事でした。執筆時点、LambdaのRuntimeでNodejs10系はサポート外のため発生したエラーと考えられます。取り合えずエラー解消のためLambdaのRuntimeをnodejs14.xに修正しました。

CloudFormationには既に失敗したスタックが存在するため、それを削除して再度デプロイを実行してみます。

Successfully created/updated stack - my-date-time-app in None

正常にSAMのデプロイが実行され、CloudFormationのスタックが作成されました。

Lambda実行テスト

Runtimeをnodejs10.x -> nodejs14.xに変更してそのまま動作するか、Lambdaの動作確認をしてみました。チュートリアルで作成したLambdaは日付を返す仕組みとなっていたため、以下のようなテストコードで実行を試みます。

{
    "option": "date",
    "period": "today"
}

実行結果は以下の通りです。ちゃんとTodayの日付が返答されたため問題なく動作している事が確認できました。

{
  "statusCode": 200,
  "headers": {
    "Content-type": "application/json"
  },
  "body": "{\"month\":4,\"day\":29,\"year\":2022}"
}

Step.2 Lambda関数を更新

Lambdaの作成、及び動作確認が出来たので手元のmyDateTimeFunction.jsの内容を更新していきます。更新後のコードはこちらから確認ください。

Step.3 更新したLambda関数をデプロイ

更新したmyDateTimeFunction.jsをStep.1で作成したLambda関数にデプロイしていきます。デプロイ方法はStep.1と同様、AWS SAMのパッケージ処理とデプロイ処理を行うだけなので、省略します。

Step.1と異なり、AWS SAMのデプロイ処理に時間がかかります。これはCodeDeployを使用してLambda関数のバージョン間で段階的にトラフィック移行させる処理が動いているからです。デプロイ中、CodeDeployをコンソール上で確認すると段階的トラフィック移行の処理が確認出来ます。この処理はtemplate.ymlにType: Linear10PercentEvery1Minuteと記載されている通り、1分間に10パーセント毎トラフィックを新バージョンに移行させる内容となります。

# Specifies the deployment configuration      
          Type: Linear10PercentEvery1Minute

また、CodeDeployがLambdaに対してデプロイを行うとき、デプロイ前後でLambda関数を実行して処理を組み込む事が可能です。Step.1で作成したbeforeAllowTraffic.jsafterAllowTraffic.jsがそれに該当します。デプロイ前後の処理手順は以下のようになっており、BeforeAllowTrafficはAllowTrafficの前に処理されているため、新バージョンのLambdaにトラフィックが流れる前に処理が実行できるようです。

template.ymlではBeforeAllowTraffic、AfterAllowTrafficで実行するLambda関数を以下のように指定しています。

# Specifies Lambda functions for deployment lifecycle hooks
          Hooks:
            PreTraffic: !Ref beforeAllowTraffic
            PostTraffic: !Ref afterAllowTraffic

コンソール上でLambda関数を確認するとバージョン1とバージョン2が作成されており、liveというエイリアスが紐づいている事が確認出来ます。このエイリアス設定はtemplate.ymlでAutoPublishAlias: liveと記載されているため更新時、自動的に設定されています。

# Instructs your myDateTimeFunction is published to an alias named "live".      
      AutoPublishAlias: live

デプロイ実行から10分後、全ての処理が完了してSAMのデプロイ処理も完了しました。

Lambda関数のエイリアスは、トラフィックの移行が完了すると新バージョンのみエイリアスが付いている事も確認できました。

Step.4 Lambda関数の更新確認

Lambda関数が更新されているか確認するため、以下のようなテストコードで時刻が取得します。

{
  "option": "time"
}

時刻が取得出来ているため、正常に更新されている事が確認できました。

{
  "statusCode": 200,
  "headers": {
    "Content-type": "application/json"
  },
  "body": "{\"hour\":11,\"minute\":22,\"second\":16}"
}

また、CloudWatchLogsを確認するとデプロイ前後に実行されたBeforeAllowTraffic.js , AfterAllowTraffic.jsの処理も確認できました。

まとめ

今回はCodeDeployとSAMを使用したLambda関数更新のチュートリアルを試してみました。SAMを使用してLambda関数を更新する方法や、段階的にトラフィックを移行する方法等が学べるチュートリアルとなっておりました。一部そのままでは実行できない箇所もありましたが、すんなり解決出来て良かったです。この記事が何方かのお役に立てば幸いです。