Closed11

AWS SAMを試してみる

kun432kun432

前提

前提は前回と同じ。

以下を参考にdevcontainerを作った。

https://zenn.dev/nmemoto/articles/using-aws-cdk-and-aws-sam-with-remote-containers

githubのテンプレートレポジトリにしている。

https://github.com/kun432/devcontainer-aws-cdk-sam

最初のサイトにworkspace周りの設定が含まれているが、ここはちょっと自分でハマってみたいので、一旦設定は入れてない。

とりあえず上記テンプレートレポジトリからレポジトリを作って、vscode devcontainerで作業することとする。足りなければ適宜編集していく。

なお、dockerはremote development で使用しているサーバ上で動かしている。Docker Destktopではないので注意。

kun432kun432

詳細は上のworkshopを参考に。

冒頭でプロジェクトディレクトリを作成しているが、gitレポジトリのルートをプロジェクトディレクトリとして使いたいのでスキップする。

s3バケット作成

$ aws s3 mb s3://aws-sam-sample-2023508

翻訳用Lambdaのディレクトリとファイルを作成

$ mkdir translate-function
$ touch translate-function/translate-function.py

SAMのテンプレートファイルを作成

$ touch template.yaml

それぞれ以下の内容で作成する。

translate-function/translate-function.py
import json
import logging

logger = logging.getLogger()
logger.setLevel(logging.INFO)

def lambda_handler(event, context):

    logger.info(event)

    return {
        'statusCode': 200,
        'body': json.dumps('Hello Hands on world!')
    }
template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: AWS Hands-on for Beginners - Serverless 2
Resources:
  TranslateLambda:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: translate-function-2
      CodeUri: ./translate-function
      Handler: translate-function.lambda_handler
      Runtime: python3.7
      Timeout: 5
      MemorySize: 256

SAMのテンプレートのリファレンスはここにある

https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-resources-and-properties.html

ではこれらをCloudFormationのパッケージにしていく

$ aws cloudformation package \
     --template-file template.yaml \
     --s3-bucket aws-sam-sample-2023508 \
     --output-template-file packaged-template.yaml

出力

Uploading to d33d23482e788e1ff1e5bf734af8de98  310 / 310.0  (100.00%)
Successfully packaged artifacts and wrote output template to file packaged-template.yaml.
Execute the following command to deploy the packaged template
aws cloudformation deploy --template-file /workspaces/aws-sam-sample/packaged-template.yaml --stack-name <YOUR STACK NAME>

packaged-template.yamlが生成される。中身はこんな感じ。

packaged-template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: AWS Hands-on for Beginners - Serverless 2
Resources:
  TranslateLambda:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: translate-function-2
      CodeUri: s3://aws-sam-sample-2023508/d33d23482e788e1ff1e5bf734af8de98
      Handler: translate-function.lambda_handler
      Runtime: python3.7
      Timeout: 5
      MemorySize: 256

CodeUriがS3に置き換わっているのがわかる。ここにLambdaのソースが置かれるのだと思う。

で先ほど実行したコマンドの出力結果に出ているdeployのコマンドを実行すればデプロイされるということになるが、ワークショップ内で指定されているコマンドは以下となっていた。

$ aws cloudformation deploy \
     --template-file ./packaged-template.yaml \
     --stack-name hands-on-serverless-2 \
     --capabilities CAPABILITY_IAM

--template-fileは相対なのか絶対なのかの違いだけなのでおいておく。--capabilities CAPABILITY_IAMはCloudFormationからIAMの操作が必要となるため付与する必要がある。

ということで実行した出力結果。

Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - hands-on-serverless-2

作成された模様。

さらに上記のLambdaからAmazon Translateを使えるようにSAMテンプレートを修正して、Lambdaのコードも変更する。

まずLambdaのコード。

translate-function/translate-function.py
import json
import boto3

translate = boto3.client('translate')

def lambda_handler(event, context):

    input_text = "こんにちは。ご機嫌いかがですか?"

    response = translate.translate_text(
        Text=input_text,
        SourceLanguageCode='ja',
        TargetLanguageCode='en'
    )

    output_text = response.get('TranslatedText')

    return {
        'statusCode': 200,
        'body': json.dumps({
            'output_text': output_text
        })
    }

boto3を入れてなかったので入れておく。

requirements.txt
boto3
$ pip install -r requirements.txt

次にSAMのテンプレート。こちらは大きく変わったわけではなくて、最後にIAMのマネージドポリシーをアタッチしてTranslateにアクセスできるようになっている。

template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: AWS Hands-on for Beginners - Serverless 2
Resources:
  TranslateLambda:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: translate-function-2
      CodeUri: ./translate-function
      Handler: translate-function.lambda_handler
      Runtime: python3.7
      Timeout: 5
      MemorySize: 256
      # 以下を追加
      Policies:
        - TranslateFullAccess

ではパッケージ化してデプロイする。

$ aws cloudformation package \
     --template-file template.yaml \
     --s3-bucket aws-sam-sample-2023508 \
     --output-template-file packaged-template.yaml

$ aws cloudformation deploy \
     --template-file ./packaged-template.yaml \
     --stack-name hands-on-serverless-2 \
     --capabilities CAPABILITY_IAM

テストしてみると、変更したものがデプロイされ正常に動いていることがわかる。

では次にAPI Gatewayを前段に配置してWeb APIとしてアクセスできるようにするように変更していく。

まずLambda。クエリパラメータを受けてTranslateに渡してその結果を返すというものになった。

translate-function/translate-function.py
import json
import boto3

translate = boto3.client(service_name='translate')

def lambda_handler(event, context):

    input_text = event['queryStringParameters']['input_text']

    response = translate.translate_text(
        Text=input_text,
        SourceLanguageCode="ja",
        TargetLanguageCode="en"
    )

    output_text = response.get('TranslatedText')

    return {
        'statusCode': 200,
        'body': json.dumps({
            'output_text': output_text
        }),
        'isBase64Encoded': False,
        'headers': {}
    }

次にSAMテンプレート。

template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: AWS Hands-on for Beginners - Serverless 2
Resources:
  TranslateLambda:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: translate-function-2
      CodeUri: ./translate-function
      Handler: translate-function.lambda_handler
      Runtime: python3.7
      Timeout: 5
      MemorySize: 256
      Policies:
        - TranslateFullAccess
      # 以下を追加
      Events:
        GetApi:
          Type: Api
          Properties:
            Path: /translate
            Method: get
            RestApiId: !Ref TranslateAPI
  TranslateAPI:
    Type: AWS::Serverless::Api
    Properties:
      Name: translate-api-2
      StageName: dev
      EndpointConfiguration: REGIONAL

Translate APIって書いてあるからAmazon Translateのリソース設定かと一瞬思ったけど、AWS::Serverless::ApiとあるのでこれがAPI Gatewayのことらしい。EventsがLambdaとAPI Gatewayを紐付けるために必要なプロパティで、!Refでリソース間の依存関係を指定するのはCloudFormationと同じ。

ではパッケージ化してデプロイ。

$ aws cloudformation package \
     --template-file template.yaml \
     --s3-bucket aws-sam-sample-2023508 \
     --output-template-file packaged-template.yaml

$ aws cloudformation deploy \
     --template-file ./packaged-template.yaml \
     --stack-name hands-on-serverless-2 \
     --capabilities CAPABILITY_IAM

API Gatewayが作成されている・Lambdaと紐付いている・Lambdaのコードが更新されている、ことを確認したら、ブラウザからAPI Gatewayのエンドポイントにアクセスしてみる。

https://XXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/Stage/translate?input_text=こんばんはー、今日は冷えますね。

結果

{"output_text": "Good evening, it's going to be cold today."}

ちゃんと動いていることが確認できた。

さらにDynamoDBを追加してリクエストの履歴をDynamoDBに保存するようにしていく。

Lambdaのコードは以下。詳細は割愛。

translate-function/translate-function.py
import json
import boto3
import datetime

translate = boto3.client(service_name='translate')

dynamodb_translate_history_tbl = boto3.resource('dynamodb').Table('translate-history-2')

def lambda_handler(event, context):

    input_text = event['queryStringParameters']['input_text']

    response = translate.translate_text(
        Text=input_text,
        SourceLanguageCode="ja",
        TargetLanguageCode="en"
    )

    output_text = response.get('TranslatedText')

    dynamodb_translate_history_tbl.put_item(
      Item = {
        "timestamp": datetime.datetime.now().strftime("%Y%m%d%H%M%S"),
        "input": input_text,
        "output": output_text
      }
    )

    return {
        'statusCode': 200,
        'body': json.dumps({
            'output_text': output_text
        }),
        'isBase64Encoded': False,
        'headers': {}
    }

SAMテンプレートは以下。

template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: AWS Hands-on for Beginners - Serverless 2
Resources:
  TranslateLambda:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: translate-function-2
      CodeUri: ./translate-function
      Handler: translate-function.lambda_handler
      Runtime: python3.7
      Timeout: 5
      MemorySize: 256
      Policies:
        - TranslateFullAccess
        - AmazonDynamoDBFullAccess     # 追加
      Events:
        GetApi:
          Type: Api
          Properties:
            Path: /translate
            Method: get
            RestApiId: !Ref TranslateAPI
  TranslateAPI:
    Type: AWS::Serverless::Api
    Properties:
      Name: translate-api-2
      StageName: dev
      EndpointConfiguration: REGIONAL
  # 以下を追加
  TranslateDynamoDbTbl:
    Type: AWS::Serverless::SimpleTable
    Properties:
      TableName: translate-history-2
      PrimaryKey:
        Name: timestamp
        Type: String
      ProvisionedThroughput:
        ReadCapacityUnits: 1
        WriteCapacityUnits: 1

DynamoDBテーブルリソースを追加してLambdaに権限を与えるという感じ。

再度パッケージ化してデプロイ。

$ aws cloudformation package \
     --template-file template.yaml \
     --s3-bucket aws-sam-sample-2023508 \
     --output-template-file packaged-template.yaml

$ aws cloudformation deploy \
     --template-file ./packaged-template.yaml \
     --stack-name hands-on-serverless-2 \
     --capabilities CAPABILITY_IAM

ブラウザからアクセスしてみる

https://XXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/Stage/translate?input_text=こんばんはー、今日は冷えますね。

ちゃんとレスポンスが返ってきたことを確認しつつ、DynamoDBを見てみるとテーブルが作成されていて、リクエストの内容が保存されていることがわかる。

ここまでで一旦完了、ということで、作成したリソースを削除していく。

ここまでのやり方だとaws-cliを使っているので、aws cloudformation delete-stackになると思うけどまあ今回はマネージメントコンソールから削除する。

  • CloudFormationで"hands-on-serverless-2"スタックを削除。これでLambda・API Gateway・DynamoDB・その他IAMロールなどが削除される。
  • S3は削除されないので中身を空にして削除する。
kun432kun432

SAM CLIを使う

ここまでのやり方だとSAMはCloudFormationの簡易版っていうぐらいでそこまで便利とは思えなかった。おそらくSAM CLIを使うと変わるのだと思う。ということでやっていく。

新しくレポジトリは用意した。

SAM CLIは予めdevcontainerに入れてあるのでスキップ。Dockerのインストールも言われているけど、最新のドキュメントにはそのあたりの記載がない。ただDocker-from-Dockerもdevcontainerで用意してあるのでおそらく大丈夫ではないかなと。

$ sam --version
SAM CLI, version 1.82.0
$ docker --version
Docker version 20.10.24+azure-1, build 297e1284d3bd092e9bc96076c3ddc4bb33f8c7ab
$ python --version
Python 3.9.16

ではプロジェクトの初期化

$ sam init

設定は対話形式で行われるので、順に設定していく。質問内容が以前とは変わっている模様。以下は参考までに。python3.10を選びたかったけどruntimeが対応していない様子なので3.9で。(Imageだったらできるのかな?)

Which template source would you like to use?
        1 - AWS Quick Start Templates
        2 - Custom Template Location
Choice: 1     # 1を選択

Choose an AWS Quick Start application template
        1 - Hello World Example
        2 - Multi-step workflow
        3 - Serverless API
        4 - Scheduled task
        5 - Standalone function
        6 - Data processing
        7 - Hello World Example With Powertools
        8 - Infrastructure event management
        9 - Serverless Connector Hello World Example
        10 - Multi-step workflow with Connectors
        11 - Lambda Response Streaming
        12 - Lambda EFS example
        13 - DynamoDB Example
        14 - Machine Learning
Template: 1     # 1を選択

Use the most popular runtime and package type? (Python and zip) [y/N]: N     # Nを選択

Which runtime would you like to use?
        1 - aot.dotnet7 (provided.al2)
        2 - dotnet6
        3 - dotnet5.0
        4 - dotnetcore3.1
        5 - go1.x
        6 - go (provided.al2)
        7 - graalvm.java11 (provided.al2)
        8 - graalvm.java17 (provided.al2)
        9 - java17
        10 - java11
        11 - java8.al2
        12 - java8
        13 - nodejs18.x
        14 - nodejs16.x
        15 - nodejs14.x
        16 - nodejs12.x
        17 - python3.9
        18 - python3.8
        19 - python3.7
        20 - python3.10
        21 - ruby2.7
        22 - rust (provided.al2)
Runtime: 17     # 17を選択

What package type would you like to use?
        1 - Zip
        2 - Image
Package type: 1     # 1を選択

Would you like to enable X-Ray tracing on the function(s) in your application?  [y/N]: N     # Bを選択

Would you like to enable monitoring using CloudWatch Application Insights?
For more info, please view https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch-application-insights.html [y/N]: N     # Nを選択

Project name [sam-app]:      # デフォルトのまま

以下のようにプロジェクトの設定が表示される。

Cloning from https://github.com/aws/aws-sam-cli-app-templates (process may take a moment)

    -----------------------
    Generating application:
    -----------------------
    Name: sam-app
    Runtime: python3.9
    Architectures: x86_64
    Dependency Manager: pip
    Application Template: hello-world
    Output Directory: .
    Configuration file: sam-app/samconfig.toml
    
    Next steps can be found in the README file at sam-app/README.md
        

Commands you can use next
=========================
[*] Create pipeline: cd sam-app && sam pipeline init --bootstrap
[*] Validate SAM template: cd sam-app && sam validate
[*] Test Function in the Cloud: cd sam-app && sam sync --stack-name {stack-name} --watch

で、プロジェクトディレクトリが作成される。

$ ls -a
.  ..  .devcontainer  .git  .gitignore  README.md  sam-app  .vscode

$ tree -a sam-app/
sam-app/
├── events
│   └── event.json
├── .gitignore
├── hello_world
│   ├── app.py
│   ├── __init__.py
│   └── requirements.txt
├── __init__.py
├── README.md
├── samconfig.toml
├── template.yaml
└── tests
    ├── __init__.py
    ├── integration
    │   ├── __init__.py
    │   └── test_api_gateway.py
    ├── requirements.txt
    └── unit
        ├── __init__.py
        └── test_handler.py

5 directories, 15 files

SAMのテンプレートやLambdaのコードも用意されている。テスト用のコードとかも見える。

CDKもそうだけど新しくディレクトリが切られるのね。ちょっとdevcontainerのディレクトリ構成を考えたほうがいいのかな?一旦そのへんはおいておいて。

プロジェクトディレクトリに移動。

$ cd sam-app

ファイルは一通り揃っているので、一旦このタイミングでファイルの内容を検証する。

$ sam validate

以下のように表示されればOK

/workspaces/aws-sam-cli-sample/sam-app/template.yaml is a valid SAM Template

パッケージを作成する

$ sam build

"Build Succeeded"となっていればいけてるっぽい。

Starting Build use cache
Manifest file is changed (new hash: 3298f13049d19cffaa37ca931dd4d421) or dependency folder (.aws-sam/deps/5f7d2a7a-b6ad-48cf-bde2-b6932e5a9197) is missing for (HelloWorldFunction), downloading dependencies and copying/building source
Building codeuri: /workspaces/aws-sam-cli-sample/sam-app/hello_world runtime: python3.9 metadata: {} architecture: x86_64 functions: HelloWorldFunction
Running PythonPipBuilder:CleanUp
Running PythonPipBuilder:ResolveDependencies
Running PythonPipBuilder:CopySource
Running PythonPipBuilder:CopySource

Build Succeeded

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

Commands you can use next
=========================
[*] Validate SAM template: sam validate
[*] Invoke Function: sam local invoke
[*] Test Function in the Cloud: sam sync --stack-name {{stack-name}} --watch
[*] Deploy: sam deploy --guided

ではデプロイ。

$ sam deploy --guided

色々対話形式で出てくるので順に答えていく。とりあえずよくわからないものもあるので今回は以下のような感じにした。

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

        Looking for config file [samconfig.toml] :  Found
        Reading default arguments  :  Success

        Setting default arguments for 'sam deploy'
        =========================================
        Stack Name [sam-app]: 
        AWS Region [ap-northeast-1]: ap-northeast-1
        #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]: Y
        #Preserves the state of previously provisioned resources when an operation fails
        Disable rollback [y/N]: 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]: 

しばらく待っていると以下のような確認が行われるので"y"ですすめる。

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


Changeset created successfully. arn:aws:cloudformation:ap-northeast-1:XXXXXXXXXXXX:changeSet/samcli-deploy1683539264/deb801d3-94a5-4abb-9807-d47bae3d9ae5


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

リソースが作成されていく

CloudFormation events from stack operations (refresh every 5.0 seconds)
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
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                     -                                        
(snip)

完了するとこんな感じで表示される。

CloudFormation outputs from deployed stack
-------------------------------------------------------------------------------------------------------------------------------------------
Outputs                                                                                                                                   
-------------------------------------------------------------------------------------------------------------------------------------------
Key                 HelloWorldFunctionIamRole                                                                                             
Description         Implicit IAM Role created for Hello World function                                                                    
Value               arn:aws:iam::XXXXXXXXXXXX:role/sam-app-HelloWorldFunctionRole-1315DUBYI6ZW                                            

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

Key                 HelloWorldFunction                                                                                                    
Description         Hello World Lambda Function ARN                                                                                       
Value               arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:sam-app-HelloWorldFunction-HckQCM18lmkr                           
-------------------------------------------------------------------------------------------------------------------------------------------


Successfully created/updated stack - sam-app in ap-northeast-1

ということで、API GatewayからLambdaが応答するかためしてみる。ブラウザからアクセス。

https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello

ちゃんと応答している。

{"message": "hello world"}

で、これは実際にAWS上にデプロイした形だがローカルでも確認ができる。

$ sam local start-lambda

実行してみるとこうなる。

Initializing the lambda functions containers.
Local image was not found.
Removing rapid images for repo public.ecr.aws/sam/emulation-python3.9
Building image...Lambda functions containers initialization failed because of Credentials store docker-credential-dev-containers-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx exited with "".
Error: Lambda functions containers initialization failed

でこれはチョットよくわからないのだが、devcontainer内の以下が悪さをしている様子。

~/.docker/credStore
{
        "credsStore": "dev-containers-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

これを削除するかリネームしてしまう。今回はリネームした。

$ mv ~/.docker/config.json ~/.docker/config.json_BAK

もう一度実行してみる。

$ sam local start-lambda

お、立ち上がってきた。

2023-05-08 10:09:22 WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:3001
2023-05-08 10:09:22 Press CTRL+C to quit

もう一つターミナルを開いて直接Lambdaを叩いてみる。

aws lambda invoke --function-name "HelloWorldFunction" --endpoint-url "http://127.0.0.1:3001" --no-verify-ssl out.txt

以下のレスポンスが返ってくればOKとある。

{
    "StatusCode": 200
}

でサーバが立ち上がっている方のコンソールにも以下のようにリクエストが来ていることがわかるが・・・

2023-05-08 10:17:45,830 | Invoking app.lambda_handler (python3.9)
(snip)
2023-05-08 10:18:05,923 | Timed out while attempting to establish a connection to the container. You can increase this timeout by setting the SAM_CLI_CONTAINER_CONNECTION_TIMEOUT environment variable. The current timeout is 20.0 (seconds).
2023-05-08 10:18:05 127.0.0.1 - - [08/May/2023 10:18:05] "POST /2015-03-31/functions/HelloWorldFunction/invocations HTTP/1.1" 200 -

なんかタイムアウトしているみたい。SAM_CLI_CONTAINER_CONNECTION_TIMEOUTを増やしてもダメだった。

やはり以下の記事にあるのと同じ状態になる模様。

https://zenn.dev/nmemoto/articles/using-aws-cdk-and-aws-sam-with-remote-containers

ということで、.devcontainer/devcontainer.jsonを修正する。

  "remoteUser": "vscode",
  "workspaceMount": "source=${localWorkspaceFolder},target=${localWorkspaceFolder},type=bind",
  "workspaceFolder": "${localWorkspaceFolder}",

再ビルドするとdevcontainerではworkspaceのパスが変わっているし、sam local start-lambdaで立ち上がるLambdaコンテナ側もマウントパスは正しいのだが、それでもタイムアウトしてしまう。。。

色々やってみたがLinux上のDockerだとダメなのかもしれない(上の記事や他の記事を見てもDocker Desktop for Win/Macになっている)。なんとなくhost.docker.internalがこの辺をよしなにやってくれてるのかなという気がしている。

MacのDocker Desktopで再度ためしてみる。

kun432kun432

MacのDocker Desktopで同じことをやってみた。結論からいうと問題なし。

$ sam local start-lambda --container-host host.docker.internal
$ aws lambda invoke --function-name "HelloWorldFunction" --endpoint-url "http://127.0.0.1:3001" --no-verify-ssl out.txt
{
    "StatusCode": 200
}

タイム・アウトしてない。

Invoking app.lambda_handler (python3.9)
Reuse the created warm container for Lambda function 'HelloWorldFunction'
Lambda function 'HelloWorldFunction' is already running
END RequestId: 65e4328e-0706-431b-a076-89988d1ce3f1
REPORT RequestId: 65e4328e-0706-431b-a076-89988d1ce3f1  Init Duration: 0.25 ms  Duration: 122.47 ms     Billed Duration: 123 ms Memory Size: 128 MB    Max Memory Used: 128 MB
2023-05-09 03:29:51 127.0.0.1 - - [09/May/2023 03:29:51] "POST /2015-03-31/functions/HelloWorldFunction/invocations HTTP/1.1" 200 -

こちらも。

$ sam local invoke HelloWorldFunction --no-event --container-host host.docker.internal
Invoking app.lambda_handler (python3.9)
Local image is up-to-date
Using local image: public.ecr.aws/lambda/python:3.9-rapid-x86_64.

Mounting /Users/kun432/repository/aws-sam-cli-sample/sam-app/.aws-sam/build/HelloWorldFunction as /var/task:ro,delegated, inside runtime container
START RequestId: 717df814-f6af-42c5-9e69-652433a8f8e4 Version: $LATEST
{"statusCode": 200, "body": "{\"message\": \"hello world\"}"}END RequestId: 717df814-f6af-42c5-9e69-652433a8f8e4
REPORT RequestId: 717df814-f6af-42c5-9e69-652433a8f8e4  Init Duration: 0.25 ms  Duration: 118.08 ms     Billed Duration: 119 ms Memory Size: 128 MB    Max Memory Used: 128 MB

うーん、やっぱりDocker Desktopが良しなにやってくれてる気がするなぁ。host.docker.internalってのが重要なのかなと。

このへんなのかな。

https://qiita.com/skobaken/items/03a8b9d0e443745862ac

https://kazuhira-r.hatenablog.com/entry/2022/05/21/152825

うーん、シンプルにdevcontainerだけで出来てるのでdocker-composeに書き換えるというのはなぁ・・・かといってメインマシンを買い換えるというのもやりたくない(そろそろそういう時期ではあるのだけど。)まあdocker-composeに書き換えれば、ほぼどこでも動くだろうし。落ち着いたらやる。

kun432kun432

削除はsam deleteがあった。

$ sam delete
        Are you sure you want to delete the stack sam-app in the region ap-northeast-1 ? [y/N]: y
        Are you sure you want to delete the folder sam-app in S3 which contains the artifacts? [y/N]: y
        - Deleting S3 object with key sam-app/52182b25e6a404d6c7e9f18a8cf85d8f
        - Deleting S3 object with key sam-app/f48532e228cf6c9d3df7f931b59f17b8.template
        - Deleting Cloudformation stack sam-app

Deleted successfully
kun432kun432

まとめ

  • YAMLだけなのでTerraformとかCloudFormationとかと感覚的には同じで、そこにアプリのコードが含まれるって感じ。CDKと比べるとだいぶ違う。
  • ローカルでテストできるのは便利そう。Docker Desktopじゃなくて、Dockerサーバを使う場合はもう少し確認が必要。
    • DynamoDB使う場合はDynamoDB-Localを使うことになる
    • この辺のネットワーク周りを考えるとやはりdocker-compose化しちゃうのが良さげ。

個人的にはサーバレスで完結させるなら、CDK使わなくてもSAMで良い気がしたけど、監視とかそういうのを考え出すとやはりIaC的なものが欲しくなる。

組み合わせってこういうことなのかな?
https://logmi.jp/tech/articles/326602

kun432kun432

SAMでコンテナイメージも使えるのでやってみる。

$ sam init

違いはruntimeとpackage typeのところだけ。

Use the most popular runtime and package type? (Python and zip) [y/N]: N

Which runtime would you like to use?
        1 - aot.dotnet7 (provided.al2)
        2 - dotnet6
        3 - dotnet5.0
        4 - dotnetcore3.1
        5 - go1.x
        6 - go (provided.al2)
        7 - graalvm.java11 (provided.al2)
        8 - graalvm.java17 (provided.al2)
        9 - java17
        10 - java11
        11 - java8.al2
        12 - java8
        13 - nodejs18.x
        14 - nodejs16.x
        15 - nodejs14.x
        16 - nodejs12.x
        17 - python3.9
        18 - python3.8
        19 - python3.7
        20 - python3.10
        21 - ruby2.7
        22 - rust (provided.al2)
Runtime: 17

What package type would you like to use?
        1 - Zip
        2 - Image
Package type: 2

Based on your selections, the only dependency manager available is pip.
We will proceed copying the template using pip.

ディレクトリに移動

$ cd sam-app
$ tree -a
.
├── events
│   └── event.json
├── .gitignore
├── hello_world
│   ├── app.py
│   ├── Dockerfile
│   ├── __init__.py
│   └── requirements.txt
├── __init__.py
├── README.md
├── samconfig.toml
├── template.yaml
└── tests
    ├── __init__.py
    └── unit
        ├── __init__.py
        └── test_handler.py

4 directories, 13 files

Dockerfileとrequirements.txtがあるのがわかる。

Dockerfile
FROM public.ecr.aws/lambda/python:3.9

COPY requirements.txt ./
RUN python3.9 -m pip install -r requirements.txt -t .

COPY app.py ./

# Command can be overwritten by providing a different command in the template directly.
CMD ["app.lambda_handler"]
requirements.txt
request

SAMテンプレートのLambdaの部分はこう。PackageTypeとMetadataでDocker周りの設定がされているのがわかる。

template.yaml
Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
    Properties:
      PackageType: Image
      Architectures:
        - x86_64
      Events:
        HelloWorld:
          Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
          Properties:
            Path: /hello
            Method: get
    Metadata:
      Dockerfile: Dockerfile
      DockerContext: ./hello_world
      DockerTag: python3.9-v1

パッケージを作成してみる。

$ sam build

Dockerでビルドもやってくれる。


        SAM CLI now collects telemetry to better understand customer needs.

        You can OPT OUT and disable telemetry collection by setting the
        environment variable SAM_CLI_TELEMETRY=0 in your shell.
        Thanks for your help!

        Learn More: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-telemetry.html

Building codeuri: /Users/kun432/repository/aws-sam-cli-sample/sam-app runtime: None metadata: {'Dockerfile': 'Dockerfile', 'DockerContext': '/Users/kun432/repository/aws-sam-cli-sample/sam-app/hello_world', 'DockerTag': 'python3.9-v1'} architecture: x86_64 functions: HelloWorldFunction
Building image for HelloWorldFunction function
Setting DockerBuildArgs: {} for HelloWorldFunction function
Step 1/5 : FROM public.ecr.aws/lambda/python:3.9
3.9: Pulling from lambda/python 
Status: Downloaded newer image for public.ecr.aws/lambda/python:3.9 ---> 4acb7f05d221
Step 2/5 : COPY requirements.txt ./
 ---> cf338165fbd4
Step 3/5 : RUN python3.9 -m pip install -r requirements.txt -t .
 ---> Running in 36837a0d1597
Collecting requests
  Downloading requests-2.30.0-py3-none-any.whl (62 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 62.5/62.5 KB 1.3 MB/s eta 0:00:00
Collecting certifi>=2017.4.17
  Downloading certifi-2023.5.7-py3-none-any.whl (156 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 157.0/157.0 KB 7.7 MB/s eta 0:00:00
Collecting charset-normalizer<4,>=2
  Downloading charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (199 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 199.2/199.2 KB 12.7 MB/s eta 0:00:00
Collecting urllib3<3,>=1.21.1
  Downloading urllib3-2.0.2-py3-none-any.whl (123 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 123.2/123.2 KB 6.4 MB/s eta 0:00:00
Collecting idna<4,>=2.5
  Downloading idna-3.4-py3-none-any.whl (61 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 61.5/61.5 KB 5.2 MB/s eta 0:00:00
Installing collected packages: urllib3, idna, charset-normalizer, certifi, requests
Successfully installed certifi-2023.5.7 charset-normalizer-3.1.0 idna-3.4 requests-2.30.0 urllib3-2.0.2
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
WARNING: You are using pip version 22.0.4; however, version 23.1.2 is available.
You should consider upgrading via the '/var/lang/bin/python3.9 -m pip install --upgrade pip' command.
Removing intermediate container 36837a0d1597
 ---> 5292ab3aefdb
Step 4/5 : COPY app.py ./
 ---> 841d720fb5d7
Step 5/5 : CMD ["app.lambda_handler"]
 ---> Running in 15e4870eba67
Removing intermediate container 15e4870eba67
 ---> 6b71f8e85521
Successfully built 6b71f8e85521
Successfully tagged helloworldfunction:python3.9-v1


Build Succeeded

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

Commands you can use next
=========================
[*] Validate SAM template: sam validate
[*] Invoke Function: sam local invoke
[*] Test Function in the Cloud: sam sync --stack-name {{stack-name}} --watch
[*] Deploy: sam deploy --guided

まずはローカルでためしてみる

$ sam local invoke --container-host host.docker.internal 
Invoking Container created from helloworldfunction:python3.9-v1
Local image was not found.
Removing rapid images for repo helloworldfunction
Building image.................
Using local image: helloworldfunction:rapid-x86_64.

START RequestId: deaf8365-b843-43fd-a54a-dfcc8be57114 Version: $LATEST
{"statusCode": 200, "body": "{\"message\": \"hello world\"}"}END RequestId: deaf8365-b843-43fd-a54a-dfcc8be57114
REPORT RequestId: deaf8365-b843-43fd-a54a-dfcc8be57114  Init Duration: 0.40 ms  Duration: 165.12 ms     Billed Duration: 166 ms Memory Size: 128 MB    Max Memory Used: 128 MB

デプロイする。以前はECRも自分で作らないといけなかったようだが、今は作ってくれるらしい。

$ sam deploy --guided 

こういう感じで設定。ドキュメント見る限り、ECRについても聞いてくるとあるのだが、何も聞かれなかった。

PackageType: Image で宣言された関数またはレイヤーリソースがアプリケーションに含まれる場合、AWS SAM CLI を使用して、必要な Amazon Elastic Container Registry (Amazon ECR) リポジトリを自動的に作成することができます。このリポジトリを AWS SAM CLI で作成するには、--resolve-image-repos オプションまたは --guided オプションのいずれかを使用して、その後のプロンプトに Y で応答します。

https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-deploy.html

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

        Looking for config file [samconfig.toml] :  Found
        Reading default arguments  :  Success

        Setting default arguments for 'sam deploy'
        =========================================
        Stack Name [sam-app]: 
        AWS Region [ap-northeast-1]: 
        #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]: Y
        #Preserves the state of previously provisioned resources when an operation fails
        Disable rollback [y/N]: 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]: 

イメージがビルドされているのがわかる

85b5b030b35b: Pushed 
663927b9dabd: Pushed 
d4168391b5c8: Pushed 
091e7273b536: Pushed 
a4d4ba764b31: Pushed 
2d244e0816c6: Pushed 
ac6a33d11b17: Pushed 
84ea14de468a: Pushed 
9e50b5c2a61f: Pushed 
helloworldfunction-6b71f8e85521-python3.9-v1: digest: sha256:d0a030aa050fef9b4f7003abedfbf47c81ff692e8df302b992b1863bf400f9ae size: 2206

ECRが作成されているようだが、

        Deploying with following values
        ===============================
        Stack name                   : sam-app
        Region                       : ap-northeast-1
        Confirm changeset            : True
        Disable rollback             : False
        Deployment image repository  : 
                                       {
                                           "HelloWorldFunction": "XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/samapp7427b055/helloworldfunction19d43fc4repo"
                                       }
        Deployment s3 bucket         : aws-sam-cli-managed-default-samclisourcebucket-1ij83f43psag0
        Capabilities                 : ["CAPABILITY_IAM"]
        Parameter overrides          : {}
        Signing Profiles             : {}

ChangeSetにECRは含まれていないように見える。

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

ECRに作成されていた。

削除してみる

$ sam delete

なんか聞いてくる。

        Are you sure you want to delete the stack sam-app in the region ap-northeast-1 ? [y/N]: y
        Found ECR Companion Stack sam-app-7427b055-CompanionStack
        Do you want to delete the ECR companion stack sam-app-7427b055-CompanionStack in the region ap-northeast-1 ? [y/N]: 

なるほど、メインのCloudFormationスタック以外にcompanionスタックという形で作成されるのか。

ECRはここで管理されている。

進めてみると再度確認される。

        ECR repository samapp7427b055/helloworldfunction19d43fc4repo may not be empty. Do you want to delete the repository and all the images in it ? [y/N]: 

更に進めると削除される。

        - Deleting ECR repository samapp7427b055/helloworldfunction19d43fc4repo
        - Deleting ECR Companion Stack sam-app-7427b055-CompanionStack
        - Deleting Cloudformation stack sam-app

--guidedで何も聞かれなかったのだけが気になる。コードを見る限りは聞いてきても良さそうなものだけど。

https://github.com/aws/aws-sam-cli/blob/c3ce941ec2b4dd3edce759f0a85063a0284c810c/samcli/commands/deploy/guided_context.py#LL464C1-L464C1

kun432kun432

複数の環境

色々方針はあると思うけど、とりあえず以下のような感じがいいかなと思っている。

  • 本番(Prod)/開発(Dev)の2つに分ける
  • 全部分ける。
    • 例えばAPI Gatewayはステージで分けることもできるし、Lambdaならエイリアス/バージョニングで分けることができる。
    • が、リソースごとにやり方が異なるよりは、もう完全に分けてしまったほうが混乱しないという判断。

参考

https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html

https://www.cyberowl.co.jp/blog/technology/1634#7mw8fyo9

https://qiita.com/sawa-akabee/items/d4ea2cfeced78fec2beb

https://qiita.com/saba_miso/items/50080fc9b81d6460d666

https://stackoverflow.com/questions/68826108/how-to-deploy-to-different-environments-with-aws-sam

https://rarejob-tech-dept.hatenablog.com/entry/2020/11/20/190000

https://tech.fusic.co.jp/posts/2021-12-09-2021-12-09-aws-sam-samconfig/

https://blog.webcreativepark.net/2021/10/28-162051.html

やってみた

$ sam init

質問はこんな感じで。

Which template source would you like to use?
        1 - AWS Quick Start Templates
        2 - Custom Template Location
Choice: 1

Choose an AWS Quick Start application template
        1 - Hello World Example
        2 - Multi-step workflow
        3 - Serverless API
        4 - Scheduled task
        5 - Standalone function
        6 - Data processing
        7 - Hello World Example With Powertools
        8 - Infrastructure event management
        9 - Serverless Connector Hello World Example
        10 - Multi-step workflow with Connectors
        11 - Lambda Response Streaming
        12 - Lambda EFS example
        13 - DynamoDB Example
        14 - Machine Learning
Template: 1

Use the most popular runtime and package type? (Python and zip) [y/N]: N

Which runtime would you like to use?
        1 - aot.dotnet7 (provided.al2)
        2 - dotnet6
        3 - dotnet5.0
        4 - dotnetcore3.1
        5 - go1.x
        6 - go (provided.al2)
        7 - graalvm.java11 (provided.al2)
        8 - graalvm.java17 (provided.al2)
        9 - java17
        10 - java11
        11 - java8.al2
        12 - java8
        13 - nodejs18.x
        14 - nodejs16.x
        15 - nodejs14.x
        16 - nodejs12.x
        17 - python3.9
        18 - python3.8
        19 - python3.7
        20 - python3.10
        21 - ruby2.7
        22 - rust (provided.al2)
Runtime: 20

What package type would you like to use?
        1 - Zip
        2 - Image
Package type: 2

Based on your selections, the only dependency manager available is pip.
We will proceed copying the template using pip.

Would you like to enable X-Ray tracing on the function(s) in your application?  [y/N]: N

Would you like to enable monitoring using CloudWatch Application Insights?
For more info, please view https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch-application-insights.html [y/N]: N

Project name [sam-app]: 
$ cd sam-app

次にSAMテンプレートを修正する

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

  Sample SAM Template for sam-app

Globals:
  Function:
    Timeout: 3

Parameters:
  ENV:
    Type: String
    AllowedValues:
      - dev
      - prod
    Default: dev

Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub hello-world-${ENV}
      PackageType: Image
      Architectures:
        - x86_64
      Events:
        HelloWorld:
          Type: Api
          Properties:
            Path: /hello
            Method: get
      FunctionUrlConfig:
        AuthType: NONE
    Metadata:
      Dockerfile: Dockerfile
      DockerContext: ./hello_world
      DockerTag: !Ref ENV

Outputs:
  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
  HelloWorldFunctionUrl:
    Description: "Hello World Lambda Function URL Endpoint"
    Value:
      Fn::GetAtt: HelloWorldFunctionUrl.FunctionUrl

以下で外部からのパラメータを受けるようにする。デフォルトは"dev"にしている。

Parameters:
  ENV:
    Type: String
    AllowedValues:
      - dev
      - prod
    Default: dev

Lambdaの関数名に環境を付与するようにする。

  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub hello-world-${ENV}

今回はコンテナイメージを使うので、タグにも付与しておく。実際にはバージョン情報とかリリースとかコミットIDとかを付与したほうがいいのかなーと思うけど、とりま。

(snip)
  HelloWorldFunction:
(snip)
    Metadata:
      Dockerfile: Dockerfile
      DockerContext: ./hello_world
      DockerTag: !Ref ENV
(snip)

あと今回はAPI GatewayではなくLambda FunctionURLsを使うことにする。Lambdaのプロパティに以下を追加。今回はAuthTy

(snip)
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
(snip)
      FunctionUrlConfig:
        AuthType: NONE
(snip)

Outputsもそれに合わせて以下を追加。元々あったAPI Gatewayのエントリは削除した。

Outputs:
(snip)
  HelloWorldFunctionUrl:
    Description: "Hello World Lambda Function URL Endpoint"
    Value:
      Fn::GetAtt: HelloWorldFunctionUrl.FunctionUrl

パッケージ作成。

$ sam build
$ sam deploy --guided

質問はこんな感じ。デフォルトは"dev"としている。IAMとかLambdaの認証とか、色々詰めないといけないことはあるけど、とりま。

        Stack Name [sam-app]: sam-app-dev
        AWS Region [ap-northeast-1]: 
        Parameter ENV [dev]: 
        #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]: Y
        #Preserves the state of previously provisioned resources when an operation fails
        Disable rollback [y/N]: N
        HelloWorldFunction may not have authorization defined, Is this okay? [y/N]: y
        HelloWorldFunction Function Url 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]: 

完了したらこんな感じ。

CloudFormation outputs from deployed stack
--------------------------------------------------------------------------------------------------------------------------------------------
Outputs                                                                                                                                    
--------------------------------------------------------------------------------------------------------------------------------------------
Key                 HelloWorldFunctionIamRole                                                                                                                 
Description         Implicit IAM Role created for Hello World function                                                                                        
Value               arn:aws:iam::XXXXXXXXXXXX:role/sam-app-dev-HelloWorldFunctionRole-xxxxxxxxxxxx                                                           

Key                 HelloWorldFunctionUrl                                                                                                                     
Description         Hello World Lambda Function URL Endpoint                                                                                                  
Value               https://xxxxxxxxxxxxxxxx.lambda-url.ap-northeast-1.on.aws/                                                                

Key                 HelloWorldFunction                                                                                                                        
Description         Hello World Lambda Function ARN                                                                                                           
Value               arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:hello-world-dev                                                    
--------------------------------------------------------------------------------------------------------------------------------------------


Successfully created/updated stack - sam-dev in ap-northeast-1

FunctionURLにアクセスしてちゃんと応答が返ってきている。

$ curl https://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.lambda-url.ap-northeast-1.on.aws/    
{"message": "hello world"}

では次に"Prod"の設定をしつつデプロイ

$ sam deploy --guided

スタック名やENV、SAMの設定上の環境を"prod"向けに書き換えている。

        Stack Name [sam-app-dev]: sam-app-prod
        AWS Region [ap-northeast-1]: 
        Parameter ENV [dev]: prod
        #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]: Y
        #Preserves the state of previously provisioned resources when an operation fails
        Disable rollback [y/N]: N
        HelloWorldFunction may not have authorization defined, Is this okay? [y/N]: y
        HelloWorldFunction Function Url 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]: prod

作成されたものはこれ。

Outputs                                                                                                                                                       
---------------------------------------------------------------------------------------------------------------------------------------------------------------
Key                 HelloWorldFunctionIamRole                                                                                                                 
Description         Implicit IAM Role created for Hello World function                                                                                        
Value               arn:aws:iam::XXXXXXXXXXXX:role/sam-app-prod-HelloWorldFunctionRole-xxxxxxxxxxxx                                                           

Key                 HelloWorldFunctionUrl                                                                                                                     
Description         Hello World Lambda Function URL Endpoint                                                                                                  
Value               https://xxxxxxxxxxxx.lambda-url.ap-northeast-1.on.aws/                                                                

Key                 HelloWorldFunction                                                                                                                        
Description         Hello World Lambda Function ARN                                                                                                           
Value               arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:hello-world-prod                                                                      
---------------------------------------------------------------------------------------------------------------------------------------------------------------

なるほど。スタックを分けた場合にはスタック名がリソースに付与されるっぽい。Lambdaの関数名に環境を渡して命名してるけど、これって必要なんだろうか???

とりあえずできたリソースを見てみる。

$ aws cloudformation list-stacks | jq -r '.StackSummaries[] | select( .StackStatus != "DELETE_COMPLETE" ) | .StackName' | grep -i sam-app
sam-app-prod
sam-app-prod-93e0fccc-CompanionStack
sam-app-dev
sam-app-dev-341f0582-CompanionStack

$ aws lambda list-functions | jq -r '.Functions[] | .FunctionName' | grep "hello-world"
hello-world-prod
hello-world-dev

$ aws iam list-roles | jq -r '.Roles[] | .RoleName' | grep sam-app
sam-app-dev-HelloWorldFunctionRole-1LS1ITHGEYB1D
sam-app-prod-HelloWorldFunctionRole-7JLLWED3RK7O

ちゃんスタック分かれてるし、リソース名からどっちの環境なのか判断できる。でもこれならLambdaにもスタック名をプリフィクスとしてつけてほしい。FunctionNameでわざわざ環境変数付与したけどやっぱり不要かも。外してやってみる。

さっきは--guided使ったけどsamconfig.tomlの設定ができたら、以降はdeployで--config-envで環境指定すれば良い。指定しない場合はdefault(今回の設定だとdev)が読み込まれる。

$ sam build
$ sam deploy

結果

Outputs                                                                                                                                                       
---------------------------------------------------------------------------------------------------------------------------------------------------------------
Key                 HelloWorldFunctionIamRole                                                                                                                 
Description         Implicit IAM Role created for Hello World function                                                                                        
Value               arn:aws:iam::XXXXXXXXXXXX:role/sam-app-dev-HelloWorldFunctionRole-xxxxxxxxxxxx                                                           

Key                 HelloWorldFunctionUrl                                                                                                                     
Description         Hello World Lambda Function URL Endpoint                                                                                                  
Value               https://xxxxxxxxxxxx.lambda-url.ap-northeast-1.on.aws/                                                                

Key                 HelloWorldFunction                                                                                                                        
Description         Hello World Lambda Function ARN                                                                                                           
Value               arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:sam-app-dev-HelloWorldFunction-GRIkzKsOYDcA                                           
---------------------------------------------------------------------------------------------------------------------------------------------------------------

こっちでいいんじゃないかという気がする。ちゃんとスタック名でわかるし。template.yaml内での名称(HelloWorldFunction)が付与される感じっぽい。

kun432kun432

ということでGitHub Actionsでデプロイまでやっちゃう。

このスクラップは2023/10/13にクローズされました