CloudFormationでサイズの大きいSwaggerファイルを参照させる方法

2020.03.14

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

こんにちは。大阪オフィスの林です。

CloudFormationを使ってAPI Gatewayをプロビジョニングする際、AWS::Serverless::Apiリソースを利用することで、S3に格納されているSwaggerファイルを参照させながらAPI Gatewayをプロビジョニングすることが出来ます。HowTo的な部分は下記のブログをご参照頂ければと思います。

今回CloudFormationでAWS::Includeというモジュールを使ってS3に格納されているSwaggerファイルを参照させながらAPI Gatewayをプロビジョニングしていたのですが、参照しているSwaggerファイルが一定のサイズを超えるとTransform AWS::Include failed with: The specified S3 object is too big.となりCloudFormationでのプロビジョニングに失敗してしまいました。

今回はこのエラーに対する1つの対処を検討したのでその内容をまとめておきたいと思います。(他にも対処の方法はあるかと思うのですがワークアラウンドの1つとしてご紹介させて頂きます)

制約の確認

上述した『一定のサイズを超えると』という部分がこの制約に引っかかっていたのではないかと考えています。実際にS3に格納したSwaggerファイルを確認すると500KBを超えていました。他の比較的サイズの小さい(100KB~200KB程度)Swaggerファイルではプロビジョニングが成功していたのでこの制約に引っかかっていたと考えて概ね問題ないでしょう。

Amazon S3 テンプレート URL を使用して S3 オブジェクトとして渡す場合は 460,800 バイトです。ただし、CloudFormation はテンプレート内のマクロを連続的に処理するため、処理中にテンプレートの一時的な状態が更新されます。このため、処理中のテンプレートのサイズは、完全に処理されたテンプレートの許容サイズを一時的に超える場合があります。CloudFormation では、このような処理中のテンプレートにバッファーで対処できます。ただし、テンプレートやマクロを設計する際は、処理済みのスタックテンプレートの最大許容サイズに留意してください。

参照元

AWS::Includeを使ってた時のコード

AWS::Includeを使用してS3に格納されているSwaggerファイルのパスを指定しています。このコードではAWS::Includeを使用しているためSwaggerのファイルサイズ次第では上述の制約に引っかかりCloudFormationでのプロビジョニングに失敗してしまいます。

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: "APIGateway created by Classmethod"
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      -
        Parameters:
          - swaggerpath
Parameters:
  swaggerpath:
    Description: Please type the swaggerpath.
    Type: String
    Default: s3://swagger-test-backet/swagger.json
Resources:
  ApiGateway:
    Type: AWS::Serverless::Api
    Properties:
      EndpointConfiguration: REGIONAL
      StageName: prod
      OpenApiVersion: '3.0.0'
      DefinitionBody:
          'Fn::Transform':
            Name: 'AWS::Include'
            Parameters:
              Location: !Sub ${swaggerpath}
(省略)

AWS::Includeを使うメリットの1つとして、CloudFormationで作成したリソースに変更が無くてもS3に格納されたSwaggerファイルが更新されていれば、そのSwaggerファイルの更新を把握して変更セットを実行することが可能という点があげられます。しかし今回はサイズの制約に引っかかってしまったためAWS::Includeが使用できません。

どうしたか?

今回は下記のコードに変更をしました。S3に格納されたSwaggerファイルを参照するという部分は変わらないのですが、AWS::Includeを使わずにDefinitionUriでS3に格納されたSwaggerファイルを参照するように変更しています。ただしAWS::Includeを使用していないので、この場合S3に格納されたSwaggerファイルが更新されても、その変更をCloudFormationは認識できません。故に変更セットが実行できません。そこでDefinitionUriの中にVersionというパラメータを持たせて、S3で管理されているオブジェクトのバージョンIDを指定することで、Swaggerファイルの変更をCloudFormationに認識させ変更セットを実行させることとしました。※バージョンIDを作成するためにS3バケットのバージョニングを有効にする必要があります。

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: "APIGateway created by Classmethod"
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      -
        Parameters:
          - Corporationswaggerpath
Parameters:
  swaggerbacket:
    Description: Please type the swaggerbacket.
    Type: String
    Default: swagger-test-backet
  swaggerfilename:
    Description: Please type the swaggerfilename.
    Type: String
    Default: swagger.json
  swaggerfileversion:
    Description: Please type the swaggerfileversion.
    Type: String
    Default: ""
Resources:
  ApiGateway:
    Type: AWS::Serverless::Api
    Properties:
      EndpointConfiguration: REGIONAL
      StageName: prod
      OpenApiVersion: '3.0.0'
      #この部分(↓)を変えた!!!
      DefinitionUri:
        Bucket: !Sub ${swaggerbacket}
        Key: !Sub ${swaggerfilename}
        Version: !Sub ${swaggerfileversion}
(省略)

やってみた

まずはTransform AWS::Include failed with: The specified S3 object is too big.というエラーで失敗していたCloudFormationが成功するか見ていきます。スタック作成直後にエラーになっていましたがその部分は問題なくクリアしているように見えます。

CloudFormationでのプロビジョニングが正常終了しました。

次にSwaggerのファイルを更新してAPI Gatewayのリソースに更新がかかるか見ていきます。事前にS3から、更新したSwaggerファイルのバージョンIDを取得しておきます。上記で作成したCloudFormationのスタックから変更セットを実行していきます。今回はS3に格納されたSwaggerファイルのバージョンIDをCloudFormationのパラメータで渡すようなコードにしているので、更新したSwaggerファイルのバージョンIDをパラメータに指定します。
<変更前>

<変更後>

バージョンIDを変更したので変更セットが問題なく実行できることが分かります。では実行します。

正常終了することが確認できました。

最後にAPI Gatewayのリソースに更新がかかっているか確認しておきます。今回はとあるリソースのドキュメントのDescriptionだけ更新しています。
<更新前>

<更新後>

まとめ

それなりのシステム規模になるとSwagger自体のファイルサイズも大きくなっていくということもあると思いますので同じような事象に遭遇された際は是非参考にして頂けますと幸いです。もうちょっとスマートなやり方がないかと検討をしましたが正直見つけられなかったという背景もあり、多少アナログな対処ではありますがまとめさせて頂きました。

以上、大阪オフィスの林がお送りしました!