【API Gateway】カナリアリリース機能を使ってみた

記事タイトルとURLをコピーする

こんにちは。 ディベロップメントサービス1課の山本です。

今回は API Gateway でカナリアリリース機能の使い方を説明したいと思います。

この記事の対象者は?

  • デプロイ時に変更の影響を最小限にしたい方
  • カナリアリリースを検討されている方

カナリアリリースについて

カナリアリリースとは、ソフトウェアのデプロイ方法の一つです。
方法は以下の通りです。

  1. 現行のソフトウェアを維持したまま、新規のソフトウェアをデプロイ
  2. トラフィックの一部を新規ソフトウェアに向けて転送
  3. 新規ソフトウェアをテスト
    1. 問題なければ、全てのトラフィックを新規ソフトウェアに移行
    2. 問題がある場合は、現行のソフトウェアに切り戻す

API Gateway と AWS Lambda を例に説明すると、以下のよう形になります。

カナリアリリース 説明

API Gateway でのカナリアリリースの方法

API Gateway では REST API のみ canary(カナリア)リリースでのデプロイがサポートされてます。
こちらを利用して、今回カナリアリリースを実施してみます。
API Gateway の Canary リリースデプロイの設定 - Amazon API Gateway

AWS Serverless Application Model (以降、SAM) を利用してデプロイしてみます。

SAM テンプレートファイルの内容

以下にテンプレートを記載します。
10 % の割合で新バージョンに流れるようにします。

着目点は以下の点です。

  • Api のプロパティに CanarySetting を記載する。
  • Function のプロパティに AutoPublishAlias を設定する。
    • カナリアリリースには API Gateway のステージ更新が必要。
    • エイリアスを指定・変更しないと Lambda バージョンが LATEST で固定されるため、ステージが更新されない。
  • Function に DeletionPolicy: Retain を追加する。
    • 追加しない場合、エイリアス更新の度に過去のエイリアスが削除されるのでカナリアリリースできない。
  • Function に UpdateReplacePolicy: Retain を追加する。
    • 追加しない場合、エイリアス更新の度にリソースベースのポリシーが新規エイリアスに置き換わりカナリアリリースできない。

template.yaml

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: sam-app

Globals:
  Function:
    Timeout: 3
    MemorySize: 128

Resources:
  RestAPI:
    Type: AWS::Serverless::Api
    Properties:
      StageName: test
      CanarySetting:  # カナリアリリースの設定を追加
        PercentTraffic: 10

  HelloWorldFunction:
    Type: AWS::Serverless::Function
    DeletionPolicy: Retain # 過去のエイリアスが削除されないように追加
    UpdateReplacePolicy: Retain # リソースベースのポリシーが削除されないように追加
    Properties:
      CodeUri: hello_world/
      Handler: app.lambda_handler
      Runtime: python3.9
      AutoPublishAlias: "step1" # Lambda 更新時に API Gateway のステージが更新されるように追加
      Architectures:
        - x86_64
      Events:
        HelloWorld:
          Type: Api
          Properties:
            Path: /hello
            Method: get
            RestApiId:
              Ref: RestAPI

Lambda 関数の内容

エイリアスを確認できるARNを返却する簡単なプログラムを作成しました。

app.py

import json
  
  
def lambda_handler(event, context):
  
    arn = context.invoked_function_arn
    message = f"arn: {arn}"
  
    return {
        "statusCode": 200,
        "body": json.dumps(message),
    }

カナリアリリースの実施

初回デプロイ

それではカナリアリリースを実施してみたいと思います。
まず普通に初回デプロイします。

sam build
sam deploy

カナリアリリース設定は問題無し。

canary 設定

Lambda のエイリアスも step1 に設定されております。

リクエスト先の設定 step1

API の結果も エイリアスが step1 の Lambda が呼ばれてます。

"arn: arn:aws:lambda:ap-northeast-1:XXX:function:sam-app-HelloWorldFunction-QWELwhKuFQv3:step1"

2回目のデプロイ

Lambda のエイリアスを step2 に変更してデプロイします。

リクエスト先の設定 step2

ここで、問題が発生しました。

step2 と step1のエイリアスを持つレスポンス両方返却されるのですが、想定と割合が逆です。step2 の方が多い!

step1 step2
想定 90 % 10 %
実際 10 % 90 %

トラフィックの割合が反転した理由

どうも SAM からデプロイすると、カナリアリリースにはならず本番デプロイとして扱われ最新デプロイが Active になる模様です。

デプロイ履歴

初回デプロイ時は強制的にカナリアリリースも含まれるので、step1 が canary 、step2 が現行として扱われるので割合が反転しました。

コンソール上からのデプロイ

SAM から無理なら、コンソール上から試します。
リクエスト先の Lambda エイリアスを step 3 に変更後、コンソール上からデプロイします。

リクエスト先の設定 step3

コンソールからのデプロイ画面

すると、デプロイは成功したのですが Active 状態にはならずカナリアリリース成功となります。

コンソールからデプロイ後のデプロイ履歴

この状態で API をコールすると、想定通り 10 % のトラフィックのみ step3 に流すことができました。

step2 step3
想定 90 % 10 %
実際 90 % 10 %

canary リリースを現行に昇格

Canary タブから canaryを昇格することが可能です。
昇格後は元々カナリアリリースしたデプロイが Active 状態になり、全てのトラフィックを受信することになります。

Canary タブ
canary 昇格画面
昇格後のデプロイ履歴

まとめ

  • API Gateway の canary の設定を行うことで、カナリアデプロイが可能
  • SAM からデプロイすると、常に最新デプロイ適用されるためカナリアデプロイはできない
  • コンソール上から実施することでカナリアデプロイが実施可能

さいごに

よく試験で見かけた内容を試してみましたが、落とし穴だらけでした。

本ブログがどなかたのお役に立てれば幸いです。

山本 真大(執筆記事の一覧)

アプリケーションサービス部 ディベロップメントサービス1課

2023年8月入社。カピバラさんが好き。