Amazon API Gateway でステージやカスタムドメインを使いながら複数APIバージョンを管理してみる

2022.06.20

いわさです。

API Gatewayでステージという概念がありますが、gitブランチのような分岐した複数のバージョンを開発することが出来るのか調べてみました。
ここでは、APIドキュメントのみで管理するのではなくマネジメントコンソールでAPI Gatewayを管理出来ることを前提条件にしています。

まずはそのままステージへデプロイ

まずは適当なLambda関数と統合したうえで適当なステージ(ここではprd)へデプロイします。

lambda_function.py

import json

def lambda_handler(event, context):
    # TODO implement
    return {
        'statusCode': 200,
        'body': json.dumps('hoge!')
    }
$ curl  https://nykfeanm94.execute-api.ap-northeast-1.amazonaws.com/prd/lambda
"hoge!"

本番と開発でバージョンを分ける

これで、本番用にprdというステージが稼働している状態です。
ここで、開発や検証用に別のステージが必要になる場合がありますので、そのシナリオを確認してみます。

ここでは、LambdaでバージョニングしつつAPI Gatewayでもステージごとに参照しているエイリアスを分ける方針を取っています。

Lambda のバージョンとエイリアスを使う

まず、今回は API Gateway の統合先が Lambda なので Lambda 自体のバージョン分岐について考えます。
Lambda ではバージョンとエイリアスという概念があり、 Lambda に関してもバージョンは読み取り専用のデプロイ時のスナップショットとなっており、エイリアスは特定バージョンの参照です。

API Gateway 側も本番用ステージと開発用ステージを用意し、それぞれのステージからアクセスする Lambda 関数にエイリアスを指定します。

$ curl  https://nykfeanm94.execute-api.ap-northeast-1.amazonaws.com/prd/lambda
"prd"
$ curl  https://nykfeanm94.execute-api.ap-northeast-1.amazonaws.com/dev/lambda
"dev"

これで、開発用APIと本番用APIを分けて動作させることが出来るようになりました。
また、API GatewayのWAFなどはステージごとに関連付けすることが出来るので、開発用APIはIP制限で、本番用APIはmTLSで構成する、なども出来るようになります。
また、ログに関しても別の管理となります。

ステージ変数を使う

この状態だと、それぞれのデプロイごとに参照するLambdaのエイリアスを変更する必要があるので、API Gatewayの構成が同じであれば、ステージ変数を使って差異を吸収すると効率的に開発することが出来ます。
ステージ変数を使うようにしておくと、デプロイ前のテスト呼び出しなどでもステージ変数を割り当てて本番シミュレーション的なことが出来るので便利です。

ここでは統合先のLambda関数をステージ変数に設定しました。

カスタムドメインを使う

デプロイステージが多い場合に、API呼び出し側がステージを意識する必要が出てくる場合があるので、カスタムドメインを構成しAPIマッピング機能を使うとLambdaエイリアスのようにパスとステージを切り替えることも出来ます。
ユーザーフレンドリな後述のようにAPIを分ける場合などにもAPIマッピング便利なので、早い段階でカスタムドメイン構成しておくと便利だなと思いました。
ただし、APIマッピングはカスタムドメインと対象APIが同一AWSアカウントにある必要があるので、アカウント分離戦略をとっている場合に同一カスタムドメインで本番APIと開発APIを使い分けることは残念ながら出来ません。

$ curl https://apigwcm.tak1wa.com/devpath/lambda
"dev"
$ curl https://apigwcm.tak1wa.com/prdpath/lambda
"prd"

ブランチ戦略のように分岐させたまま並行した開発を行う

AWS CLIのV1とV2みたいな感じです。
これは、デプロイ前のAPIの構成がひとつしか存在しないので同一APIで行うことは出来ません。

厳密にいうとAPIをドキュメントのみで管理している場合はドキュメントのバージョン管理とデプロイツールを使うことで分岐したまま開発出来そうですが、マネジメントコンソールを使う場合は出来ません。

以下では、devステージにdevonlyというリソースを作成し、prdステージにprdonlyというリソースを作成するパターンを想定してみます。

この場合だと、prdステージのためにdev用リソースを削除して...などが必要になってしまいますね。

この場合はAPI自体を分けたほうが良いようです。
APIを分ける場合、API GatewayがAPIを複製するための「既存のAPIからクローン」する機能を備えているのでこちらを利用することが出来ます。
また、AWSのBlackbeltではAPIドキュメントのエクスポートとインポートを使う方法も推奨されています。

ステージが複製出来たらそれぞれのリソースを開発してデプロイします。
注意点として、複製時にはステージ情報などは複製されないので、クローンしたあとで新しく作る必要があります。ステージ変数もです。
そして、多くの場合はLambda統合の際にAPIごとのリソースベースでアクセスポリシーを定義していると思うので、APIが変わる場合は権限の追加が必要か気にしてやる必要があるのでご注意ください。

APIの複製と設定が出来たら、最後にカスタムドメインでAPIマッピングを設定します。
前述のとおり、APIの実体が別なのかどうかは意識しなくて済むのでクライアントサイドがサーバーサイドの都合を気にしなくていいので良いですね。

$ curl https://apigwcm.tak1wa.com/devpath/lambda
"dev"
$ curl https://apigwcm.tak1wa.com/prdpath/lambda
"prd"
$ curl https://apigwcm.tak1wa.com/devpath/devonly
203.0.113.1
$ curl https://apigwcm.tak1wa.com/prdpath/prdonly
203.0.113.1
$ curl https://apigwcm.tak1wa.com/prdpath/devonly
{"message":"Missing Authentication Token"}
$ curl https://apigwcm.tak1wa.com/devpath/prdonly
{"message":"Missing Authentication Token"}

さいごに

本日はAPI Gatewayでステージなどを活用して分岐したバージョンをどのように管理出来るのか、並行開発出来るのかなどを調べてみました。

API Gatewayの構成が共通化出来るかどうか、ステージ変数で切り離しが出来る範囲であればひとつのAPIでステージ変数で分けることで出来そうで、リソース構成が変わるなどのそれ以上の差異がある場合はAPI自体を分けてカスタムドメインでAPIマッピングしてやるのが良さそうです。