ユニファ開発者ブログ

ユニファ株式会社プロダクトデベロップメント本部メンバーによるブログです。

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

こんにちは、SRE の中村です。

弊社では Lambda とその周辺リソースは基本的には Serverless Framework で管理してきましたが、V3 がサポートされなくなること、V4 からは有償化されることをきっかけに、CloudFormation(SAM)に移行することになりました。 Serverless Framework も実体は CloudFormation なので、文法などの違いはあるものの、特に問題なく進められるだろうと思っていましたが、やってみると意外にも面倒な点がありました。 以下にやり方をご紹介します。

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

CloudFormation にも Terraform と同じように import 機能があります。 なので、まずは SAM のテンプレートで作成された import 先となるスタックを準備して、それに対し import していく方針にします。

とりあえず以下のようにしてデプロイします。 空のテンプレートではスタックを作成できないので、ここでは適当にリソースを作成して後で削除します。

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: import to sam stack

Resources:
  TestSQS: 
    Type: AWS::SQS::Queue
    Properties:
      QueueName: sam-import-tmp

余談ですが、SAM テンプレートのデプロイ工程に置いて、sam buildコマンドの --use-container オプションを使用すると、指定されたランタイムの Lambda 実行環境を厳密に模倣した Docker コンテナ内でビルドプロセスを実行することができるのでオススメです。(Docker を起動させておく必要あり)

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

最初は import 用の変更セットを作成せずとも以下ドキュメントのようにして普通に import できそうだと思ったのですが、どうやら SAM のテンプレートには対応していないようでした。
スタックへの既存リソースのインポート - AWS CloudFormation

そのため、Lambda を import したい場合でもリソースタイプを Type: AWS::Serverless::Function のようにすることはできません。 通常の CloudFormation のテンプレートの通り Type: AWS::Lambda::Function として、import 完了後に変更する形になります。

ちなみに import に対応しているリソースは以下の通りです。
Resource type support - AWS CloudFormation

今回は SAM を使用したいので、import 用の変更セットを作成 -> 適用 という手順を追う必要があります。 ここで準備する必要があるのは以下の3つです。(命名規則は特になし)

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

import-template.yaml

Serverless Framework で管理されているスタックのテンプレートから import 対象の Resource ブロックをコピーして、1の template.yaml に追加した内容のもの( import-template.yaml )を準備します。 serverless.yml は CloudFormation の記法になっていませんが、コンソールからスタックのテンプレートを見ると、serverless.yml が CloudFormation の記法に変換されているので、ここからコピーすれば OK です。 以下のようにしてみます。

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: import to sam stack

Resources:
  TestSQS: 
    Type: AWS::SQS::Queue
    Properties:
      QueueName: sam-import-tmp
  
  # import 対象リソースを追記
  TestLogGroup:
    Type: AWS::Logs::LogGroup
    DeletionPolicy: Retain
    Properties:
      LogGroupName: /aws/lambda/lambda-import-tmp

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

import.txt

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

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

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

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

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

aws cloudformation create-change-set \
  --stack-name sam-import-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 完了です。
※ここでは上述までで例示したリソースではなく、実際に弊社で管理しているリソースの import 画面のためリソース数などが異なります。

あとは template.yaml にも imoport-template.yaml に追記したリソースを定義してあげる、もしくはそのまま imoport-template.yaml を使用しても良いです。ひとまずこれ以降は SAM でリソースの変更などが可能となります。 imoport-template.yamlimoport.txt はあくまで import 用なので、この時点で削除しても構いません。

尚、初めに SAM 用のスタックを用意するために作成したリソースの削除と、全リソースに DeletionPolicy: Retain を付与していることを忘れてはいけませんね。
また、複数環境を運用されている場合は、samconfig.toml を活用して環境ごとのリソース定義ができるようにしたり、Lambda のリソースタイプを Type: AWS::Serverless::Function から Type: AWS::Lambda::Function に変えてみたりと、SAM の恩恵を十分に受けられるように多少手を加えて完成です。

Terraform ならもっと簡単なのに、、、と思うところは多々ありましたが、Serverless Framework から SAM への移行は社内で初めての試みだったので、他のプロジェクトでの移行作業はこれでスムーズにいきそうです。


最後に、ユニファで一緒に働く仲間を探しています!

jobs.unifa-e.com