自動復旧インフラが状況を悪化させるとき

午前2時。本番アプリケーションがコネクションプールエラーを吐き始める。オンコールエンジニアがクラウドコンソールに飛び込み、データベースのパラメータを調整すると、システムは安定する。全員が一息つく。

20分後、アラートが再び鳴る。同じエラーだ。エンジニアがコンソールを確認すると、パラメータが元の値に戻されている。Infrastructure as Codeのパイプラインが手動変更を「ドリフト」と検出し、自動的に元に戻したのだ。インシデントが再発し、誰かが自動調整メカニズムを無効にするまで、このサイクルは繰り返される。

このシナリオは仮定の話ではない。コードからの逸脱をすべて修正すべき問題として扱う自動調整が引き起こす現実の出来事だ。

すべてのドリフトが悪いという前提の問題

自動調整は紙の上では完璧に聞こえる。パイプラインが実インフラとコード定義の乖離を検出し、自動的に正しい状態を適用する。人間の介入は不要。ドリフトが残る余地もない。

しかし、その前提は間違っている。すべてのドリフトがミスとは限らない。パイプライン外での変更が正当な理由で行われることもあり、それらの変更こそがシステムを動かし続けているのだ。

インシデント対応中、エンジニアは緊急変更を行う。データベース移行中、チームは慎重な手順の一部として一時的にリソースを変更する。負荷テスト中、スケーリングパラメータはその場で調整される。これらはすべて、コードリポジトリと一致しないインフラが存在する正当な理由だ。

自動調整システムには、破壊的な変更と命綱となる変更を区別する方法がない。実際の状態が望ましい状態と異なることだけを認識し、その仕事は望ましい状態を復元することだ。なぜ変更が行われたのか、インシデントが進行中かどうか、変更がチームによって検証されたかどうかについて、システムは一切の文脈を持たない。

タイミングが問題を悪化させるとき

自動調整のタイミングは別のリスクを生み出す。複雑なデータベース移行の最中にあるチームを考えてみよう。彼らはまだIaCに完全に反映されていない多段階の手順の一部として、複数のクラウドリソースを意図的に手動で変更している。もし調整パイプラインが移行中に実行されれば、移行途中のリソースを削除し、データ損失や移行の完全な失敗を引き起こす可能性がある。

これは理論上のエッジケースではない。移行、インフラアップグレード、セキュリティインシデント対応はすべて、ライブ環境が意図的にコードベースと異なる一時的な状態を含む。これらのウィンドウ中に実行される自動調整は、単なる不便さを超えて、データを破壊し、稼働中のサービスを停止させ、スピードが優先されたために手動で適用された重要なセキュリティ対策を元に戻す可能性がある。

自動化を諦めずにリスクを制御する

答えは自動調整を完全に無効にすることではない。答えは、実際の運用に合った制御を構築することだ。

以下のフローチャートは、問題のある自動調整ループと、提案する制御が介入するポイントを示している。

flowchart TD A[ドリフト検出] --> B{承認ゲート?} B -- なし --> C[自動ロールバック] C --> D[インシデント再発] D --> A B -- あり --> E[人間によるレビュー] E --> F{正当なドリフト?} F -- はい --> G[コードに取り込む] F -- いいえ --> H[安全に調整] I[調整ウィンドウ] --> B J[変更フリーズ] --> B K[除外ルール] --> A

調整の承認ゲート

ドリフト検出時にパイプラインが自動的に変更を適用する代わりに、レビューステージで停止させる。変更内容の詳細を含む通知を該当チームに送信し、調整の実行前に承認を要求する。これにより、チームはドリフトをロールバックすべきか、コードベースに取り込むべきかを確認する時間を得られる。

これは運用を遅くすることを意味しない。適切に設計された承認プロセスは迅速に行える。重要なのは、文脈を欠いた自動システムではなく、人間が判断を下すことだ。

調整ウィンドウ

自動調整の実行を許可する特定の時間枠を定義する。例えば、平日の午前9時から午後5時まで。それ以外の時間帯は、ドリフトを検出して報告するが、自動的には修正しない。

このシンプルなルールが、午前2時のインシデントシナリオを防ぐ。夜間に緊急変更が発生した場合、パイプラインはそれを記録してチームに警告するが、誰かが適切にレビューできる朝まで修正を元に戻さない。

変更フリーズ

チームがフリーズ期間中の場合、すべての自動調整をオフにする。フリーズはメジャーリリース前、監査中、または重要な移行中に行われる。フリーズ中はドリフトを監視して記録するが、自動変更は許可しない。チームはフリーズ終了後、すべての正当な変更がコードに記録されたことを確認してから、調整を再び有効にできる。

動的リソースの除外ルール

一部のリソースは設計上、パイプライン外で頻繁に変更される。オートスケーリンググループは負荷に応じてサイズを調整する。監視ツールは自動的に設定を調整する。これらのリソースは自動調整から除外するか、特定の種類のドリフトを許可する特別なルールを与えるべきだ。

例えば、Terraformでは lifecycle ブロックと ignore_changes を使用して、正当な動的調整がパイプラインによって元に戻されるのを防ぐことができる:

resource "aws_autoscaling_group" "app" {
  name               = "production-app-asg"
  min_size           = 2
  max_size           = 10
  desired_capacity   = 4
  launch_configuration = aws_launch_configuration.app.id
  vpc_zone_identifier = ["subnet-abc123", "subnet-def456"]

  lifecycle {
    ignore_changes = [
      desired_capacity,
      min_size,
      max_size,
    ]
  }
}

これにより、Terraformはスケーリングパラメータの変更を無視するため、負荷スパイク時の手動スケーリングが元に戻されることはない。

これはルールの例外を作ることではない。一部のインフラは本質的に動的であり、その通常の運用変更をドリフトとして扱うことが、解決するよりも多くの問題を生み出すことを認識することだ。

実践的なチェックリスト

任意のリソースグループに対して自動調整を有効にする前に、以下のポイントを確認すること:

  • インシデント発生時にチームが調整をオーバーライドまたは一時停止できるか?
  • 時間外を除外した調整ウィンドウが定義されているか?
  • オートスケーリンググループなどの動的リソースが除外されるか、特別なルールが与えられているか?
  • パイプラインは調整変更を適用する前に人間の承認を必要とするか?
  • 正当なドリフトをコードに取り込むための文書化されたプロセスがあるか?

本当の教訓

自動調整はツールであり、ポリシーではない。インフラが安定しており、すべての変更がパイプラインを通り、インシデントが稀な場合にはうまく機能する。運用が乱雑で、緊急事態が発生し、人間が判断を下す必要がある場合には、逆効果になる。

これをうまく処理するチームは、すべてを自動化しない。ドリフトの検出と通知は自動化するが、調整の決定は人間の手に委ねる。運用の現実に合わせたウィンドウとフリーズを構築する。動的であるべきリソースは除外する。

インフラはコードからドリフトする。そのドリフトの一部は問題になる。一部はサービスを稼働させ続けた理由になる。目標はドリフトを排除することではない。目標は、行動を起こす前に、どの種類のドリフトに対処しているのかを判断できるだけの制御を持つことだ。