AWS SAM における Lambda 関数のエイリアスとバージョンの重みづけについて
以前から、AWS SAM を使用して AWS Lambda 関数のエイリアスとバージョンの重みづけを設定したいなーと思ってました。
ただ、結論から言うと、AWS SAM 仕様では重みづけの設定する方法は無く、AWS CloudFormation のプロパティとして設定する必要があることがわかりました。
エイリアスやバージョンの発行、という観点だと、AWS SAM では、AutoPublishAlias というプロパティを使用できます。
このプロパティの指定だけで、AWS Lambda 関数のエイリアスと、それに関連付けられた AWS Lambda 関数のバージョンが自動的に発行されます。
AutoPublishAlias を指定している場合、SAM でスタックが作成、更新される都度に新しいバージョンが発行され、エイリアスの重みづけは常に 100% に設定されます。
AutoPublishAlias を指定したうえで、さらに DeploymentPreference というプロパティを指定すると、 新バージョンへの段階的な移行が可能になり、例えば Canary や Linear などの手法で、時間の経過とともに新バージョンに振り分けるトラフィック量を自動的に変更したり、CloudWatch Alarm と連動させて、デプロイをロールバックすることもできます。 docs.aws.amazon.com
この AutoPublishAlias と DeploymentPreference は、非常に強力かつ便利ではあるのですが、意外に単純なことができないことがわかりました。
それは、Canary や Linear などの手法ではなく、単に エイリアスと複数バージョンの重みづけを設定すること です。これができないのです。
例えば、次のような手順を AWS SAM AutoPublishAlias と DeploymentPreference を指定して 行うことはできません。
- AWS Lambda関数の バージョン 1を発行する。エイリアスと関連付けて重みづけは 100% とする。
- AWS Lambda関数のコードを更新して、バージョン 2を発行する。エイリアスで、バージョン 1 は90%、バージョン 2は 10%の重みづけにする。
- AWS Lambda関数の バージョン 2の、エイリアスて重みづけを 100% とする。
DeploymentPreference で Canary や Linear を指定するのも便利ですが、その場合は、あくまであらかじめ用意されている、Canary10Percent15Minutes や Linear10PercentEvery10Minutes というタイプから選ぶしかありません。
トラフィックを移行する割合を手動で指定したい、自分でトラフィックを切り替えるタイミングを制御したいという場合は、AWS SAM 仕様のプロパティでは対応するものが無いのです。
では、どうすればいいかというと、AWS CloudFormation のプロパティで指定する、という方法があります。
まず、AWS Lambda 関数の バージョン 1を発行し、エイリアスと関連付けて重みづけは 100% とするための SAM テンプレートの例をみてみましょう。
AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Globals: Function: Timeout: 3 Resources: HelloWorldFunction: Type: AWS::Serverless::Function Properties: FunctionName: HelloSAMAliasVersion CodeUri: hello_world/ Handler: app.lambda_handler Runtime: python3.7 HelloWorldFunctionVersion1: Type: AWS::Lambda::Version Properties: FunctionName: !Ref HelloWorldFunction Description: v1 HelloWorldFunctionAlias: Type: AWS::Lambda::Alias Properties: FunctionName: !Ref HelloWorldFunction FunctionVersion: !GetAtt HelloWorldFunctionVersion1.Version Name: live
SAM テンプレートとして記載していますが、AWS Lambda 関数のエイリアスやバージョンを発行する指定は、Type: AWS::Lambda::Version や Type: AWS::Lambda::Alias と、AWS CloudFormation のプロパティを指定しています。
このSAM テンプレートを使用して デプロイし、スタックを作成すると、エイリアス名 live で、最初のバージョンが重みづけ 100% で設定された状態になります。
次に、AWS Lambda 関数のコードを更新し、新しいバージョン 2として、エイリアス live に 10% の重みづけでトラフィックを振り分けたいとします。
その場合は、SAM テンプレートを次のように変更してデプロイします。
AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Globals: Function: Timeout: 3 Resources: HelloWorldFunction: Type: AWS::Serverless::Function Properties: FunctionName: HelloSAMAliasVersion CodeUri: hello_world/ Handler: app.lambda_handler Runtime: python3.7 HelloWorldFunctionVersion1: Type: AWS::Lambda::Version Properties: FunctionName: !Ref HelloWorldFunction Description: v1 HelloWorldFunctionVersion2: Type: AWS::Lambda::Version Properties: FunctionName: !Ref HelloWorldFunction Description: v2 HelloWorldFunctionAlias: Type: AWS::Lambda::Alias Properties: FunctionName: !Ref HelloWorldFunction FunctionVersion: !GetAtt HelloWorldFunctionVersion1.Version Name: live RoutingConfig: AdditionalVersionWeights: - FunctionVersion: !GetAtt HelloWorldFunctionVersion2.Version FunctionWeight: 0.1
デプロイが完了すると、バージョン 1が 90%、バージョン 2が 10% になったことを確認できます。
この後、バージョン 2 へ完全に切り替えたい場合は、このテンプレートの FunctionWeight: で指定する値を 1.0 変更してデプロイします。
これらの プロパティについては、次のドキュメントも参考にしてください。
AWS CloudFormation のプロパティを使うと、自分で重みづけや、切り替えタイミングを制御できるのはいいのですが、プロパティの記載量はどうしても増えます。
SAM であれば、次のように、AWS Lambda 関数 で AutoPublishAlias を指定しつつ、さらに API Gateway の APIとの統合もシンプルに指定できます。
HelloWorldFunction: Type: AWS::Serverless::Function Properties: CodeUri: hello_world/ Handler: app.lambda_handler Runtime: python3.7 AutoPublishAlias: live Events: HelloWorld: Type: Api Properties: Path: /hello Method: get
ただし、AWS CloudFormation のプロパティでエイリアスやバージョンを手動指定すると、このような書き方はできません。
なので、AutoPublishAlias で、自分でバージョンの重みづけができればいいのですが、それは現状ではサポートされていないようです。
(次の issue にも Feature request として挙げられていましたが、DeploymentPreferences を使いなさい、と close されてました。)
ちょっと残念ですね。