このシリーズの2つの荷重を支える前提は、いずれも今日、マネージドサービスで、午後の内にテストできる。AWS Fault Injection Serviceには "AZ Availability: Power Interruption" という名のシナリオが付いており、1つのアベイラビリティゾーン内のタグ付けされたすべてのインスタンスを停止し、それを置き換えようとするAuto ScalingグループにInsufficientInstanceCapacityエラーを送り込み、EBSボリュームのIOを一時停止し、サブネットのトラフィックを遮断し、その後障害を解除して停止したものを再起動する。第3回のコントロールプレーンの前提には既製の障害はないが、その正直な近似は1つのJSONファイルと1つのIAM拒否に収まる。どちらもほとんど誰も走らせない。その理由はツールではない。理由は、テストは失敗しうるが前提は失敗しえない、ということだ。

これは Nothing Fails Alone の第4回、最後の1つだ。第1回は5月のus-east-1インシデントを取り上げ、クォーラムがその内側で死ぬ一方でゾーン境界が持ちこたえるのを示した。第2回は3月のme-central-1のイベントを取り上げ、1つの原因が18時間の間隔をおいて、あらゆる分離保証を越えて2つのゾーンに届くのを示した。第3回は2つの提供者にまたがる3つのコントロールプレーンのインシデントを取り上げ、復旧計画がそれが走る層と共に死ぬのを示した。シリーズの背骨を2文で。あなたが買う可用性は、提供者が約束したものの境界で終わり、その線の上にあるすべてはあなたが所有するアーキテクチャだ。所有していて一度も動かさないものはアーキテクチャではない。それはあなたの名前が付いた前提だ。この回はそれを動かし、そしてシリーズを採点する。

AZ訓練は棚から取り出せる

FISのシナリオライブラリのAZ Availability: Power Interruptionは、1つのゾーンを失う際の記録された症状を誘発する公開された実験テンプレートで、その公開JSONは7つの障害タイプにまたがる8つのアクションを持つ(インスタンスの停止は2度現れる。1度はスタンドアロンインスタンス用、もう1度はAuto Scalingグループ自身のもの用だ)。ターゲットゾーン内のタグ付けされた稼働インスタンスは停止され、設定された継続時間の後に再起動される。タグ付けされたAuto Scalingグループからの起動リクエストは、その間InsufficientInstanceCapacityを受け取り、あなたが名指しした任意のIAMロールの容量呼び出しも同様だ。というのも、シナリオページによれば、実際の電源中断の間 "EC2 API calls made by the Auto Scaling control plane to recover lost capacity in the AZ will fail" からだ。EBSボリュームのIOは一時停止される。サブネットのトラフィックは、拒否ルールで満たされた複製ネットワークACLに差し替えることで拒否される。ゾーン内にライターを持つRDSクラスターはフェイルオーバーされ、ElastiCacheレプリケーショングループはそのゾーンの電源を中断される。それは5月のインシデントがuse1-az4にしたことのほとんどだ。Coinbaseを一晩ダウンさせた障害は、いまやライブラリの一項目だ。

それが何でないかについて正確になろう。インスタンスは正面玄関、StopInstances APIを通じて停止される。電源切断ではなく秩序あるシャットダウンなので、クラッシュ整合性については何もテストされない。Fargateタスクはカバーされない。2つの読み取り可能なスタンバイを持つRDS Multi-AZクラスターはサポートされない。1つのドリフトの注記。シナリオページは復旧アクションaws:arc:start-zonal-autoshiftを記述しているが、それ自身のJSONスナップショットには含まれていない。コンソールのライブラリは最新のリビジョンを持ち、ラボは公開JSONに従う。

ラボはシリーズリポジトリの04-game-dayで、シリーズの読み取り専用ルールを2度目にして最後に破る。--injectはあなたのクレデンシャルが届くどのアカウントに対しても実際の実験を開始するので、サンドボックスに、第3回のラボスタックに向けて、本番の近くには決して置かず、属するべきだ。

名前、ID、そして空で出荷される停止条件

第2回はゾーン名とゾーンIDについて騒ぎ立てたが、ゲームデーはその騒ぎが報われる場所だ。インシデントレポートはIDで話す。5月のレポートはuse1-az4と言い、3月の更新はmec1-az2、次いでmec1-az3と言った。あなたのアカウントは名前、AWSがアカウントごとにランダム化するエイリアスで話す。そしてツールは、大部分において、名前を要求する。インスタンスとサブネットのターゲットはPlacement.AvailabilityZoneでフィルタリングし、それはあなたのアカウントローカルの名前にマッチし、公開シナリオはEBS、RDS、ElastiCacheのターゲットパラメータも名前で埋める。ちょうど2つのアクションが物理IDを受け付ける。容量不足のペア、aws:ec2:api-insufficient-instance-capacity-erroraws:ec2:asg-insufficient-instance-capacity-errorで、そのavailabilityZoneIdentifiersパラメータは名前だけでなくゾーンIDも取ると記述されている。そこでさえ、公開シナリオはそのフィールドを名前、us-east-1aで埋めている。

したがってゲームデーは、第2回がラボを提供した翻訳の問題から始まる。ランナーはそれを一度、冒頭で解決する。run.pyが受け付ける唯一のゾーンフラグは--az-id、物理ゾーン、インシデントレポートが名指しするものだ。それはDescribeAvailabilityZonesを通じてアカウントローカルの名前を解決し、両方を表示し、各プレースホルダーをその消費者が要求する形で埋める。あなたはインシデントレポートが与えるであろう名前の下で障害をリハーサルし、そのリハーサルは、あなたのアカウントがたまたま話す方言で自身を設定する。

ランナーが継承を拒む2つ目のものはより静かだ。公開シナリオの停止条件ブロックは、そのままこう見える。

"stopConditions": [
    {
        "source": "aws:cloudwatch:alarm",
        "value": ""
    }
]

中身が何もないガードレールの形であり、ページの制限事項セクションは停止条件はあなたが追加するものだと言っている。防御可能なデフォルトだ。AWSはあなたの定常状態を知りえないのだから。だが仕込まれたものでもある。JSONはきれいに貼り付けられ、空文字列は欠落した安全システムには見えないからだ。ラボの立場。run.py--alarm-arnが与えられない場合、何かを作成する前に終了する。意味のある停止条件のない実験はテストではなく、賭けだからだ。定常状態は障害の前にコミットする数であり、そうでなければゲームデーは失敗しえず、失敗しえないゲームデーはあなたに何も教えられない。

合格がどう見えるか、測って

第3回の2パススタックに対して実験を走らせ、その2ゾーンの一方を落とす。

python3 run.py experiments/az-power-interruption.json \
  --az-id euw1-az1 \
  --fis-role-arn arn:aws:iam::111111111111:role/fis-game-day \
  --alarm-arn arn:aws:cloudwatch:eu-west-1:111111111111:alarm:game-day-abort \
  --target-group-arn ... \
  --inject

--injectなしでは同じコマンドはドライランだ。解決されたテンプレートを表示し、何も開始しない。それを付けると、ランナーは実験を作成して開始し、その後終端状態までポーリングし、各アクションのステータスをログに記録し、測定としてターゲットグループの健全カウントをサンプリングする。そのタイムラインが成果物だ。以下に続くのは合格の形であって、私が得た結果ではない。それを勝ち取れる本番形のアカウントを私は持っていないからだ。パスB、静的に安定なものは、生き残ったゾーンがすでに負荷を担うので、障害後の要件である2つの健全なターゲットを決して下回らない。パスAは半分に落ち、障害の継続時間ずっとそこにとどまる。そのインスタンスを停止したのと同じ実験が、その置き換え起動にInsufficientInstanceCapacityを送り込んでいるからだ。第3回の測定スクリプトはパスAの復旧を協力的なコントロールプレーンに対して計測した。ゲームデーは非協力的なものに対して同じパスを示し、その2つの数の差こそが、あなたのDR計画が置いていた前提の大きさだ。

4つの数を記録する価値がある。復旧した容量までの時間、健全ターゲットのサンプルから。失敗したであろうコントロールプレーン呼び出しを必要としたランブックステップの数、障害の窓の間あなたのランブックを歩いて数える。第3回の協力的な数とゲームデーの非協力的なものとの差。そして第1回の検出ツールの各検出結果の運命。それが表示するすべての行はゲームデーが決着させられる予測だからだ。シングルAZのAuto Scalingグループは、本当にその容量を容量エラーの背後に取り残す。デフォルトルートが失敗したゾーンに入り込む健全なゾーンのサブネットは、本当にエグレスを失う。検出ツールの検出結果は仮説だ。ゲームデーは実験だ。

FISが与えられないコントロールプレーンの訓練

第3回の前提はより難しく、ここでは正直な文が先に来る。FISにはコントロールプレーン喪失のアクションがない。アクションの完全なリファレンスはそのフレーズを一度も含まず、その中の何もコントロールプレーンを奪わない。最も近いのは、あなたが名指しした呼び出し元にスコープされたエラー注入だ。上記の容量不足のペアと、名指しされたIAMロールが行うリクエストに障害を注入する3つの汎用APIエラーアクション(internal、throttle、unavailable)で、EC2とKinesisのネームスペースだけが対象だ。プレーンは稼働したままで、選ばれた呼び出し元がノーと告げられる。あなたが借りられるものの何も、STSが3回別々に失敗する一方でコンソールが504を配信する状況を再現しない。

そこでラボの2つ目のテンプレートは近似であり、そう明記されている。ファイル自身の中のトップレベルのapproximationキーの中に、だ。ラベルが、それがラベル付けするものからドリフトできないようにするためだ。FIS側はInsufficientInstanceCapacityを、ワークロードASGの起動と、デプロイロールの容量呼び出し、RunInstancesCreateFleetStartInstancesCreateCapacityReservationに、失敗したゾーンで20分間注入する。もう半分はFISではまったくない。ec2:RunInstancesautoscaling:*cloudformation:*に対する手動の、スコープされた、時間制限付きのIAM拒否で、それがランブックの「緊急スタックを押すだけ」のステップを、2023年6月にそうなったであろう障害に変える。run.pyは適用と削除のコマンドを表示し、決して実行せず、時間制限はポリシーがアタッチされる前に決められ、拒否はあなたがそれを削除するために必要とするロールには決して掛からない。その最後のルールは杓子定規ではない。それは訓練とインシデントの違いだ。

近似が再現しないもの、ファイル自身のリストから。本当のコントロールプレーンの劣化はレイテンシとブラウンアウトであって、きれいなエラーであることは稀だ。ファイルが決して名指ししないサービス、ELB、Route 53、IAM自体、コンソールは、ここでは動き続けるが、実際のイベントでは動かないかもしれない。読み取りは成功し続けるので、あなたのダッシュボードは実際よりも健全に見える。TerminateInstancesやロードバランサーの設定変更のような容量以外の変異は成功し続けるので、これはコントロールプレーンではなく容量作成を拒否する。そしてそれは1つのゾーンの容量であって、実際のイベントはリージョナルでありうる。この訓練ではもう1つ測れ。検知までの時間だ。修正が機能していないと人間が気づくのにどれだけかかったか。誰かがコントロールプレーン喪失をシミュレートしたと言うなら、その5つのギャップのどれをカバーしたかを尋ねよ。私のものもそのどれもカバーしない。それは、あなたのアーキテクチャが最初の1時間に拒否された呼び出しを必要としない、というより狭い主張をカバーする。

シリーズを採点する

4つのインシデント、4つのラボ、1つの背骨。シリーズが確立したこと、それ自身の基準に照らして。主張が数えられるのは、それが運用者の公開された言葉に立脚しているときだけだ。第一に、ゾーン分離は、それが設計対象とする障害に対しては本物だ。5月のサーマルイベントはuse1-az4の内側にとどまり、その夜失敗したアーキテクチャは、AWSではなくそれ自身のポストモーテムの認めるところによって失敗した。第二に、ゾーン障害は独立事象ではない。1つの原因が18時間の間隔をおいてmec1-az2とmec1-az3に届き、失われた2つのゾーンがリージョナルサービスをその明示された1ゾーンの許容度を越えて追い込んだ。第三に、コントロールプレーンはデータプレーンが動き続ける一方で、1つより多い提供者で失敗し、コントロールプレーンの操作である復旧計画はそれと共に失敗する。2023年と2025年10月はAWS自身のポストイベントサマリー、2026年2月はAzureのものに基づく。

さてもう一方の列だ。勝ちだけを数える回顧はマーケティングだからだ。前提のまま残るもの。あなたについての定量的なすべてだ。私はこれらのラボを本番フリートに対して一度も走らせていないので、シリーズのすべての数は出力の形であり、正直にラベル付けされてはいるが依然として形だ。大量フェイルオーバーのサンダリングハードの代償、AWSの "longer than usual provisioning times" は2つのインシデントに現れ、AWSによっても私によっても一度も数を与えられていない。第3回の静的安定性の保険料は算術であって、本物のフリートからの請求書ではなかった。そしてあなたのブレークグラス経路が機能するかは、ここからは知りようがない。

私が違うやり方でやるとしたら。ゲームデーを最後ではなく最初に走らせる。シリーズはそのラボを教育的に、検出、翻訳、測定、注入と並べたが、その順序は運用上は逆だ。1回の注入実行が、検出ツールが予測することしかできない検出結果のリストを生み出す。そして私はもっと早く二次情報源を疑っただろう。ルール、運用者自身のページからのみ引用する、は最後までその価値を稼ぎ続けた。それは誤った継続時間、半日ずれたタイムスタンプ、そして見かけ上の情報源が取ってくるとそれを含んでいなかった主張を捕まえた。テストされていない前提についてのシリーズが、いくつかをもう少しで出荷するところだった。それは私が用意しえたであろう、それ自身のテーゼの、これ以上ないほどきれいなデモンストレーションだ。

ゲームデーも失敗する

計器は、それが測るものと同じ懐疑に値するので、ゲームデーがあなたに嘘をつく3つのやり方で締めくくる。

  • テストが走ったことだけを証明するテスト。 FISはターゲットをタグで解決し、タグの不一致は実験を失敗させない。AZシナリオはターゲットが何にも解決されないアクションをスキップし、ラボはその挙動を保つ(emptyTargetResolutionMode: skip)ので、部分的なスタックも走れる。その代償。実験は何も停止しないままcompletedに達しうる。緑の結果、注入された障害はゼロ。ステータス行ではなくアクションごとの表を読め。コントロールプレーンのテンプレートは代わりにfailを設定する。そこでは空のターゲットは実行を無意味にするからだ。終了コードも一致する。completedは0で終了し、stoppedした実験は、停止したことがあなたのアラームが機能したことを意味するにもかかわらず1で終了する。ガードレールが発火することはガードレールが機能していることであり、それでも合格ではない。
  • 早く発火しすぎる停止条件。 アラームを厳しい閾値の内部メトリックに束ねると、実験は興味深い障害の前、2分で停止する。あなたが学ぶのはアラームが発火することだけで、その後の誘惑はそれを緩めるか削除することだ。そうやって、選んで、シナリオの空文字列に戻り着く。修正はガードレールを減らすことではない。それはアラームを、実際のインシデントを停止させたいであろう閾値で、ユーザー向けの定常状態メトリックに束ねることだ。
  • 本番ではないアカウント。 サンドボックスの合格はメカニズムを証明するのであって、結果を証明しない。本番トラフィックなし、データの重力なし、うるさい隣人なし、午前3時に起こされるオペレーターなし。それに注入自身の甘さ、ブラウンアウトではなく秩序あるシャットダウン、きれいなエラーを加えると、正直な証拠の連鎖はこう読める。検出ツールが予測し、サンドボックスのゲームデーがその予測のメカニズムをテストし、本番はラベル付けされた外挿を継承する。それは何もないよりずっと良く、証明にはずっと及ばない。そうでないふりをすることが、「私たちはカオスエンジニアリングをやった」がもう1つのテストされていない前提になるやり方だ。

そこがシリーズの終わりだ。何ものも単独では失敗しない。どの回も、障害がその傍らの何かと絡み合っているのを見つけた。クォーラムと建物、ゾーンと戦争、修正とコントロールプレーンだ。何ものも単独では合格しない。どの合格も、それを生み出した環境と絡み合っており、そう述べるラベルこそがレポートの中で最も荷重を支える行だ。

次に読む

AWS、クラウドアーキテクチャ、レジリエンスレビュー、プラットフォーム業務のコンサルティングは、ercanermis.comからどうぞ。

参考資料