KINTO Tech Blog
CI/CD

GitHub Actionsを意図せず大量実行させて社内CIを止めた話

Cover Image for GitHub Actionsを意図せず大量実行させて社内CIを止めた話

はじめに

KINTOテクノロジーズでインフラエンジニアをしているyassanです。

先日、GitHub Actionsのワークフローを意図せず大量に起動してしまい、社内のCI/CDパイプラインを約1時間にわたって止めてしまうという事故を起こしました。

この記事では、小さなミスがどう連鎖して大きな障害になったのか、そしてそこから何を学んだのかをお話しします。

前提:コメント駆動のCI/CDパイプライン

私たちのチームでは、Terraformのインフラコードを管理するリポジトリでGitHub Actionsを活用しています。

仕組みはシンプルで、PRにコメントを投稿すると、そのPRで変更されたディレクトリを検出して自動的に terraform plan を実行してくれるというものです。

ワークフローの概要を簡略化すると、以下のようなイメージです。

name: Terraform Plan

on:
  issue_comment:
    types: [created, edited]  # コメントの新規作成・編集時に発火

jobs:
  plan:
    # PRへのコメントで、本文にコマンド文字列を含む場合に実行
    if: |
      github.event.issue.pull_request
      && contains(github.event.comment.body, '/command')
    runs-on: ubuntu-latest
    steps:
      - name: PRの変更ディレクトリを検出
        # ...
      - name: 対象ディレクトリごとに terraform plan を実行
        # ...
      - name: 結果をPRにコメント
        # ...

通常であれば、PRの変更範囲は1〜2ディレクトリ程度。数分で完了する軽い処理です。

やらかしの連鎖

火種:いつもの感覚でリベースしたら、対象が35ヶ所に膨れ上がった

普段のPRは main ブランチに向けて作成しています。しかしこの日に限って、別の作業ブランチをベースにしたPRを作っていました。

ここで、いつもの癖で何も考えずにリベースを実行。すると、そのブランチにあった他のメンバーのコミットが差分に混入してしまいました。

本来1ディレクトリだったplanの対象が、一気に35ディレクトリに膨れ上がりました。

延焼:消火しようとしたらガソリンだった

35ディレクトリ分のplanが走ってしまったことに気づき、「余計な結果コメントを非表示にして整理しよう」と考えました。

そこでGitHub APIを使って、不要な34件のコメントのうち20件を非表示(minimize)にしていきました。

その操作がワークフローのトリガーになるとも知らずに、非表示にするだけだと軽い気持ちで実施しました。

結果として、思いがけず20件 × 35ディレクトリ = 約700回のワークフローが一斉に走り出しました。

種明かし:大量のトリガー

GitHub APIの minimizeComment でコメントを非表示にすると、GitHub上では 「コメントの編集」イベント として扱われます。ちなみに、Web UIから手動でhideした場合はこのイベントは発生しません。

そして、非表示にしたコメントの本文には、ワークフローのトリガーとなるコマンド文字列が含まれていました。

つまり、1件非表示にするたびに、35ディレクトリ分のplanが再び起動してしまう状況だったのです。

誤判断:PRを閉じれば止まると思った

約10分後、大量のワークフローが走っていることに気づきました。パニックになった私は「PRを閉じれば止まるはず」と考え、すぐにPRをクローズしました。

「これで大丈夫」と安心して、別の作業に戻りました。

発覚:社内から悲鳴が上がる

さらに約10分後。社内のチャットに「GitHub Actionsが動かない」「CIがずっとキュー待ちになっている」という報告が上がり始めました。

慌ててGitHubを確認すると、クローズしたはずのPRにまだ結果コメントが投稿され続けていました

実は、PRをクローズしても 実行中のワークフローはキャンセルされません

それどころか、クローズされたPRに対してもコメントイベントは発火するため、PRクローズ自体にワークフローを止める効果はないのです。

これにより、共有ランナーの枠を食いつぶしてしまい、他チームのCIが動かなかったわけです。

私はすぐにGitHub Actionsの画面から、実行中のワークフローを手動で片っ端からキャンセル。ようやくキュー溜まりが解消し、社内のCI/CDが正常に戻りました。

あとから確認したところ、恐ろしいことに約3,000分(50時間相当)のActions実行時間を、わずか1時間の間に消費していたことがわかりました。

何が起きていたのか

今回の事故は、4つのミスが連鎖して起きました。

# やったこと 何が起きたか
1 別ブランチベースのPRでリベース 他人のコミット混入で対象35ディレクトリに膨張
2 結果コメントを非表示にして整理 非表示=編集イベント → ワークフロー再起動 × 20回
3 PRをクローズして安心 起動済みワークフローは止まらない
4 20分間気づかず放置 社内CI/CDが1時間停止

一つ一つは「ちょっとした判断ミス」や「仕様を知らなかった」程度のことですが、それが連鎖することで大きな障害になりました。

ワークフロー変更による再発防止

1. トリガー条件の見直し

ワークフローのトリガーから edited(編集)イベントを削除し、created(新規作成)のみに限定しました。これにより、コメントの編集や非表示でワークフローが起動することはなくなりました。

on:
  issue_comment:
-    types: [created, edited]
+    types: [created]

2. コマンド判定ロジックの厳格化

コメント本文にコマンド文字列が「含まれているか」ではなく、「先頭から始まっているか」で判定するように変更しました。さらに、イベント種別の二重チェックも追加しています。

jobs:
  run_plan:
    if: |
      github.event.issue.pull_request
+      && github.event.action == 'created'
-      && contains(github.event.comment.body, '/command')
+      && startsWith(github.event.comment.body, '/command')

3. 同時実行の制御

concurrency グループを設定し、同一PRでのワークフローの並列実行を防止しました。後から起動したワークフローが、先行するものをキャンセルして最新のplanだけが実行されるようになっています。

concurrency:
  group: plan-${{ github.event.issue.number }}
  cancel-in-progress: true

組織としての課題

今回の事故で、ワークフロー単体の修正だけでは防ぎきれない課題も見えてきました。

  • 共有ランナーの同時実行数が急増しても気づく仕組みがない
  • ワークフローのトリガー設計に関する共通のガイドラインがない
  • 暴走に気づいたとき、誰がどう止めるかの手順が整備されていない

これを踏まえてコーポレートITグループと連携して以下による改善を進めていきたいと考えています。

  • ランナー使用状況の監視強化(同時実行数がしきい値を超えた際の Slack アラート)
  • ARMランナーやハイスペックランナーへの切り替えによる処理効率の改善
  • ワークフロートリガー設定のベストプラクティス策定・既存ワークフローの一括監査

この経験から学んだこと

「止めたつもり」が一番怖い。

PRを閉じればワークフローも止まると思い込んでいましたが、実際にはそうではありませんでした。慌てているときほど、思い込みで行動してしまいがちです。

ワークフローのトリガー条件は、「最悪のケース」で考える。

GitHub APIを使ったコメントの非表示は編集イベントとして扱われること、結果コメントの本文にトリガー文字列が含まれること。どちらも普段は問題にならない仕様ですが、組み合わさったときに暴走を引き起こしました。

小さなミスは連鎖する。

リベースのミス、コメント整理の操作、PRクローズへの過信、確認不足。どれか一つでも正しく対処できていれば、ここまでの事故にはなりませんでした。失敗が起きたとき、焦らずに「今何が動いているのか」を確認することが大事だと痛感しました。

おわりに

今回の事故は、自分の操作で社内の開発フローを止めてしまうという、なかなかにつらい経験でした。

ただ、この失敗をきっかけにワークフローのトリガー設計を見直し、同様の暴走が起きない仕組みに改善できました。外注開発なら責任問題になりかねない失敗も、内製開発なら改善のきっかけにできる。それがこの経験で得た一番の実感です。

この記事が、同じようなCI/CDの落とし穴を避けるための参考になれば幸いです。

Facebook

関連記事 | Related Posts