Systems Managerのパラメータストアを更新したあと、Lambdaを再デプロイしないと内容が反映されなかった話

AWS SAMで定義しているLambdaの環境変数に「Systems Managerのパラメータストア」を使っています。 このとき、パラメータストアの内容を更新するだけではLambdaの環境変数に反映されません。
2020.05.28

AWS SAMやCloudFormationでsAWS Systems Managerのパラメータストアを使っている方は多いと思います。 何らかの値をLambdaの環境変数として渡せば、templateファイル自体に内容が記載されないため、GitHub等でPublicなリポジトリにできたりします。

そんなパラメータストアですが、内容を変更したあと、Lambdaを再デプロイしないと値が反映されませんでした。という話です。

パラメータストアに値を追加

下記コマンドでSSM(AWS Systems Manager)のパラメータストアに適当な値を追加します。

$ aws ssm put-parameter \
    --type 'String' \
    --name '/Hoge/Message' \
    --value 'This is a pen.'
{
    "Version": 1,
    "Tier": "Standard"
}

AWS SAMで適当なLambdaを作成する

テンプレートファイルを修正

SSMパラメータストアから/Hoge/Messageの値を取得し、Lambdaの環境変数MESSAGEに設定しています。

template.yaml

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: ssm-parameter-sample

Parameters:
  Message:
    Type: AWS::SSM::Parameter::Value<String>

Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: hello_world/
      Handler: app.lambda_handler
      Runtime: python3.7
      Environment:
        Variables:
          MESSAGE: !Ref Message
      Timeout: 5
      Events:
        HelloWorld:
          Type: Api
          Properties:
            Path: /hello
            Method: get

Outputs:
  HelloWorldApi:
    Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"

Lambdaコードを作成

Lambdaの環境変数MESSAGEの内容をAPIのResponseBodyとしています。

app.py

import json
import os

MESSAGE = os.environ['MESSAGE']

def lambda_handler(event, context):
    return {
        'statusCode': 200,
        'body': json.dumps({
            'message': MESSAGE,
        }),
    }

デプロイする

下記コマンドでビルド&デプロイします。parameter-overridesには、SSMパラメータストアのKey名を与えています。

$ sam build

$ sam package \
    --output-template-file packaged.yaml \
    --s3-bucket hoge-sam-bucket

$ sam deploy \
    --template-file packaged.yaml \
    --stack-name Ssm-Parameter-Sample-Stack \
    --capabilities CAPABILITY_NAMED_IAM \
    --no-fail-on-empty-changeset \
    --parameter-overrides \
        Message=/Hoge/Message

動作確認する(初回)

APIエンドポイントを取得する

下記コマンドでAPIエンドポイントを取得します。

$ aws cloudformation describe-stacks \
		--stack-name Ssm-Parameter-Sample-Stack \
		--query 'Stacks[].Outputs'
[
    [
        {
            "OutputKey": "HelloWorldApi",
            "OutputValue": "https://xxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/"
        }
    ]
]

APIにアクセスする

最初にSSMパラメータストアに登録した内容が返ってきました。

$ curl https://xxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/
{"message": "This is a pen."}

動作確認する(パラメータストアを更新した)

パラメータストアの内容を更新する

下記コマンドでSSMパラメータストアの内容を更新します。overwriteオプションを付与しています。

$ aws ssm put-parameter \
    --overwrite \
    --type 'String' \
    --name '/Hoge/Message' \
    --value 'This is a banana.'
{
    "Version": 2,
    "Tier": "Standard"
}

APIにアクセスする

SSMパラメータストアを更新しましたが、APIの応答には反映されていません。

$ curl https://xxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/
{"message": "This is a pen."}

Lambdaの様子

マネジメントコンソールでLambdaを確認すると、環境変数は更新されていません。

動作確認する(再デプロイした)

再デプロイする

同じコマンドで再デプロイします。

$ sam build

$ sam package \
    --output-template-file packaged.yaml \
    --s3-bucket hoge-sam-bucket

$ sam deploy \
    --template-file packaged.yaml \
    --stack-name Ssm-Parameter-Sample-Stack \
    --capabilities CAPABILITY_NAMED_IAM \
    --no-fail-on-empty-changeset \
    --parameter-overrides \
        Message=/Hoge/Message

APIにアクセスする

APIの応答には反映されました!

$ curl https://xxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/
{"message": "This is a banana."}

Lambdaの様子

マネジメントコンソールでLambdaを確認すると、環境変数は更新されました!

さいごに

改めて考えてみると「そうですよね」としか言えないですが、知らなければ地味にハマりそうです。 SSMパラメータストアの内容を即時反映したい場合は、Lambdaの環境変数を使わずにコードで毎回取得すると良さそうですね。

参考