コンテナによるLambdaのデプロイとSAM+GithubActionsによる自動デプロイ

# はじめに
※ この記事は[LIFULL AdventCalendar 2020](https://qiita.com/advent-calendar/2020/lifull)の19日目の記事として投稿されている可能性があります。

最近AWS re:Inventが開催されましたね。
エンジニアのみなさんが注目されているのがわかるほどにツイッターでも多くの情報がタイムライン上に飛び交っていました。
そんな中わたしも情報を追っていてすごくワクワクしながらみておりました。

その中でも私自身が一番アツいと思ったのはAWSLambdaのコンテナサポートですね。
AWSLambdaはサーバーについて気にすることなくコードをアップロードして実行できるため、とても使い勝手が良く非常に小さなソースコードの実行に向いているので使用される頻度は多いAWSサービスの一つだと思います。
その反面でソースコードは直接コードをGUI上で変更したりデプロイ時にzip化したファイルをアップロードするなどしてちょっと手間だなと思うこともあったと思いますが、今回のコンテナサポートによってECRへのpushしたイメージでデプロイができるようになったので、非常にこの辺りの運用が簡単になったのではないかと思ってワクワクしたのが個人的には一番嬉しい内容でした。

なので今回はコンテナを利用したLambdaでのデプロイについてとLambda関数のGithubActionsを利用した自動デプロイについてを書いていこうと思います。


# コンテナでのLambda関数のデプロイ
Lambdaをコンテナで利用する場合にはECRにアップロードしたコンテナイメージをそのままランタイムとして指定することができます。
最大サイズは10GBであり、従来のzipパッケージのアップロードが最大50MBだったことから比較してもできることが格段に増えました。

コンテナにてlambdaを動かす場合にはAWSBatchやECSを利用する場合と変わらず、
構成としては最短で以下の図の様な構成にてデプロイする形式になります。

![lambda_deploy.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255007/70643099-a56a-70ef-4e26-c6062bb57d51.png)

したがって、最低限必要となる手順は以下の三つです。
1. Dockerfileと実行するソースコードを用意
2. ECRのリポジトリの作成とイメージのpush
3. Lambda関数をECRのイメージから作成

## 1 Dockerfileとソースコード
ただデプロイができればいいので、単純な物を用意しておきました。
AWSはLambdaにて[提供しているランタイム](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html)のベースイメージを提供しています。
したがってnodejs12.xのランタイム用にもAWSが提供するベースイメージが存在するので、
そちらを利用した上でDockerfileを作成します。

```js:index.js
exports.lambdaHandler = async (event) => {
    console.log('test1');
}
```

```dockerfile:Dockerfile
FROM amazon/aws-lambda-nodejs:12
COPY . .
CMD ["index.lambdaHandler"]
```

## 2 ECRの作成とimageのpush
### 2.1 ECRの作成
今回イメージを格納する箱をECRのリポジトリ作成から作りましょう。
ここについては特に難しいことはないと思いますので、詳しい説明は省きます。
今回はプライベートでtest-lambda1というECRのリポジトリを作成しています。
![スクリーンショット 2020-12-19 2.56.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255007/65d30d21-4448-d1cd-b8e6-dc1702c3b81f.png)

### 2.2 ECRへのimageのpush
2.1の工程でECRのリポジトリができたらローカルでイメージを立ち上げた上でECRへのpushを行います。
ここも難しいことはないので以下のコマンドでイメージを作成した上でtag付けをした上でECRへpushしましょう。

```bash
$ aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin {account id}.dkr.ecr.ap-northeast-1.amazonaws.com

$ docker build -t test-lambda1 .

$ docker tag test-lambda1:latest {account id}.dkr.ecr.ap-northeast-1.amazonaws.com/{ECRのリポジトリ名}:latest

$ docker push {account id}.dkr.ecr.ap-northeast-1.amazonaws.com/{ECRのリポジトリ名}:latest
```

## 3 lambda関数の作成
2.2までの作業でECRにイメージがpushされていることだと思いますので、pushしたイメージを元にlambda関数を作成します。

作成方法はlambda関数の作成画面に新規に"コンテナイメージ"から関数を作成する部分が新規にできているかと思いますので、こちらを選択したのち関数名と実行するイメージをECRから選択して作成することができます。
![スクリーンショット 2020-12-19 2.55.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255007/77332294-1a10-2716-0667-59db42a01bd3.png)

ここまででコンテナを利用したlambda関数の作成自体は完了です。

## Lambdaでコンテナを使う上で注意するべきこと
Lambda実行環境で正常動作させるためにコンテナイメージには以下の要件が要求されます。

- コンテナイメージはLambdaのランタイムAPIと連携して動作させる。
  - AWSが提供しているベースイメージにはAWS Lambda Runtime Interface Clients(RIC)がすでに内包されているので、特に気を遣う必要はないです。
- Lambda内での書込み可能なのは/tmpディレクトリのみかつ書き込みサイズは512MBまで
- 実行時に必要なファイルは全てのファイルが読み取り可能なこと
- コンテナイメージはLinuxベースのもののみ実行可能
- コンテナイメージではENTRYPOINT, CMD, ENV, WORKDIRのみ適用


# Lambdaへの自動デプロイをしたい
ここまででコンテナを利用した上でLambda関数の手動での作成をおこなうことができましたね。
ここでこんなことを思う方がいるのではないでしょうか？「Lambda起動時にECRから取得するイメージをlatestタグのイメージにしておけばECSとかと同様にECRにpushしたイメージに対してlatestタグを付与するだけで自動デプロイできるようになるのでは？」と。
僕は正しくこの考えだったため、実際にLambdaから見に行くイメージをlatestに変更して、意気揚々と最新のイメージをlatestとしてpushしてみましたが、どうもうまく行きませんでした。
原因をしらべたところ、ドキュメントに以下の様に記載されておりました。

> リポジトリを選択したら、アップロードした latest イメージを使用します。イメージを選択すると、Lambda はそれを基盤となるイメージのダイジェスト (下の画像のタグの右側) に変換しています。docker images --digests コマンドを使用して、イメージのダイジェストをローカルで確認することができます。このように、latest タグが新しいタグに渡された場合でも、関数は同じイメージを使用するため、意図しないデプロイから保護されます。関数コードで使用するイメージを更新できます。その間にタグが別のイメージに再割り当てされた場合でも、関数設定の更新が使用されるイメージに影響することはありません。
[引用] https://aws.amazon.com/jp/blogs/news/new-for-aws-lambda-container-image-support/


つまり、latestタグが変わっても以前のイメージを見に行くのでECRにpushしただけではうまく自動デプロイをすることはできなかったです。
なので、自動デプロイをする場合にはこれまでLambdaでの自動デプロイとして利用されていたSAM等にて自動デプロイを実施する必要がありそうです。

## SAMを使用した上でのコンテナ化Lambdaの自動デプロイ
SAMを利用する場合にはSAM CLIをインストールしておく必要がありますので、[こちら](https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)からSAM CLIのインストールをお願いします。

## 1. プロジェクトの作成

sam initにてプロジェクトを作成します。

```
$ sam init
```

この時、
``What package type would you like to use?``
という質問がありますので、
そこで
```2 - Image (artifact is an image uploaded to an ECR image repository)```
の方を選択するようにしてください。
以下に設定内容の例を示します。

```
$ sam init
Which template source would you like to use?
        1 - AWS Quick Start Templates
        2 - Custom Template Location
Choice: 1
What package type would you like to use?
        1 - Zip (artifact is a zip uploaded to S3)
        2 - Image (artifact is an image uploaded to an ECR image repository)
Package type: 2

Which base image would you like to use?
        1 - amazon/nodejs12.x-base
        2 - amazon/nodejs10.x-base
        3 - amazon/python3.8-base
        4 - amazon/python3.7-base
        5 - amazon/python3.6-base
        6 - amazon/python2.7-base
        7 - amazon/ruby2.7-base
        8 - amazon/ruby2.5-base
        9 - amazon/go1.x-base
        10 - amazon/java11-base
        11 - amazon/java8.al2-base
        12 - amazon/java8-base
        13 - amazon/dotnetcore3.1-base
        14 - amazon/dotnetcore2.1-base
Base image: 1

Project name [sam-app]: lambda3

Cloning app templates from https://github.com/aws/aws-sam-cli-app-templates

    -----------------------
    Generating application:
    -----------------------
    Name: lambda3
    Base Image: amazon/nodejs12.x-base
    Dependency Manager: npm
    Output Directory: .

    Next steps can be found in the README file at ./lambda3/README.md
```

上記コマンドによって、初期化が完了したら、Project Nameで設定したディレクトリに移動します。
今回はlambda3に移動します。

```
$ cd lambda3/
```

ディレクトリの中身を確認してみると生成されたディレクトリは以下のような構成です。

```
$ tree .
.
├── README.md
├── events
│   └── event.json
├── hello-world
│   ├── Dockerfile
│   ├── app.js
│   ├── package.json
│   └── tests
│       └── unit
│           └── test-handler.js
├── samconfig.toml
└── template.yaml
```

初期段階ではhello-worldディレクトリの中にDockerfileとapp.jsがあります。

```dockerfile
FROM public.ecr.aws/lambda/nodejs:12

COPY app.js package.json ./

RUN npm install

# Command can be overwritten by providing a different command in the template directly.
CMD ["app.lambdaHandler"]
```
みていただければわかりますが、AWSが提供しているベースイメージを元に作成されているので、こちらを元にアプリケーションを組むだけですぐにデプロイできます。

次に自動で生成されたSAMテンプレートを確認します。

```yml:template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  lambda3

  Sample SAM Template for lambda3
  
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
  Function:
    Timeout: 3

Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      PackageType: Image
      Events:
        HelloWorld:
          Type: Api
          Properties:
            Path: /hello
            Method: get
    Metadata:
      DockerTag: nodejs12.x-v1
      DockerContext: ./hello-world
      Dockerfile: Dockerfile

Outputs:
  # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function
  # Find out more about other implicit resources you can reference within SAM
  # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api
  HelloWorldApi:
    Description: "API Gateway endpoint URL for Prod stage for Hello World function"
    Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
  HelloWorldFunction:
    Description: "Hello World Lambda Function ARN"
    Value: !GetAtt HelloWorldFunction.Arn
  HelloWorldFunctionIamRole:
    Description: "Implicit IAM Role created for Hello World function"
    Value: !GetAtt HelloWorldFunctionRole.Arn
```

コンテナを利用してLambdaを作る場合には```Type: AWS::Serverless::Function```の**Properties**と**Metadata**が重要です。

- PackageType
  - パッケージ形式を指定するプロパティで、ZipもしくはImageが指定可能です
  - コンテナにて実行する場合にはImageをセットします。
- Metadata
  - sam build実行時の振る舞いを制御するためのプロパティで、以下のプロパティが指定可能です
     - Dockerfile: Dockerfileのファイル名を指定するプロパティです
     - DockerContext: Dockerfileの場所を指定するプロパティで、指定されたディレクトリがビルドコンテキストとなります
     - DockerTag: ビルドしたイメージに付与するタグを指定するプロパティ

ここまでがコンテナ化する上で必要な項目なのですが、
今のまま実行してしまうと、作成されるlambda関数の命名がデプロイされるたびに変わってしまうので、
固定させることと、ECRのリポジトリを設定しましょう。
その場合にはtemplate.yamlを以下のように変更します。

```diff:template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  lambda3

  Sample SAM Template for lambda3
  
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
  Function:
    Timeout: 3

Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      PackageType: Image
+     FunctionName: 'test-lambda3'
+     ImageUri: '{AWSのアカウントID}.dkr.ecr.ap-northeast-1.amazonaws.com/test-lambda3:latest'
      Events:
        HelloWorld:
          Type: Api
          Properties:
            Path: /hello
            Method: get
    Metadata:
      DockerTag: nodejs12.x-v1
      DockerContext: ./hello-world
      Dockerfile: Dockerfile

Outputs:
  # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function
  # Find out more about other implicit resources you can reference within SAM
  # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api
  HelloWorldApi:
    Description: "API Gateway endpoint URL for Prod stage for Hello World function"
    Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
  HelloWorldFunction:
    Description: "Hello World Lambda Function ARN"
    Value: !GetAtt HelloWorldFunction.Arn
  HelloWorldFunctionIamRole:
    Description: "Implicit IAM Role created for Hello World function"
    Value: !GetAtt HelloWorldFunctionRole.Arn
```
見ていただいた通り、**FunctionName**にはlambda関数の関数名をセットできます。
**ImageUri**にはECRのイメージを記載するのでどのイメージからlambdaを作るかを定義できます。

ここまででデプロイの準備は整いました。

## 2. sam buildを利用したイメージのbuildとPUSH
以下のコマンドを実行するだけで、イメージのbuildを行うことが可能です。

```
$ sam build
```

```
$ sam build
Building codeuri: . runtime: None metadata: {'DockerTag': 'nodejs12.x-v1', 'DockerContext': './hello-world', 'Dockerfile': 'Dockerfile'} functions: ['HelloWorldFunction']
Building image for HelloWorldFunction function
Setting DockerBuildArgs: {} for HelloWorldFunction function
Step 1/4 : FROM public.ecr.aws/lambda/nodejs:12
 ---> 8e9e6f058535
Step 2/4 : COPY app.js package.json ./
 ---> 6d2923429f4d
Step 3/4 : RUN npm install
 ---> Running in 50172fcd29a1
added 110 packages from 75 contributors and audited 111 packages in 7.511s
 ---> 086a4bb4d9ed
Step 4/4 : CMD ["app.lambdaHandler"]
 ---> Running in ccf4879c0c26
 ---> fb4a3c3557af
Successfully built fb4a3c3557af
Successfully tagged helloworldfunction:nodejs12.x-v1

Build Succeeded

Built Artifacts  : .aws-sam/build
Built Template   : .aws-sam/build/template.yaml

Commands you can use next
=========================
[*] Invoke Function: sam local invoke
[*] Deploy: sam deploy --guided
```

続いてsam deployにて自動デプロイを行います。
最初のタイミングでは、samconfig.tomlがないので、```sam deploy --guided```にて、対話形式にてデプロイを実行します。
次回以降は```sam deploy```のみでデプロイの実行が可能です。

```bash
$ sam deploy --guided

Configuring SAM deploy
======================

        Looking for config file [samconfig.toml] :  Not found

        Setting default arguments for 'sam deploy'
        =========================================
        Stack Name [sam-app]: lambda3
        AWS Region [us-east-1]: ap-northeast-1
        Image Repository []: {AWSアカウントID}.dkr.ecr.ap-northeast-1.amazonaws.com/test-lambda3
        Images that will be pushed:
          helloworldfunction:nodejs12.x-v1 to {AWSアカウントID}.dkr.ecr.ap-northeast-1.amazonaws.com/test-lambda3:helloworldfunction-b77be1b0ba0f-nodejs12.x-v1

        #Shows you resources changes to be deployed and require a 'Y' to initiate deploy
        Confirm changes before deploy [y/N]: y
        #SAM needs permission to be able to create roles to connect to the resources in your template
        Allow SAM CLI IAM role creation [Y/n]: 
        HelloWorldFunction may not have authorization defined, Is this okay? [y/N]: y   
        Save arguments to configuration file [Y/n]: y
        SAM configuration file [samconfig.toml]: 
        SAM configuration environment [default]: 

        Looking for resources needed for deployment: Found!

                Managed S3 bucket: aws-sam-cli-managed-default-samclisourcebucket-1jjy7crwtboxt
                A different default S3 bucket can be set in samconfig.toml

        Saved arguments to config file
        Running 'sam deploy' for future deployments will use the parameters saved above.
        The above parameters can be changed by modifying samconfig.toml
        Learn more about samconfig.toml syntax at 
        https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html
The push refers to repository [{AWSアカウントID}.dkr.ecr.ap-northeast-1.amazonaws.com/test-lambda3]
6670d08613b8: Pushed 
288bf7b4ecd2: Pushed 
fd7b79127d3f: Pushed 
467c3002b991: Pushed 
d6fa53d6caa6: Pushed 
9061a595f0d9: Pushed 
e9f6c7e7646b: Pushed 
af6d16f2417e: Pushed 
helloworldfunction-b77be1b0ba0f-nodejs12.x-v1: digest: sha256:b3d89bf30af13b71e233041361e4d5227f7efa175e974a44a55c721d64aced25 size: 1998


        Deploying with following values
        ===============================
        Stack name                   : lambda3
        Region                       : ap-northeast-1
        Confirm changeset            : True
        Deployment image repository  : {AWSアカウントID}.dkr.ecr.ap-northeast-1.amazonaws.com/test-lambda3
        Deployment s3 bucket         : aws-sam-cli-managed-default-samclisourcebucket-1jjy7crwtboxt
        Capabilities                 : ["CAPABILITY_IAM"]
        Parameter overrides          : {}
        Signing Profiles           : {}

Initiating deployment
=====================
HelloWorldFunction may not have authorization defined.
Uploading to lambda3/190a864b18340f9d6bc8ff22ad0d89de.template  1170 / 1170.0  (100.00%)

Waiting for changeset to be created..

CloudFormation stack changeset
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
Operation                                 LogicalResourceId                         ResourceType                              Replacement                             
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Add                                     HelloWorldFunctionHelloWorldPermissionP   AWS::Lambda::Permission                   N/A                                     
                                          rod                                                                                                                         
+ Add                                     HelloWorldFunctionRole                    AWS::IAM::Role                            N/A                                     
+ Add                                     HelloWorldFunction                        AWS::Lambda::Function                     N/A                                     
+ Add                                     ServerlessRestApiDeployment47fc2d5f9d     AWS::ApiGateway::Deployment               N/A                                     
+ Add                                     ServerlessRestApiProdStage                AWS::ApiGateway::Stage                    N/A                                     
+ Add                                     ServerlessRestApi                         AWS::ApiGateway::RestApi                  N/A                                     
---------------------------------------------------------------------------------------------------------------------------------------------------------------------

Changeset created successfully. arn:aws:cloudformation:ap-northeast-1:{AWSアカウントID}:changeSet/samcli-deploy1608344052/64c3b913-393f-40b7-9080-852c425e87a6


Previewing CloudFormation changeset before deployment
======================================================
Deploy this changeset? [y/N]: y

2020-12-19 11:14:32 - Waiting for stack create/update to complete

CloudFormation events from changeset
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
ResourceStatus                            ResourceType                              LogicalResourceId                         ResourceStatusReason                    
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
CREATE_IN_PROGRESS                        AWS::IAM::Role                            HelloWorldFunctionRole                    -                                       
CREATE_IN_PROGRESS                        AWS::IAM::Role                            HelloWorldFunctionRole                    Resource creation Initiated             
CREATE_COMPLETE                           AWS::IAM::Role                            HelloWorldFunctionRole                    -                                       
CREATE_IN_PROGRESS                        AWS::Lambda::Function                     HelloWorldFunction                        -                                       
CREATE_IN_PROGRESS                        AWS::Lambda::Function                     HelloWorldFunction                        Resource creation Initiated             
CREATE_COMPLETE                           AWS::Lambda::Function                     HelloWorldFunction                        -                                       
CREATE_IN_PROGRESS                        AWS::ApiGateway::RestApi                  ServerlessRestApi                         Resource creation Initiated             
CREATE_IN_PROGRESS                        AWS::ApiGateway::RestApi                  ServerlessRestApi                         -                                       
CREATE_COMPLETE                           AWS::ApiGateway::RestApi                  ServerlessRestApi                         -                                       
CREATE_IN_PROGRESS                        AWS::Lambda::Permission                   HelloWorldFunctionHelloWorldPermissionP   Resource creation Initiated             
                                                                                    rod                                                                               
CREATE_IN_PROGRESS                        AWS::Lambda::Permission                   HelloWorldFunctionHelloWorldPermissionP   -                                       
                                                                                    rod                                                                               
CREATE_IN_PROGRESS                        AWS::ApiGateway::Deployment               ServerlessRestApiDeployment47fc2d5f9d     -                                       
CREATE_COMPLETE                           AWS::ApiGateway::Deployment               ServerlessRestApiDeployment47fc2d5f9d     -                                       
CREATE_IN_PROGRESS                        AWS::ApiGateway::Deployment               ServerlessRestApiDeployment47fc2d5f9d     Resource creation Initiated             
CREATE_IN_PROGRESS                        AWS::ApiGateway::Stage                    ServerlessRestApiProdStage                -                                       
CREATE_IN_PROGRESS                        AWS::ApiGateway::Stage                    ServerlessRestApiProdStage                Resource creation Initiated             
CREATE_COMPLETE                           AWS::ApiGateway::Stage                    ServerlessRestApiProdStage                -                                       
CREATE_COMPLETE                           AWS::Lambda::Permission                   HelloWorldFunctionHelloWorldPermissionP   -                                       
                                                                                    rod                                                                               
CREATE_COMPLETE                           AWS::CloudFormation::Stack                lambda3                                   -                                       
---------------------------------------------------------------------------------------------------------------------------------------------------------------------

CloudFormation outputs from deployed stack
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
Outputs                                                                                                                                                             
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
Key                 HelloWorldFunctionIamRole                                                                                                                       
Description         Implicit IAM Role created for Hello World function                                                                                              
Value               arn:aws:iam::{AWSアカウントID}:role/lambda3-HelloWorldFunctionRole-3J1HNC0XM3VJ                                                                      

Key                 HelloWorldApi                                                                                                                                   
Description         API Gateway endpoint URL for Prod stage for Hello World function                                                                                
Value               https://imdapkybi1.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/                                                                         

Key                 HelloWorldFunction                                                                                                                              
Description         Hello World Lambda Function ARN                                                                                                                 
Value               arn:aws:lambda:ap-northeast-1:{AWSアカウントID}:function:lambda3-HelloWorldFunction-F9EZCIWJOS08                                                     
---------------------------------------------------------------------------------------------------------------------------------------------------------------------

Successfully created/updated stack - lambda3 in ap-northeast-1
```

しばらく待つとデプロイが完了しています。
作成したlambdaを確認すると、イメージを元に作成されていることがわかります。
![スクリーンショット 2020-12-19 14.09.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255007/c4a750a5-44d5-f4b1-d9ce-04d865141229.png)

API Gatewayも用意されているので、動作確認としてcurlコマンドでLambdaを実行してみます

```
$curl https://******.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/
{"message": "hello world"}
```

## 再デプロイをするとき
試しにソースコードを"hello world"ではなく"hello world say yeah"とメッセージを返すように変更してデプロイしなおしてみます。

```diff:app.js
// const axios = require('axios')
// const url = 'http://checkip.amazonaws.com/';
let response;

exports.lambdaHandler = async (event, context) => {
    try {
        // const ret = await axios(url);
        response = {
            'statusCode': 200,
            'body': JSON.stringify({
-               message: 'hello world',
+               message: 'hello world say yeah',
                // location: ret.data.trim()
            })
        }
    } catch (err) {
        console.log(err);
        return err;
    }

    return response
};
```

その後sam cli経由でbuild → deployの順に実行してデプロイを実施します。

```
$ sam build
$ sam deploy
```

しばらく待つとデプロイされるので、再度curlコマンドを実行すると、ソースコードが変更されていることを確認できると思います。

```
$curl https://******.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/
{"message": "hello world say yeah"}
```
変更されていますね :D


# Github Actionsで自動デプロイ
では最後にgithub actionsを利用して ソースコードの変更後にmainブランチへの変更を検知した場合の自動デプロイを行います。
今回は以下のディレクトリ構成で管理されているリポジトリの中でlambda3/内のファイルに変更があったcommitがmainブランチに追加された場合にgithub actionsでworkflowを動かし、sam deployを実行した上でlambdaへの自動デプロイを行うようにします。

```
$ tree .
.
├── lambda1
├── lambda2
└── lambda3
    ├── README.md
    ├── events
    │   └── event.json
    ├── hello-world
    │   ├── Dockerfile
    │   ├── app.js
    │   ├── package.json
    │   └── tests
    │       └── unit
    │           └── test-handler.js
    ├── samconfig.toml
    └── template.yaml
```

行うことのイメージとしては以下の図のような感じになります。
![githubactions_sam_deploy.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255007/516addd2-e1e8-782b-ab37-adf8255ea26d.png)


github actionsでSAM経由でのデプロイを実行するためには、github actionsで使用するデプロイ用のマシンユーザーをIAMで作成し、必要なリソースに対する権限を追加した上で、アクセスキーとシークレットキーを用意しておいてください。
また、上記で取得したAccesskeyとSecretKeyはgithub actionsで使用するので、githubリポジトリのSetting > Secretsにて以下のように事前に追加しておいてください。

![スクリーンショット 2020-12-19 23.50.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255007/b7704e11-d252-18ec-dcaf-e5a214f7e61c.png)

IAMの用意とデプロイユーザーのkeyをgithubに登録したらあとはリポジトリルートに.github/workflowsを作成し、任意の名前のyamlファイルを用意して以下の様に記述するだけになります。
今回はlambda3に対するdeployだったので、deploy3.ymlとしています。

```yml:.github/workflows/deploy3.yml
name: deploy3
on:
  push:
    branches: [ main ]
     paths:
      - "lambda3/*"
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ap-northeast-1
      - name: Set up Python
        uses: actions/setup-python@v1
        with:
          python-version: 3.7
      - name: Install SAM
        run: |
          python -m pip install --upgrade pip
          pip install aws-sam-cli

      - name: Build by SAM
        run: |
          cd lambda3
          sam build
      - name: Deploy by SAM
        run: |
          cd lambda3
          sam deploy --no-confirm-changeset
```

内容としてはmainブランチにpushされた時にlambda3/の何かしらのファイルが更新された場合に起動し、
SAM CLIをインストール→ sam buildでイメージをbuild → sam deployでデプロイをする仕組みになります。

上記ファイルを用意してmainブランチにpushしていただければ、
githubのactionsタブから以下の様にbuildが成功したことが確認できるようになると思います。
![スクリーンショット 2020-12-19 23.58.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255007/7389a926-1278-a104-c817-3a32722eae73.png)

これだけで自動デプロイができるようになりました。
github actions便利ですよね！