AWS SAMで管理するAWS Lambda関数を、単一のAWSアカウント内の複数環境にデプロイする

# Whats'？

AWS SAMで管理するAWS Lambda関数を、単一AWSアカウント内の複数回（別環境として）デプロイするのにはどうすればよいのかな？ということで、試してみました。

# AWS CloudFormationと複数環境

AWS SAMは、AWS CloudFormationの拡張です。

> AWS SAM は AWS CloudFormation の拡張であるため、AWS CloudFormation の信頼性の高いデプロイ機能を利用できます。

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

このため、AWS SAMで管理している内容を複数の環境に適用するには、AWS CloudFormationの考え方に従うのが妥当でしょう。


AWS CloudFormationのドキュメントによると、テンプレートを複数環境向けに利用するには、パラメーターやマッピング、条件セクションで環境間の差異を吸収していくようです。

> たとえば、開発、テスト、本番の環境を作成して、本番環境に実装する前に変更をテストすることができます。テンプレートを再利用可能にするには、パラメーター、マッピング、および条件セクションを使用してスタックの作成時にカスタマイズできるようにします。

[AWS CloudFormation ベストプラクティス / テンプレートを再利用して複数の環境にスタックを複製する](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/best-practices.html#reuse)

このあたりですね。

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/mappings-section-structure.html

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/conditions-section-structure.html

また、AWS SAMではパラメーターの設定は、`--parameter-overrides`（設定ファイルの場合は`parameter_overrides`）で行うようです。

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

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

これらを利用して、AWS SAMで管理するAWS Lambda関数を、複数環境にデプロイしてみます。

# やってみること

今回は、以下の内容をお題にしてみます。

- AWS SAMアプリケーションのデプロイ先を開発環境（`development`）と本番環境（`production`）の2つに対して行う
- アプリケーション自体は、AWS SAMのQuick StartからHello World Example（Node.js）をベースにして作成
  - AWS Lambda関数の名前は固定し、どの環境向けの関数なのかを名前でわかるようにする（※）
  - ひとつのAWS SAMテンプレートで、複数環境にデプロイできるようにカスタマイズ
- 各環境で異なる構成で動作していることがわかりやすいように、アプリケーション内で環境変数を参照するようにする
  - 参照する環境変数は、AWS SAMテンプレート内で環境別の値を設定する

※ … AWS Lambda関数名を固定しない（`FunctionName`を指定しない）場合は一意の名前が生成されるので、このお題の意味があまりないかもですが

# 環境

今回の環境は、こちらです。

```shell
$ sam --version
SAM CLI, version 1.37.0


$ aws --version
aws-cli/2.4.11 Python/3.8.8 Linux/5.4.0-94-generic exe/x86_64.ubuntu.20 prompt/off


$ node --version
v14.18.3


$ npm --version
6.14.15
```

なお、AWSのクレデンシャルは今回は環境変数に指定しているものとします。

```shell
$ export AWS_ACCESS_KEY_ID=.....
$ export AWS_SECRET_ACCESS_KEY=.....
$ export AWS_DEFAULT_REGION=ap-northeast-1
```

# AWS SAMアプリケーションを作成する

まずは、AWS SAMアプリケーションを作成します。`sam init`でアプリケーション名は`sam-hello-world`、テンプレートは`hello-world`、ランタイムはNode.js 14.xとします。

```shell
$ sam init \
  --name sam-hello-world \
  --runtime nodejs14.x \
  --app-template hello-world \
  --package-type Zip
```

ディレクトリ内へ移動。

```shell
$ cd sam-hello-world
```

ディレクトリ内の構成は、こんな感じです。

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

4 directories, 6 files
```

ポイントとなるファイルだけ表示しておきましょう。

AWS Lambda関数。

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

/**
 *
 * Event doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format
 * @param {Object} event - API Gateway Lambda Proxy Input Format
 *
 * Context doc: https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-context.html
 * @param {Object} context
 *
 * Return doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html
 * @returns {Object} object - API Gateway Lambda Proxy Output Format
 *
 */
exports.lambdaHandler = async (event, context) => {
    try {
        // const ret = await axios(url);
        response = {
            'statusCode': 200,
            'body': JSON.stringify({
                message: 'hello world',
                // location: ret.data.trim()
            })
        }
    } catch (err) {
        console.log(err);
        return err;
    }

    return response
};
```

AWS SAMテンプレート。

```yaml:template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  sam-hello-world

  Sample SAM Template for sam-hello-world

# 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 # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
    Properties:
      CodeUri: hello-world/
      Handler: app.lambdaHandler
      Runtime: nodejs14.x
      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

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
```

ここから、少し変更してみます。

AWS SAMテンプレートには、`FunctionName`と環境変数（`Environment`）を追加します。

```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:
      CodeUri: hello-world/
      Handler: app.lambdaHandler
      Runtime: nodejs14.x
      FunctionName: HelloWorldFunction
      Architectures:
        - x86_64
      Environment:
        Variables:
          APPLICATION_MESSAGE: World
      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
```

`Environment`に`APPLICATION_MESSAGE`という環境変数を追加しました。

AWS Lambda関数は、追加された`APPLICATION_MESSAGE`環境変数を参照するように修正します。

```javascript
exports.lambdaHandler = async (event, context) => {
    try {
        // const ret = await axios(url);
        response = {
            'statusCode': 200,
            'body': JSON.stringify({
                message: `Hello ${process.env['APPLICATION_MESSAGE']}`,
                // location: ret.data.trim()
            })
        }
    } catch (err) {
        console.log(err);
        return err;
    }

    return response
};
```

では、ビルドして

```shell
$ sam build
```

デプロイしてみます。

この時、最初から環境別を意識した形での実行にします。まずは開発環境（`development`）向けにしましょう。

```shell
$ sam deploy --guided
```

入力内容はこんな感じにしました。

```shell
        Setting default arguments for 'sam deploy'                                                                                                                                    
        =========================================                                                                                                                                     
        Stack Name [sam-app]: development-sam-hello-world                                                                                                                             
        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]: development
```

ここから生成される値。

```shell
        Deploying with following values                                                                                                                                               
        ===============================                                                                                                                                               
        Stack name                   : development-sam-hello-world                                                                                                                    
        Region                       : ap-northeast-1                                                                                                                                 
        Confirm changeset            : True                                                                                                                                           
        Disable rollback             : False                                                                                                                                          
        Deployment s3 bucket         : aws-sam-cli-managed-default-samclisourcebucket-1f8pzvbjpaczp                                                                                   
        Capabilities                 : ["CAPABILITY_IAM"]                                                                                                                             
        Parameter overrides          : {}                                                                                                                                             
        Signing Profiles             : {}
```

変更内容を確認して、進めます。

```shell
CloudFormation stack changeset
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Operation                                    LogicalResourceId                            ResourceType                                 Replacement                                
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Add                                        HelloWorldFunctionHelloWorldPermissionProd   AWS::Lambda::Permission                      N/A                                        
+ 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-deploy1642156897/137a0b76-fb85-433c-a389-7c43a9b40456
```

デプロイが終わりました。

```shell
2022-01-14 19:43:01 - Waiting for stack create/update to complete

CloudFormation events from stack operations
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
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                            -
CREATE_IN_PROGRESS                           AWS::ApiGateway::RestApi                     ServerlessRestApi                            Resource creation Initiated
CREATE_COMPLETE                              AWS::ApiGateway::RestApi                     ServerlessRestApi                            -
CREATE_IN_PROGRESS                           AWS::Lambda::Permission                      HelloWorldFunctionHelloWorldPermissionProd   -
CREATE_IN_PROGRESS                           AWS::ApiGateway::Deployment                  ServerlessRestApiDeployment47fc2d5f9d        -
CREATE_IN_PROGRESS                           AWS::Lambda::Permission                      HelloWorldFunctionHelloWorldPermissionProd   Resource creation Initiated
CREATE_IN_PROGRESS                           AWS::ApiGateway::Deployment                  ServerlessRestApiDeployment47fc2d5f9d        Resource creation Initiated
CREATE_COMPLETE                              AWS::ApiGateway::Deployment                  ServerlessRestApiDeployment47fc2d5f9d        -
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                      HelloWorldFunctionHelloWorldPermissionProd   -
CREATE_COMPLETE                              AWS::CloudFormation::Stack                   development-sam-hello-world                  -
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
```

アクセスして確認してみます。

```shell
$ curl https://[REST API ID].execute-api.ap-northeast-1.amazonaws.com/Prod/hello/
{"message":"Hello World"}
```

OKですね。

この時に作成された`samconfig.toml`は、以下のようになりました。

```toml:samconfig.toml
version = 0.1
[development]
[development.deploy]
[development.deploy.parameters]
stack_name = "development-sam-hello-world"
s3_bucket = "aws-sam-cli-managed-default-samclisourcebucket-1f8pzvbjpaczp"
s3_prefix = "development-sam-hello-world"
region = "ap-northeast-1"
confirm_changeset = true
capabilities = "CAPABILITY_IAM"
image_repositories = []
```

`samconfig.toml`が生成されたので、以降は`--config-env`を指定することでこの環境用の設定を利用することができます。

```shell
$ sam deploy --config-env development
```

この環境名で管理される項目一式のことを、テーブルと呼ぶみたいです。

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


では、このまま本番環境（`production`）用のものも進めてみます。

```shell
$ sam deploy --guided
```

先ほどは`development`だった部分を、`production`にして実行。

```shell
        Setting default arguments for 'sam deploy'                                                                                                                                    
        =========================================
        Stack Name [sam-app]: production-sam-hello-world
        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]: production

〜省略〜

        Deploying with following values
        ===============================
        Stack name                   : production-sam-hello-world
        Region                       : ap-northeast-1
        Confirm changeset            : True
        Disable rollback             : False
        Deployment s3 bucket         : aws-sam-cli-managed-default-samclisourcebucket-1f8pzvbjpaczp
        Capabilities                 : ["CAPABILITY_IAM"]
        Parameter overrides          : {}
        Signing Profiles             : {}
```

変更内容はこちら。

```shell
CloudFormation stack changeset
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Operation                                    LogicalResourceId                            ResourceType                                 Replacement
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Add                                        HelloWorldFunctionHelloWorldPermissionProd   AWS::Lambda::Permission                      N/A
+ 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
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
```

そして、このまま進めるとデプロイに失敗します。

```shell
CloudFormation events from stack operations
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
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_FAILED                                AWS::Lambda::Function                        HelloWorldFunction                           HelloWorldFunction already exists in stack
                                                                                                                                       arn:aws:cloudformation:ap-northeast-1:[AWSアカウントID]
                                                                                                                                       :stack/development-sam-hello-
                                                                                                                                       world/4f593cc0-7529-11ec-b829-0e71e619494f
ROLLBACK_IN_PROGRESS                         AWS::CloudFormation::Stack                   production-sam-hello-world                   The following resource(s) failed to
                                                                                                                                       create: [HelloWorldFunction]. Rollback
                                                                                                                                       requested by user.
DELETE_COMPLETE                              AWS::Lambda::Function                        HelloWorldFunction                           -
DELETE_IN_PROGRESS                           AWS::IAM::Role                               HelloWorldFunctionRole                       -
ROLLBACK_COMPLETE                            AWS::CloudFormation::Stack                   production-sam-hello-world                   -
DELETE_COMPLETE                              AWS::IAM::Role                               HelloWorldFunctionRole                       -
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Error: Failed to create/update the stack: production-sam-hello-world, Waiter StackCreateComplete failed: Waiter encountered a terminal failure state: For expression "Stacks[].StackStatus" we matched expected path: "ROLLBACK_COMPLETE" at least once
```

これは、すでに同一AWSアカウント内に同じ名前のAWS Lambda関数が存在しているからですね。
今回はAWS Lambda関数名を指定しつつ、この事象を回避しようといお題になっています。

なお、この時点で`samconfig.toml`の内容はこのようになっています。

```toml:samconfig.toml
version = 0.1
[development]
[development.deploy]
[development.deploy.parameters]
stack_name = "development-sam-hello-world"
s3_bucket = "aws-sam-cli-managed-default-samclisourcebucket-1f8pzvbjpaczp"
s3_prefix = "development-sam-hello-world"
region = "ap-northeast-1"
confirm_changeset = true
capabilities = "CAPABILITY_IAM"
image_repositories = []

[production]
[production.deploy]
[production.deploy.parameters]
stack_name = "production-sam-hello-world"
s3_bucket = "aws-sam-cli-managed-default-samclisourcebucket-1f8pzvbjpaczp"
s3_prefix = "production-sam-hello-world"
region = "ap-northeast-1"
confirm_changeset = true
capabilities = "CAPABILITY_IAM"
image_repositories = []
```

いったん、これらのスタックを削除しておきましょう。

```shell
## 開発環境用のリソースを削除
$ sam delete --config-env development


## 本番環境用のリソースを削除
$ sam delete --config-env production
```

# 複数環境に対応させる

では、AWS CloudFormationのベストプラクティスに習って、複数環境に対応できるようにAWS SAMテンプレートを修正していきます。

[AWS CloudFormation ベストプラクティス / テンプレートを再利用して複数の環境にスタックを複製する](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/best-practices.html#reuse)

まず、環境の切り替えにはパラメーターを使うことにします。`Environment`というパラメーターを定義しました。

```yaml
Parameters:
  Environment:
    Type: String
    AllowedValues:
      - development
      - production
```

`Environment`に指定した値をキーにして、マッピングを作成します。

```yaml
Mappings:
  EnvironmentConfig:
    development:
      FunctionNamePrefix: Dev
      ApplicationMessage: "World[development]"
    production:
      FunctionNamePrefix: Prd
      ApplicationMessage: "World[production]"
```

今回は、AWS Lambda関数名に付与するPrefixとAWS Lambda関数に設定する環境変数の2つにしました。

これを、AWS SAMテンプレート内のAWS Lambda関数のリソース定義に設定します。

```yaml
      FunctionName: !Join
        - ""
        - - !FindInMap
            - EnvironmentConfig
            - !Ref Environment
            - FunctionNamePrefix
          - "HelloWorldFunction"
      Architectures:
        - x86_64
      Environment:
        Variables:
          APPLICATION_MESSAGE: !FindInMap
                      - EnvironmentConfig
                      - !Ref Environment
                      - ApplicationMessage
```

`FindInMap`関数の使い方は、マッピングのドキュメントを見るとわかると思います。

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/mappings-section-structure.html

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-findinmap.html

`Join`関数は文字列連結ですね。

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-join.html

AWS SAMテンプレート全体としては、このようになりました。

```yaml:template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  sam-hello-world

  Sample SAM Template for sam-hello-world

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

Parameters:
  Environment:
    Type: String
    AllowedValues:
      - development
      - production

Mappings:
  EnvironmentConfig:
    development:
      FunctionNamePrefix: Dev
      ApplicationMessage: "World[development]"
    production:
      FunctionNamePrefix: Prd
      ApplicationMessage: "World[production]"

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:
      CodeUri: hello-world/
      Handler: app.lambdaHandler
      Runtime: nodejs14.x
      FunctionName: !Join
        - ""
        - - !FindInMap
            - EnvironmentConfig
            - !Ref Environment
            - FunctionNamePrefix
          - "HelloWorldFunction"
      Architectures:
        - x86_64
      Environment:
        Variables:
          APPLICATION_MESSAGE: !FindInMap
                      - EnvironmentConfig
                      - !Ref Environment
                      - ApplicationMessage
      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

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
```

次に、`samconfig.toml`での環境と、AWS SAMテンプレートで環境を表すパラメーターを紐付けます。

これには、`parameter_overrides`を使うことにします。

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

開発環境向けのものであれば、以下のように指定します。

```yaml
parameter_overrides = [
  "Environment=development"
]
```

全体としては、こうなりました。

```toml:samconfig.toml
version = 0.1
[development]
[development.deploy]
[development.deploy.parameters]
stack_name = "development-sam-hello-world"
s3_bucket = "aws-sam-cli-managed-default-samclisourcebucket-1f8pzvbjpaczp"
s3_prefix = "development-sam-hello-world"
region = "ap-northeast-1"
confirm_changeset = true
capabilities = "CAPABILITY_IAM"
image_repositories = []
parameter_overrides = [
  "Environment=development"
]

[production]
[production.deploy]
[production.deploy.parameters]
stack_name = "production-sam-hello-world"
s3_bucket = "aws-sam-cli-managed-default-samclisourcebucket-1f8pzvbjpaczp"
s3_prefix = "production-sam-hello-world"
region = "ap-northeast-1"
confirm_changeset = true
capabilities = "CAPABILITY_IAM"
image_repositories = []
parameter_overrides = [
  "Environment=production"
]
```

設定変更したので、`sam build`します。

```shell
$ sam build
```

あとは、`--config-env`を指定して環境別にデプロイします。

```shell
$ sam deploy --config-env development
```

実行時に、`parameter_overrides`の内容が入るようになります。

```shell
        Deploying with following values
        ===============================
        Stack name                   : development-sam-hello-world
        Region                       : ap-northeast-1
        Confirm changeset            : True
        Disable rollback             : False
        Deployment s3 bucket         : aws-sam-cli-managed-default-samclisourcebucket-1f8pzvbjpaczp
        Capabilities                 : ["CAPABILITY_IAM"]
        Parameter overrides          : {"Environment": "development"}
        Signing Profiles             : {}
```

デプロイ後、確認。

```shell
$ curl https://[開発環境のREST API ID].execute-api.ap-northeast-1.amazonaws.com/Prod/hello/
{"message":"Hello World[development]"}
```

本番環境用のものもデプロイ。

```shell
$ sam deploy --config-env production
```

`parameter_overrides`で、本番環境の名前が入るようになっています。

```shell
        Deploying with following values
        ===============================
        Stack name                   : production-sam-hello-world
        Region                       : ap-northeast-1
        Confirm changeset            : True
        Disable rollback             : False
        Deployment s3 bucket         : aws-sam-cli-managed-default-samclisourcebucket-1f8pzvbjpaczp
        Capabilities                 : ["CAPABILITY_IAM"]
        Parameter overrides          : {"Environment": "production"}
        Signing Profiles             : {}
```

今度はデプロイが成功するので、動作確認もできます。

```shell
$ curl https://[本番環境のREST API ID].execute-api.ap-northeast-1.amazonaws.com/Prod/hello/
{"message":"Hello World[production]"}
```

アプリケーションが取得している環境変数の内容も、開発環境のものと異なるものになりました。

関数名の確認。

```shell
$ aws lambda list-functions --query 'Functions[].FunctionName' | grep HelloWorld
    "PrdHelloWorldFunction",
    "DevHelloWorldFunction",
```

OKですね。

確認できたので、最後に削除して終了。

```shell
$ sam delete --config-env development
$ sam delete --config-env production
```

これで、AWS SAMで管理するAWS Lambda関数を、単一のAWSアカウント内の複数環境にデプロイすることができました。