PRをマージしました。CIはグリーンでした。デプロイはログにエラー一つなく完了しました。20分後、サポートチケットが届き始めました。一部の顧客に対して決済エンドポイントが500エラーを返しており、パイプラインで何も失敗しなかったため、なぜそうなるのか全く分かりません。
カナリアテストが埋めるのは、このギャップです。ユニットテストと統合テストは、期待通りのコードをチェックします。しかし、実際のトラフィック、実際のデータベース、先週ひっそりとレート制限を変更したサードパーティAPIなど、現実世界に対するコードをチェックすることはできません。カナリアテストは、まず新しいリリースを実際のトラフィックのわずかな割合にプッシュし、その動作を監視し、シグナルが健全に見える場合にのみロールアウトを拡大します。もし何か問題が発生した場合、それが影響するのはユーザーの100%に1時間ではなく、ユーザーの2%に2分間だけです。
特にAPIの場合、ダッシュボードを監視して祈るだけよりも良い方法があります。カナリアが稼働した瞬間に、本物のテストスイートを実行し、ステータスコード、レスポンススキーマ、遅延をアサートし、その結果に基づいてロールアウトを制御できます。このガイドでは、そのワークフローを順を追って説明し、既存のCI/CDパイプライン内で全てが機能するように、Apidogとそのコマンドラインランナーを使ってエンドツーエンドで連携させます。
カナリアテストとは何か
この名前は炭鉱のカナリアに由来します。炭鉱夫は、人間よりもずっと早く有毒ガスに反応する鳥をケージに入れて地下に運びました。もし鳥が鳴き止んだら、そこから脱出しました。カナリアリリースも同じように機能します。少数の、犠牲にしても構わないサンプルが最初にリスクを負うことで、残りのユーザーは決してそのリスクを負う必要がありません。

実際には、カナリアデプロイメントとは、サービスの2つのバージョンを同時に実行することを意味します。
- Stable (安定版): 現在の製品バージョンで、ほとんどのトラフィックを処理します。
- Canary (カナリア版): 新しいバージョンで、少数の割合のトラフィック(多くの場合、最初は1%から5%)を処理します。
ロードバランサー、サービスメッシュ、またはイングレスコントローラーが、これらの間でトラフィックを分割します。カナリアのエラー率、遅延、ビジネス指標を安定版のベースラインと比較して監視します。もしカナリアが持ちこたえれば、徐々にトラフィックを増やしていき、最終的に100%を処理するようになり、新しい安定版となります。もし劣化すれば、全てを安定版に戻し、問題のあるリリースがほとんどのオーディエンスに届くことはありません。
カナリアテストは、このループの「能動的な」部分です。自然なトラフィックがバグを表面化するのを待つのではなく、意図的にAPIリクエストのスイートをカナリアに対して実行し、レスポンスをチェックします。受動的な監視は、ユーザーがそれに遭遇した後に何かが問題であることを知らせます。能動的なカナリアテストは、影響範囲を広げる前に何かが問題であることを知らせます。
既存のテストとカナリアテストの比較
カナリアテストは、他のテストを置き換えるものではありません。それはチェーンの終端に位置し、異なる種類の失敗を検出します。
| テストの種類 | 対象 | 検出する問題 | 見落とす問題 |
|---|---|---|---|
| 単体テスト | 独立した関数 | ロジックのバグ | 実際のI/Oを含むものすべて |
| 結合テスト | 結合されたコンポーネント | サービス間の契約違反 | 本番環境の設定、実際のデータ形式 |
| スモークテスト | デプロイされたビルド | 「そもそも稼働しているか?」という基本的な障害 | 微妙な動作回帰 |
| カナリアテスト | 本番インフラ上のライブリリース | 誤った設定、環境ドリフト、性能劣化、部分的な停止 | フルスケールでしか現れないバグ |
カナリアテストがその地位を確立する理由:本番環境のインシデントの大部分は、どのプレプロダクション環境でも完全に再現できないものから発生します。環境変数の不足。古いコネクションプールの設定。ステージング環境には存在するが本番環境にはないデータベースインデックス。実際の認証下で異なる動作をするダウンストリーム依存関係。あなたのコードは正しいが、その周りの環境がそうではない。カナリアテストは、新しいリリースがその環境に初めて遭遇する機会であり、あなたは全てのトラフィックではなく、2%のトラフィックでそれに遭遇したいのです。
これがどこに適合するかのより広範なコンテキストについては、CI/CDでAPIテストを自動化する方法に関するガイドで上流の段階をカバーしており、スモークテストと回帰テストの比較では、カナリアが最も依存する2つのテストタイプを説明しています。
カナリアで何を測定するか
カナリアが有用であるのは、「健全な状態」がどのようなものかを知っている場合だけです。少数のシグナルを選び、カナリアを絶対的な数値ではなく、安定版のベースラインと比較してください。1.2%のエラー率があなたのサービスにとって正常である場合もあります。重要なのは、カナリアが現在、安定版よりも著しく悪いかどうかです。
次の4つのシグナルがほとんどのケースをカバーします。
- エラー率: 5xxレスポンスの割合、そして認証変更後の401エラーの突然の急増など、発生すべきでない4xxエラーもしばしば含まれます。これは最も重要な単一の指標です。
- レイテンシ: 平均ではなく、p95とp99。平均値は、実際のユーザーが苦痛を感じる遅いテールを隠します。p99で40ms遅いカナリアは、平均が問題ないように見えても警告です。
- レスポンスの正確性: ボディがまだスキーマに一致しているか?間違った形式を返す200 OKは、監視ではフラグが立たないため、500エラーよりも悪い場合があります。
- ビジネスシグナル: チェックアウトの成功、ログインの成功、カートに追加されたアイテム。これらは、技術的には「成功した」HTTPレスポンスであるにもかかわらず、ロジックの回帰を捉えます。
最初の3つはAPIテストで直接アサートできます。それが自動化する部分です。
カナリアテストのワークフロー、ステップバイステップ
以下は、自動化されたAPIテストによって制御されるカナリアロールアウトの概要です。各ステップは、パイプラインから実行できるものです。
- 安定版と並行して、新しいバージョンをカナリアとしてデプロイします。
- トラフィックのわずかな割合(例えば5%)をカナリアにルーティングします。
- カナリアエンドポイントに対して自動化されたAPIテストスイートを実行します。
- 短期間の「ベイク期間」中、エラー率と遅延を監視します。
- ゲート: テストがパスし、メトリクスが予算内に収まっていれば、さらに多くのトラフィックをシフトします。そうでなければ、ロールバックします。
- (5%から25%へ、25%から50%へ、50%から100%へというように)段階的にトラフィックを増やし、各ステップで再テストします。
- カナリアを安定版に昇格させ、古いバージョンを停止します。
注目すべき2つの部分は、ステップ3(テストスイート)とステップ5(ゲート)です。これらを正しく設定すれば、残りはプラットフォームがすでに提供している連携部分です。
Apidogでテストスイートを構築する
テストスイートはカナリアテストの核心であり、ほとんどのチームが手抜きをする部分です。単に`/health`にpingを打ち、200が返るかだけをチェックするカナリア「テスト」では、プロセスが開始されたことは分かりますが、実際のエンドポイントが機能しているかどうかは何も教えてくれません。
実際のカナリアスイートは、重要なパスを検証します。認証、読み取り、書き込み、そしてそれぞれのレスポンス形式の検証です。Apidogのテストシナリオを使えば、これらのリクエストを連結し、データを受け渡し、グルーコードを書くことなく結果をアサートできます。
EコマースAPIの堅牢なカナリアシナリオは次のようになります。
- ステップ1、認証。テストアカウントで
POST /auth/loginを実行します。200をアサートし、レスポンスからトークンを変数に抽出します。 - ステップ2、読み取り。トークン付きで
GET /products?limit=10を実行します。200をアサートし、レスポンスが配列であることをアサートし、各アイテムにid、name、priceがあることをアサートします。 - ステップ3、書き込み。既知の製品で
POST /cartを実行します。201をアサートし、返されるカートの合計が期待値と一致することをアサートします。 - ステップ4、状態の検証。
GET /cartを実行します。追加したばかりのアイテムが存在することをアサートします。
Apidogでは、各リクエストを一度構築し、視覚的にアサーションを追加します。スキーマチェックの場合、すでに設計済みのOpenAPIスキーマに対してレスポンスを検証できるため、形式が異なるレスポンスボディは自動的にテスト失敗となります。認証トークンの受け渡しでは、ステップ1のレスポンスからそれを抽出し、後のステップで変数として参照します。一般的なケースではスクリプトは不要で、カスタムロジックが必要な場合はJavaScriptのポストプロセッサを組み込むことができます。
その利点は、同じシナリオが1つの定義から3つの方法で実行されることです。構築中は手動で、ライブ後はシンセティックモニタリングとしてスケジュールに基づいて、そしてカナリアパイプライン内でコマンドラインから実行されます。アサーションは一度書けば済みます。
コマンドラインからスイートを実行する
デプロイメントを制御するには、CIでスイートをヘッドレスで実行する必要があります。ApidogはまさにそのためのCLIを提供しています。ビルドエージェントにインストールします。
npm install -g apidog-cli
ApidogからテストシナリオデータをCLI形式のファイルとしてエクスポートするか、アクセストークンを使用してIDでシナリオをランナーに指定し、その後実行します。
apidog run \
--access-token "$APIDOG_ACCESS_TOKEN" \
-t "$CANARY_SCENARIO_ID" \
-e "$CANARY_ENV_ID" \
-r cli,html,junit
カナリア作業で知っておくと良いフラグがいくつかあります。
-t, --test-scenarioは、IDで特定のシナリオを実行します。シナリオのフォルダ全体を実行するには、-f, --test-scenario-folderを使用します。-e, --environmentは、ランタイム環境を選択します。これを、カナリアエンドポイントをベースURLとする環境に向けます。これにより、同じテストが1つの値を変更するだけでカナリア、ステージング、または本番環境を対象にできます。-r, --reportersは、出力を制御します。cliはコンソールに出力し、htmlは共有可能なレポートを生成し、junitはGitHub Actions、GitLab、Jenkins、およびほとんどのCIダッシュボードがテストごとの合否を表示するためにネイティブに解析できるXMLを出力します。-d, --iteration-dataは、CSVまたはJSONファイルの各行に対してスイートを一度実行します。1回のパスで複数のユーザープロファイルや製品IDでカナリアをヒットするのに便利です。--upload-reportは、実行サマリーをApidogにプッシュするため、チームはアプリ内でカナリアの履歴を確認できます。
アサーションが失敗すると、CLIはゼロ以外の終了コードで終了します。この終了コードが全体の制御メカニズムです。パイプラインはすでに失敗したステップで停止する方法を知っているため、失敗したカナリアテストは無料でロールアウトを停止します。
パイプラインでのApidogの実行に関するより詳しいウォークスルーについては、GitHub ActionsでのAPIテスト自動化方法とJenkins統合ガイドでこれらのプラットフォームについて詳しく説明しています。
CI/CDへの組み込み
以下は、カナリアをデプロイし、テストし、成功した場合にのみ昇格させる、簡略化されたGitHub Actionsジョブです。この構造は、わずかな構文変更でGitLab CI、CircleCI、またはJenkinsに引き継ぐことができます。
name: canary-release
on:
push:
branches: [main]
jobs:
canary:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy canary (5% traffic)
run: ./deploy.sh --canary --weight 5
- name: Install Apidog CLI
run: npm install -g apidog-cli
- name: Test the canary
run: |
apidog run \
--access-token "$APIDOG_ACCESS_TOKEN" \
-t "$CANARY_SCENARIO_ID" \
-e "$CANARY_ENV_ID" \
-r cli,junit
env:
APIDOG_ACCESS_TOKEN: ${{ secrets.APIDOG_ACCESS_TOKEN }}
CANARY_SCENARIO_ID: ${{ vars.CANARY_SCENARIO_ID }}
CANARY_ENV_ID: ${{ vars.CANARY_ENV_ID }}
- name: Bake and watch (2 min)
run: sleep 120 && ./check-metrics.sh --service canary --max-error-rate 1.0
- name: Promote canary to 100%
run: ./deploy.sh --promote
- name: Roll back on any failure
if: failure()
run: ./deploy.sh --rollback
これが通常のデプロイではなくカナリアであるとするロジックは、その順序付けにあります。カナリアはテストが実行される前にトラフィックの一部を受け取るため、テストはすでに実際の要求を処理しているリリースを検証します。if: failure()ステップはセーフティネットです。テストスイートがゼロ以外のコードで終了したり、メトリクスチェックがトリップしたりした場合、ジョブは失敗し、トラフィックが5%を超える前にロールバックが実行されます。
CANARY_ENV_IDは、ベースURLがカナリアを指すApidog環境を指し続けるようにしてください。後で同じスイートをデプロイ後の本番スモークテストとして実行したい場合は、本番環境IDに置き換えるだけで、他は何も変更しません。この再利用がポイントです。1つのスイートで、多くのステージに対応します。
カナリアテストを無意味にする一般的な間違い
間違ったエンドポイントのテスト。もしテストがロードバランシングされた公開URLをヒットする場合、そのリクエストはカナリアインスタンスではなく安定版インスタンスに到達する可能性があります。メッシュがルーティングするヘッダー、専用のカナリアホスト名、またはカナリアのアドレスがベースURLである環境を介して、明示的にカナリアにテストをルーティングしてください。
ベイク期間がゼロ。持続的な負荷がかかっている場合にのみ、メモリリーク、コネクションプールの枯渇、キャッシュの満杯などの障害が現れることがあります。テストを実行した後、プロモートする前に数分間監視してください。すぐにパスして10秒でプロモートされるカナリアは、ほとんどカナリアではありません。
自動ロールバックがない。人間が障害に気づいてロールバックをクリックしなければならない場合、インシデント対応の最も遅い部分が残ってしまいます。真の価値は、パイプラインが自動的にロールバックすることにあります。ロールバックを障害条件に連携させ、ロールバックが機能することをテストしてください。
比較ではなく絶対的なしきい値。「エラー率が1%を超えたら失敗」というルールは、ベースラインのエラー率が正当に1.5%である日に破綻します。カナリアと現在の安定版を比較し、数ヶ月前に選んだ数値を越えたときではなく、カナリアが著しく悪化したときにゲートをトリップさせてください。
薄いアサーション。不正なボディを持つ200レスポンスは、ステータスコードのみのチェックをパスし、ユーザーには失敗をもたらします。コードだけでなく、レスポンススキーマもアサートしてください。API契約を最初に設計し、スキーマに対してレスポンスを検証することがここで直接報われます。カナリアテストは、契約を無料で継承します。
カナリアはどのくらいの範囲で、どのくらいの期間行うべきか?
普遍的な答えはありませんが、ほとんどのチームにとって実用的なデフォルト設定は次のとおりです。
- トラフィックの5%から開始。ダメージを制限するには十分に小さく、忙しいサービスで数分以内に実際のシグナルを得るには十分に大きい。トラフィックの少ないAPIでは、十分なリクエストを収集するためにより長い期間が必要な場合があります。
- 段階的に増やす: 5%から25%、25%から50%、50%から100%へ。各ステップでテストスイートを再実行します。5%では隠れていた回帰が、接続プールが飽和した50%で現れることがあります。
- 各ステップで少なくとも数分間ベイク。ゆっくりと現れる障害が表面化するのに十分な長さで、すべてのリリースを1時間も停止させない程度の短さです。
トラフィックの多いサービスは、迅速にシグナルを蓄積するため、より速く進めることができます。1秒あたり数千のリクエストを処理する決済APIは、カナリアを1分で判断するのに十分なデータを持っています。1時間に数回のリクエストしか受け付けない内部管理APIは、判断を下すためにより長いベイク期間またはより重い合成テスト負荷が必要です。
リリース戦略におけるカナリアテストの位置付け
カナリアテストは、機能フラグやブルーグリーンデプロイと自然に連携しますが、その違いを明確に理解しておく価値があります。ブルーグリーンは、すべてのトラフィックを一度に1つの環境から別の環境に切り替えます。ロールバックは迅速ですが、段階的な公開はありません。機能フラグは、再デプロイなしで選択したユーザーの動作を切り替えます。カナリアリリースは、実際のトラフィックを徐々にシフトさせ、ライブシグナルに基づいて制御します。
ほとんどの成熟したチームは、これら3つすべてを使用します。インフラの切り替えにはブルーグリーン、自動ゲートによる段階的なトラフィック増加にはカナリア、そしてコードがライブになった後の詳細な制御には機能フラグです。共通する点は、これらがいずれもリリースを本番環境に対してテストする必要性をなくすものではないということです。これらは、テスト中にどのくらいのオーディエンスに公開されるかを制御するものです。
それが本当の教訓です。カナリアテストは購入するツールではありません。それは「規律」です。つまり、小さなデプロイを行い、ライブリリースを実際のアサーションでテストし、シグナルを監視し、その結果に基づいてロールアウトを制御することです。それぞれのステップを自動化するためのツールは存在します。Apidogを使用すれば、テストスイートを一度構築し、CLIからあらゆるパイプライン内で実行し、終了コードによってリリースを進めるかどうかを決定できます。問題のあるリリースはトラフィックの5%で停止し、ユーザーが500エラーを目にすることはありません。
Apidogをダウンロードして、最初のカナリアテストシナリオを構築し、環境をカナリアエンドポイントに向け、パイプラインにCLIステップを1つ追加してください。次の問題のあるマージは、すべてではなく、ごく少数のリクエストで問題が表面化するでしょう。
よくある質問 (FAQ)
カナリアテストはカナリアデプロイメントと同じですか? カナリアデプロイメントはリリース機構であり、新しいバージョンを少量のトラフィックに提供することです。カナリアテストは、その期間中に行うことで、ダッシュボードを監視するだけでなく、アクティブにテストを実行し、レスポンスをアサートすることです。テストを行うにはデプロイメントが必要ですが、リスクのあるロールアウトを制御されたものに変えるのはテストです。
カナリアテストを行うにはサービスメッシュが必要ですか? いいえ。IstioやLinkerdのようなサービスメッシュはトラフィックスプリットを容易にしますが、通常のロードバランサーの重み付け、イングレスコントローラーのカナリアアノテーション、あるいはDNS重み付けでもカナリアを実行できます。このガイドが焦点を当てているワークフローのテストとゲート部分は、トラフィックをどのように分割するかに関わらず同じように機能します。
デプロイ後のスモークテストとはどう違いますか? スモークテストは通常、完全にデプロイされたリリースに対して一度実行され、それが稼働していることを確認します。カナリアテストは、実際のトラフィックの一部のみを処理しているリリースに対して実行され、段階的な増加を制御します。アサーションは同じである可能性がありますが、違いはタイミングと結果にあります。失敗したスモークテストは、すでに全員に公開されているものをロールバックすることを意味し、失敗したカナリアテストは、ロールアウトを5%で停止することを意味します。スモークテストと回帰テストの区別については、比較ガイドを参照してください。
既存のAPIテストをカナリアテストとして再利用できますか? 多くの場合、できます。実際のアサーションを持つApidogテストシナリオがすでにある場合、ベースURLがカナリアである環境に向けて、CLIで実行します。作業は、テストがステータスコードだけでなくレスポンスボディもアサートすることを確認することと、ロードバランシングされた公開URLではなくカナリアにルーティングすることです。
CIでカナリアテストが失敗した場合どうなりますか? Apidog CLIは、アサーションが失敗するとゼロ以外のコードで終了します。パイプラインはそれを失敗したステップと同様に扱い、ジョブは停止し、昇格ステップはスキップされ、if: failure()のロールバックステップが実行されます。ロールバックが行われるのを人間が監視する必要はありません。
