はじめに
Lambda関数をデプロイする際、CloudFormation(以下、CFn)を利用される方も多いと思います。
今まで知らなかったのですが、Lambda関数に乗せるソースコードとCFnテンプレートの両方で環境変数名を同時に変更するとダウンタイムが発生する場合があったので、備忘録として検証記事を書きます。
使用するCFnテンプレート
今回の検証に利用する、最小構成のLambda関数をデプロイするためのCFnテンプレートです。
Lambda関数のリソース定義において、EnvironmentにHOGE: 1234
を追加し、CodeにHOGE
を参照するPythonコードを直接書いています。
AWSTemplateFormatVersion: 2010-09-09
Resources:
LambdaFunction:
Type: AWS::Lambda::Function
Properties:
Runtime: python3.9
FunctionName: hoge
Handler: index.lambda_handler
Role: !GetAtt LambdaExecutionRole.Arn
Environment:
Variables:
HOGE: 1234
Code:
ZipFile: |
import os
def lambda_handler(event, context):
print(os.environ['HOGE'])
LambdaExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
LogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: /aws/lambda/hoge
ダウンタイムの発生を検証してみる
上記のCFnテンプレートを利用し、ソースコードとCFnテンプレートの環境変数名を同時に変更した場合に実際にダウンタイムが生じることを見てみます。
以下、CFnテンプレートのファイル名はminimum_template.yml
とします。
検証手順
1. CFnテンプレートをデプロイする
AWS CLIを利用し、cloudformationのcreate-stack
コマンドを実行してスタックを新規作成します。実行後、hogeという名前のスタックとLambda関数が作成されます。
aws cloudformation create-stack --stack-name hoge --template-body file://minimum_template.yml --capabilities CAPABILITY_NAMED_IAM
2. 環境変数名を変更して再デプロイする
手順1でのデプロイ完了後、以下のようにLambda関数リソース定義のEnvironmentとCodeの2箇所に含まれているHOGE
をFUGA
に変更します。
LambdaFunction:
Type: AWS::Lambda::Function
Properties:
Runtime: python3.9
FunctionName: hoge
Handler: index.lambda_handler
Role: !GetAtt LambdaExecutionRole.Arn
Environment:
Variables:
FUGA: 1234 # HOGE -> FUGAに変更
Code:
ZipFile: |
import os
def lambda_handler(event, context):
print(os.environ['FUGA']) # HOGE -> FUGAに変更
上記変更後、スタックを更新するためにupdate-stack
コマンドを実行します。
aws cloudformation update-stack --stack-name hoge --template-body file://minimum_template.yml --capabilities CAPABILITY_NAMED_IAM
3. スタック更新中にLambda関数を実行し続ける
スタック更新中にダウンタイムが生じることを確認したいため、AWS CLIを利用してlambdaのinvoke
コマンドを実行し続けます。
--log-type
オプションにTail
を指定するとレスポンスとしてLogResult(Lambda関数の実行ログがbase64エンコードされた文字列)を含むjsonが返却されるため、これをjqコマンドでパースしたあとbase64コマンドでデコードしています。
while true; do
date
echo `aws lambda invoke --function-name hoge --log-type Tail output.txt` | jq -r .LogResult | base64 -d; echo
done
検証結果
以下に手順3の実行結果を載せます。今回の場合、HOGE
の参照失敗によるKeyErrorが約7秒間発生し続けていることがわかります。Lambda関数のソースコード更新よりも先に環境変数の更新が行われてHOGE
が削除されたことにより、一時的にコード側でHOGE
が参照できなくなっているように見えます。
2022年 7月26日 火曜日 17時23分45秒 JST
START RequestId: 0f33223b-fb0b-4e4c-85e7-6116d42b63bd Version: $LATEST
1234
END RequestId: 0f33223b-fb0b-4e4c-85e7-6116d42b63bd
REPORT RequestId: 0f33223b-fb0b-4e4c-85e7-6116d42b63bd Duration: 0.83 ms Billed Duration: 1 ms Memory Size: 128 MB Max Memory Used: 37 MB
2022年 7月26日 火曜日 17時23分45秒 JST
START RequestId: 06605b53-099b-49b8-bee6-4a3ebc2b691c Version: $LATEST
1234
END RequestId: 06605b53-099b-49b8-bee6-4a3ebc2b691c
REPORT RequestId: 06605b53-099b-49b8-bee6-4a3ebc2b691c Duration: 0.86 ms Billed Duration: 1 ms Memory Size: 128 MB Max Memory Used: 37 MB
2022年 7月26日 火曜日 17時23分46秒 JST
START RequestId: a6b389a0-97ab-4702-8875-d604855ef8ce Version: $LATEST
1234
END RequestId: a6b389a0-97ab-4702-8875-d604855ef8ce
REPORT RequestId: a6b389a0-97ab-4702-8875-d604855ef8ce Duration: 0.91 ms Billed Duration: 1 ms Memory Size: 128 MB Max Memory Used: 37 MB
2022年 7月26日 火曜日 17時23分47秒 JST
START RequestId: 217f85b5-ed2d-4839-acd4-6d452367893d Version: $LATEST
[ERROR] KeyError: 'HOGE'
Traceback (most recent call last):
File "/var/task/index.py", line 3, in lambda_handler
print(os.environ['HOGE'])
File "/var/lang/lib/python3.9/os.py", line 679, in __getitem__
raise KeyError(key) from NoneEND RequestId: 217f85b5-ed2d-4839-acd4-6d452367893d
REPORT RequestId: 217f85b5-ed2d-4839-acd4-6d452367893d Duration: 12.99 ms Billed Duration: 13 ms Memory Size: 128 MB Max Memory Used: 36 MB Init Duration: 106.15 ms
2022年 7月26日 火曜日 17時23分48秒 JST
START RequestId: 9362f269-cab2-4a2e-81b0-b239264663dd Version: $LATEST
[ERROR] KeyError: 'HOGE'
Traceback (most recent call last):
File "/var/task/index.py", line 3, in lambda_handler
print(os.environ['HOGE'])
File "/var/lang/lib/python3.9/os.py", line 679, in __getitem__
raise KeyError(key) from NoneEND RequestId: 9362f269-cab2-4a2e-81b0-b239264663dd
REPORT RequestId: 9362f269-cab2-4a2e-81b0-b239264663dd Duration: 1.91 ms Billed Duration: 2 ms Memory Size: 128 MB Max Memory Used: 37 MB
2022年 7月26日 火曜日 17時23分49秒 JST
START RequestId: 87ee1131-fdaa-4c57-8d10-0c5a1486d621 Version: $LATEST
[ERROR] KeyError: 'HOGE'
Traceback (most recent call last):
File "/var/task/index.py", line 3, in lambda_handler
print(os.environ['HOGE'])
File "/var/lang/lib/python3.9/os.py", line 679, in __getitem__
raise KeyError(key) from NoneEND RequestId: 87ee1131-fdaa-4c57-8d10-0c5a1486d621
REPORT RequestId: 87ee1131-fdaa-4c57-8d10-0c5a1486d621 Duration: 1.77 ms Billed Duration: 2 ms Memory Size: 128 MB Max Memory Used: 37 MB
2022年 7月26日 火曜日 17時23分50秒 JST
START RequestId: 16073262-fffb-4f16-991b-8f02bca1d08d Version: $LATEST
[ERROR] KeyError: 'HOGE'
Traceback (most recent call last):
File "/var/task/index.py", line 3, in lambda_handler
print(os.environ['HOGE'])
File "/var/lang/lib/python3.9/os.py", line 679, in __getitem__
raise KeyError(key) from NoneEND RequestId: 16073262-fffb-4f16-991b-8f02bca1d08d
REPORT RequestId: 16073262-fffb-4f16-991b-8f02bca1d08d Duration: 1.11 ms Billed Duration: 2 ms Memory Size: 128 MB Max Memory Used: 37 MB
2022年 7月26日 火曜日 17時23分51秒 JST
START RequestId: 483d5950-35b7-43b9-bae9-cf5d1bbb7482 Version: $LATEST
[ERROR] KeyError: 'HOGE'
Traceback (most recent call last):
File "/var/task/index.py", line 3, in lambda_handler
print(os.environ['HOGE'])
File "/var/lang/lib/python3.9/os.py", line 679, in __getitem__
raise KeyError(key) from NoneEND RequestId: 483d5950-35b7-43b9-bae9-cf5d1bbb7482
REPORT RequestId: 483d5950-35b7-43b9-bae9-cf5d1bbb7482 Duration: 1.19 ms Billed Duration: 2 ms Memory Size: 128 MB Max Memory Used: 37 MB
2022年 7月26日 火曜日 17時23分52秒 JST
START RequestId: fa098f17-6c93-4688-b982-f0ae7882ff48 Version: $LATEST
[ERROR] KeyError: 'HOGE'
Traceback (most recent call last):
File "/var/task/index.py", line 3, in lambda_handler
print(os.environ['HOGE'])
File "/var/lang/lib/python3.9/os.py", line 679, in __getitem__
raise KeyError(key) from NoneEND RequestId: fa098f17-6c93-4688-b982-f0ae7882ff48
REPORT RequestId: fa098f17-6c93-4688-b982-f0ae7882ff48 Duration: 1.32 ms Billed Duration: 2 ms Memory Size: 128 MB Max Memory Used: 37 MB
2022年 7月26日 火曜日 17時23分53秒 JST
START RequestId: 1bb5f8a5-61b3-48f3-a128-bf3aab39fee9 Version: $LATEST
[ERROR] KeyError: 'HOGE'
Traceback (most recent call last):
File "/var/task/index.py", line 3, in lambda_handler
print(os.environ['HOGE'])
File "/var/lang/lib/python3.9/os.py", line 679, in __getitem__
raise KeyError(key) from NoneEND RequestId: 1bb5f8a5-61b3-48f3-a128-bf3aab39fee9
REPORT RequestId: 1bb5f8a5-61b3-48f3-a128-bf3aab39fee9 Duration: 1.26 ms Billed Duration: 2 ms Memory Size: 128 MB Max Memory Used: 37 MB
2022年 7月26日 火曜日 17時23分54秒 JST
START RequestId: 05bc1601-0bf0-4042-a12c-1cd63b9dcf74 Version: $LATEST
1234
END RequestId: 05bc1601-0bf0-4042-a12c-1cd63b9dcf74
REPORT RequestId: 05bc1601-0bf0-4042-a12c-1cd63b9dcf74 Duration: 1.23 ms Billed Duration: 2 ms Memory Size: 128 MB Max Memory Used: 36 MB Init Duration: 120.57 ms
2022年 7月26日 火曜日 17時23分55秒 JST
START RequestId: 8cd572bf-4e19-432a-80f1-31d10b0f0471 Version: $LATEST
1234
END RequestId: 8cd572bf-4e19-432a-80f1-31d10b0f0471
REPORT RequestId: 8cd572bf-4e19-432a-80f1-31d10b0f0471 Duration: 1.61 ms Billed Duration: 2 ms Memory Size: 128 MB Max Memory Used: 36 MB
2022年 7月26日 火曜日 17時23分56秒 JST
START RequestId: 356670a1-c72c-44cf-8eb2-eac4b4450973 Version: $LATEST
1234
END RequestId: 356670a1-c72c-44cf-8eb2-eac4b4450973
REPORT RequestId: 356670a1-c72c-44cf-8eb2-eac4b4450973 Duration: 0.95 ms Billed Duration: 1 ms Memory Size: 128 MB Max Memory Used: 37 MB
おわりに
Lambda関数に乗せるソースコードとCFnテンプレートの両方で環境変数名を同時に変更するとダウンタイムが発生することを検証しました。
ソースコードよりも先に環境変数がデプロイされているようなので、今回のように環境変数名の変更を行いたい場合、CFnテンプレート側の対策として変更前の環境変数を残しておくか、ソースコード側の対策として環境変数が取得できない場合にデフォルト値を取得できるようにしておく、などがあると思いますが、なるべくやりたくないですね……。
最後に宣伝
株式会社オプティマインドでは、一緒に働く仲間を大募集中です。
カジュアル面談も大歓迎ですので、気軽にお声がけください。
【エンジニア領域の募集職種】
●ソフトウェアエンジニア
●QAエンジニア
●Androidアプリエンジニア
●組合せ最適化アルゴリズムエンジニア
●経路探索アルゴリズムエンジニア
●バックエンドエンジニア
●インフラエンジニア
●UXUIデザイナー
【ビジネス領域の募集職種】
●セールスコンサルタント
●オペレーションコンサルタント