0
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?

Serverless Framework から CloudFormation(SAM) に移行する

Posted at

はじめに

Lambda やその実行ログを出力する CloudWatch ロググループ、IAM、API Gateway などを Serverless Framework で管理していたが、V3 がサポートされなくなること、V4 からは有償化されることをきっかけに、CloudFormation(SAM)に移行することとなった。
この時の移行手順についてまとめる。

※基本的には以下を参考にさせていただきました。
https://dev.classmethod.jp/articles/aws-sam-template-import-resources/

SAM テンプレートで作成された import 用のスタックを準備する

Serverless Framework の実体は CloudFormation なので、CloudFormation の import 機能を使用して SAM に移行していく。
まずは SAM テンプレートで作成された、import 先となるスタックを準備する必要がある。(ここでは適当にリソースを作成して後で削除する)

とりあえず以下のようにしてデプロイする。

template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: import sam tmp stack

Globals:
  Function:
    Timeout: 3

Resources:
  TestFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: lambda-import-tmp
      Handler: app.lambda_handler
      Runtime: python3.13
      Architectures:
        - x86_64
samconfig.toml
version = 0.1

[stg.global.parameters]
stack_name = "charita-import-sam-test"

[stg.build.parameters]
debug    = true
cached   = true
parallel = true

[stg.validate.parameters]
lint = true

[stg.deploy.parameters]
debug = true
capabilities = "CAPABILITY_NAMED_IAM"
confirm_changeset = true
region = "ap-northeast-1"
s3_bucket = "charita-import-sam-test"
s3_prefix = "stg"
disable_rollback = false
sam build --use-container --config-env stg
sam deploy --config-env stg --profile hogehoge 

ちなみに --use-container オプションを使用すると、指定されたランタイムの Lambda 実行環境を厳密に模倣した Docker コンテナ内でビルドプロセスを実行することができ、以下のような問題に対応できる。(イメージは ECR Public から Pull)

  • Python のパッケージの中には、純粋な Python コードだけではなく C言語で書かれた拡張ライブラリ(NumPyPandas など) を含むものがあり、実際の Lambda 実行環境で正しく動作するために、適切な Linux ベースのコンパイル が必須
  • macOS や Windows でコンパイルすると、生成されるバイナリはそれぞれの OS に最適化され、Lambda の実行環境では動かない可能性がある
  • 各 OS では標準でインストールされているライブラリやシステムヘッダーが異なるため、同じソースコードでもコンパイル結果が異なり、Lambda で期待通りに動作しない恐れがある

※このオプションを Proxy 接続環境で使用する場合、sam cli の実行環境からは Proxy に接続できるが、実際にビルドする Docker コンテナからは Proxy に繋がらないというような問題が発生するため、以下記事のように対応する必要がある模様。

少し話は逸れたが、ここで作成されたスタックに対し、Serverless Framework のテンプレートを import していく。

import 用の変更セットを作成する

CloudFormation には import 機能があるため、import 用の変更セットを作成せずとも以下のようにして普通にできそうだが、どうやら SAM のテンプレートには対応していないようだった。

imoport 対応リソースは以下の通り。

そのため、import 用の変更セットを作成し適用という手順を追う必要がある。
ここで準備する必要があるのは以下。(命名規則は特になし)

  1. 先ほど作成したスタックの template.yaml
  2. import したいリソースが定義された import-template.yaml
  3. import したいリソースのリソースタイプ、論理名、識別子の対応が定義された import.txt

import-template.yaml

Serverless Framework で管理されているスタックのテンプレートから、import 対象の Resource ブロックをコピーし、1の template.yaml に追記する。
以下のようにする。
(今回は CloudWatch ロググループを import 対象とする)

import-template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: import sam tmp stack

Globals:
  Function:
    Timeout: 3

Resources:
  TestFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: lambda-import-tmp
      Handler: app.lambda_handler
      Runtime: python3.13
      Architectures:
        - x86_64

  # 以下を追記
  TestLogGroup:
    Type: AWS::Logs::LogGroup
    DeletionPolicy: Retain
    Properties:
      LogGroupName: /aws/lambda/lambda-import-tmp

この時、import 対象のリソースには必ず DeletionPolicy を付与する必要あり。
Retain である必要はなし

import.txt

import したいリソースのリソースタイプ、論理名、識別子を以下の形式で記述する。

import.txt
[
    {
        "ResourceType": "AWS::Logs::LogGroup",
        "LogicalResourceId":
            "TestLogGroup"
        ,
        "ResourceIdentifier": {
            "LogGroupName":"/aws/lambda/lambda-import-tmp"
        }
    }
]

この時指定する ResourceIdentifier は、一度コンソール上からリソースの import を進めてみるとわかる。
例えば以下のようにしてみると、LogGroupName というのが ResourceIdentifier で指定すべき値だということがわかる。

スクリーンショット 2025-04-15 15.56.35.png

尚、Lambda を import したい場合、上述の通り SAM のテンプレートには対応していないため、リソースタイプを Type: AWS::Serverless::Function のようにすることはできない。
そのため、通常の CloudFormation のテンプレートの通り Type: AWS::Lambda::Function とする。(import 完了後に変更可能)

以上で必要なファイルは準備できたが、まだこのままでは import できない。
これは、CloudFormation は同じリソースを複数のスタックで管理することができないためである。
なので、Serverless Framework で管理しているスタックを削除する必要がある。
この時、当然リソースが削除されてしまっては困るため、全てのリソースに対し DeletionPolicy: Retain を付与した状態でスタックを削除することで、一度スタックの管理外にしてやる。(以下参考)

スタックを削除する際、実際に DeletionPolicy: Retain が効いて削除されずに済むのかが確認できないところが心臓に悪いので、本当に DeletionPolicy: Retain が対象リソースに適用できているかというのは、改めてコンソール上からテンプレートを確認しておくことをお勧めする。

無事にスタックのみ削除し、リソースをスタックの管理外にできたら、AWS CLI コマンドで import 用の変更セットを作成する。
コマンドは以下のようになる。

aws cloudformation create-change-set \
  --stack-name charita-import-sam-test \
  --change-set-name import-changeset \
  --resources-to-import file://import.txt \
  --change-set-type IMPORT \
  --template-body file://import-template.yaml \
  --capabilities CAPABILITY_NAMED_IAM \
  --profile hogehoge

作成された変更セットは以下のようになり、「アクション」が「import」となっていることを確認し、これを実行してやれば無事 import 完了となる。

スクリーンショット 2025-04-15 10.46.16.png

あとは自由に samconfig.toml をいい感じにしてみたり、Lambda のリソースタイプを Type: AWS::Serverless::Function から Type: AWS::Lambda::Function に変えてみたりと、快適な SAM ライフを楽しむだけ。

Lambda を管理する上では非常に便利な SAM だが、Terraform の import より色々考慮事項が多いし、スタックの削除は本当にやりたくないからもっと簡単にしてほしい、、、

0
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
0
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?