4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

SAMのAutoPublishAliasでバージョンがうまく発行されないときの対処法

Last updated at Posted at 2022-09-06

はじめに

みなさま,こんにちは.
株式会社オプティマインドにて,GISエンジニアをしている@tkmbnです.

概要

SAMを用いたLambdaのデプロイ時にAutoPublishAliasを利用すると,うまくバージョンが発行されないときがありました.
対処法をいろいろと探っていたところ,良さそうな対処法を見つけたので,ご紹介いたします.

なぜ書いたか

SAMを用いて,Lambdaをデプロイしたが,以下のパターンのときに,うまくバージョンが発行されませんでした.

  • Layerの中身のみ変更
  • Lambdaの環境変数のみの変更

手動で,バージョンを発行し,エイリアスに設定をすれば,やりたいことはできるんですが,
CanaryDeployが適用できないのが課題でした.

本題

現状の環境

  • SAM テンプレートの内容
    • API Gateway
    • Lambda (複数)
      • 複数Lambda内で共通で利用するものを集めたLayer
      • 環境変数(CloudFormationのデプロイ時にParameter Storeから取得)
        • {{resolve:ssm:<parameter name>}} と,動的に取得するようにしています.
        • Lambdaの実行時に取得するようにしてもよいのですが,Parameter Storeの変更時からLambdaに適用されるまでの時間差がバラバラになってしまうことを防ぐため,再デプロイする形をとっています.
  • デプロイパイプライン
    • CodePipelineにて設定済み
    • CodeBuild → CloudFormation(Create Changeset → Execute Changeset)

解決までの道のり

試行錯誤1 : template.yaml内に VersionAliasを設定

temaplte.yamlに以下の内容を追加してみる.(Functionというリソースが定義されている前提です.)

+  LambdaVersion:
+    Type: AWS::Lambda::Version
+    Properties:
+      FunctionName: !Ref Function
+  LambdaAlias:
+    Type: AWS::Lambda::Alias
+      Properties:
+        FunctionName: !GetAtt Function.Arn
+         FunctionVersion: $LATEST
+         Name: test

この状態で,パイプラインを回すと...

arn:aws:lambda:<Region>:<AccountId>:function:<FunctionName>:<Version> already exists in stack arn:aws:cloudformation:<Region>:<AccountId>:stack/<StackName>/xxxxxxxxxxxxxxxxxx

すでにそのバージョンは存在しているよ!という旨のエラーが出てしまい,デプロイが失敗してしまいました.
この方法では不可能ということがわかりました.

試行錯誤2 : buildspec.yamlを変更

公式ドキュメントに以下のような記述がありました.

AutoPublishCodeSha256
新しい Lambda バージョンを公開するべきかどうかを決定するために使用される文字列値と、CodeUri の値です。

このプロパティは、DeploymentPreference オブジェクトが段階的なデプロイメント (サーバーレスアプリケーションの段階的なデプロイ に説明があります) 向けに設定されている、AutoPublishAlias プロパティが設定されており、デプロイメント間で変更されない、および CodeUri プロパティが設定されており、デプロイメント間で変更されないという特徴が AWS SAM テンプレートにある場合に発生する問題に対処します。

このシナリオは、Amazon Simple Storage Service (Amazon S3) の場所に保存されているデプロイパッケージが更新済みの Lambda 関数コードを使用する新しいデプロイパッケージに置き換えられたが、CodeUri プロパティがそのまま変更されていない (新しいデプロイパッケージが新しい Amazon S3 の場所にアップロードされ、CodeUri が新しい場所に変更される代わりに) という場合に発生する可能性があります。

このシナリオで段階的なデプロイを正常にトリガーするには、AutoPublishCodeSha256 に一意の値を提供する必要があります。

changeset生成時,S3上のcode_uriをもとに変化があったかどうかを判定しているようです.
CloudFormationにおいて,changesetを生成する際,ビルド時にアップロードしたS3からBuild Artifactをダウンロードしていますが,CodeBuildは頭が良いので,変更がない部分はもともとのものを再利用して,アップロードがされません.
なので,ビルド時のアップロード先を強制的に変更させてあげれば,CloudFormation側は,全く違うコードだと認識するはずです.

buildspec.yaml

version: 0.2

phases:
  pre_build:
    commands:
      - sam build
  build:
    commands:
-     - sam package --s3-bucket $S3_BUCKET --output-template-file 
+     - sam package --s3-bucket $S3_BUCKET --s3-prefix ${CODEBUILD_BUILD_NUMBER}  --output-template-file packaged-template.yml
artifacts:
  type: zip
  files:
    - packaged-template.yml
+ s3-prefix: ${CODEBUILD_BUILD_NUMBER}

ちょっとやりすぎなのかもしれないですが,sam package時に--s3-prefixを指定し,artifactsブロックでもs3-prefixをつけることで,CodeUriがビルド時に必ず変化するようにしています.
${CODEBUILD_BUILD_NUMBER}は,CodeBuildが動作する際に,毎回インクリメントし,環境変数として読み出せるものです.

この設定で,parameter storeの値のみを変更して再びパイプラインを回した結果が,以下の通りになります.

CodeBuildのコンソールログを見てみます.

~~~~

[Container] 2022/09/02 00:52:52 Entering phase BUILD
[Container] 2022/09/02 00:52:52 Running command sam package --s3-bucket $S3_BUCKET --s3-prefix ${CODEBUILD_BUILD_NUMBER}  --output-template-file packaged-template.yml

Uploading to 18/986dbea6d705bae9847d4aa950c86971  262144 / 57420023  (0.46%)
~~~~
Uploading to 18/253e0fb54662100c02bb3437891a7b10  7717 / 7717  (100.00%)
# アップロード先がちゃんと<BUILD NUMBER/hash>となっている.

~~~~

[Container] 2022/09/02 00:53:27 Phase complete: BUILD State: SUCCEEDED

続いて,CodeBuildがアップロードした先のS3バケットも確認します.
Screen Shot 2022-09-02 at 10.34.14.png

こちらでも,CodeBuildのビルド番号ごでフォルダが作成されていることが確認できました.

最終的な結果としては,
Lambdaにて,無事新しいバージョンが作成され,CanaryDeployも実行されました.
もちろん,Layerの中身のみの変更でも同様の結果が得られました,

まとめ

AutoPublishAliasを利用していて,環境変数やLayerの変更でうまくデプロイされない問題の解決策をご紹介させていただきました.

  • buildspec.yamlに以下を追加
    • sam package に --s3-prefix ${CODEBUILD_BUILD_NUMBER}
    • artifactsブロックに s3-prefix: ${CODEBUILD_BUILD_NUMBER}

これにより,CodeBuildがアップロードする先をビルドごとに必ず変化させることができ,まったく違うコードだと認識させることができました!

困っている方の手助けになれば,幸いです.
最後まで読んでいただきありがとうございした.
なにか疑問点,間違っている点,等ございましたら,コメントお願いいたします.

最後に宣伝

株式会社オプティマインドでは、一緒に働く仲間を大募集中です。
カジュアル面談も大歓迎ですので、気軽にお声がけください。

【エンジニア領域の募集職種】
ソフトウェアエンジニア
QAエンジニア
Androidアプリエンジニア
組合せ最適化アルゴリズムエンジニア
経路探索アルゴリズムエンジニア
バックエンドエンジニア
インフラエンジニア
UXUIデザイナー

【ビジネス領域の募集職種】
セールスコンサルタント
オペレーションコンサルタント

『オプティマインドってどんな会社?』については、こちらから
Wantedlyでもこちらで募集中

参考文献

4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?