
CIが急に全部レッドになると、たいていはコードや設定をまず疑いますよね。でも今回はコードでもYAMLでもrunnerでもありませんでした。今日は開発の問題というより、運用の問題に近いトラブルシューティングをしたんです。
始まりはシンプルでした。私たちの組織のいくつかのprivate repoで、GitHub Actions CIが全部失敗していたんです。最初はself-hosted runnerの問題だと思いました。最近ローカルのMac miniをGitHub Actionsのrunnerとして接続して、複数のrepoのCIをself-hosted runnerで回すように変えたばかりだったからです。
ところが症状が変でした。
普通、runnerに問題があると、jobが作られたあとにqueued状態で止まったり、「matching runnerがない」といった形で失敗します。ところが今回はjobそのものがありませんでした。
代表的なrunの状態はこうでした。
conclusion: startup_failure
workflowName: ""
path: BuildFailed
jobs: []
logs: 404ログもありませんでした。正確には、ログが作られる前に死んでいたんです。
最初に疑ったもの: self-hosted runnerの設定#
まず疑ったのはローカルのrunnerでした。
実際、過去の設定には問題がありました。runnerがデフォルトの_workフォルダを使っていて、外付けSSDに作業ディレクトリを置くには--workオプションを渡す必要があったんです。
今はこのように直っていました。
workFolder: /mnt/ssd/actions-work/my-orgrunnerもonline状態でした。
runner: local-mac-mini
status: online
busy: false
labels:
- self-hosted
- macOS
- ARM64
- local
- mac-miniそれでも問題は続きました。
そこで、self-hosted runnerをまったく使わない、ごくシンプルなsmoke workflowも作ってみました。
name: Actions Smoke Test
on:
push:
branches:
- test/actions-smoke
workflow_dispatch:
jobs:
smoke:
runs-on: ubuntu-latest
steps:
- name: Print smoke marker
run: echo "actions-smoke-ok"ところがこれも同じように失敗しました。
conclusion: startup_failure
workflowName: ""
path: BuildFailed
jobs: []この時点で、runnerだけの問題ではないと見るべきでした。ubuntu-latestもrunnerに到達する前に死んでいたからです。
二番目の疑い: Enterprise / Organizationのrunner group の絡まり#
次に疑ったのはGitHub Enterpriseの設定でした。
最近Enterpriseの利用が終わったのですが、Organization側のActions runner group画面にこんな警告が出ていたんです。
Runner group Default already exists at the Enterprise level.
Please consider renaming this group.これは十分に怪しかったです。
organizationにはDefaultというrunner groupがあり、Enterprise levelにもDefaultが残っているように見えました。しかもAPIで見ると、Default runner groupが二つあるように見えたんです。
id 1: Default, visibility=all
id 3: Default, visibility=selectedそのためしばらくは、「Enterpriseが終わったのに、runner group policyが残ってorgのActionsが絡まったんじゃないか?」と考えていました。
この仮説も悪くはありませんでした。実際、Enterprise終了後の残りの設定は整理するのが正しいですし、runner groupの名前もDefaultよりlocal-mac-miniのような区別できる名前に変えたほうがいいです。
でもこれも決定的な原因ではありませんでした。というのも、private repoだけでなく、GitHub-hosted runnerを使うsmoke workflowまでBuildFailedで死んだからです。runner groupが原因なら、少なくともubuntu-latestのworkflowは違う形で失敗するはずでした。
GitHub Supportの回答: billing lock#
結局GitHub Supportに問い合わせました。回答は意外とシンプルでした。
The BuildFailed behavior occurs when an account's billing is locked,
blocking access to billable features, like Actions.つまり原因はコードでもYAMLでもrunnerでもありませんでした。billing lock(請求ロック)のせいでActionsそのものがブロックされた状態だったんです。
この説明なら、すべての症状が噛み合います。
- 複数のprivate repoで同時に失敗
self-hostedrunnerも失敗ubuntu-latestも失敗- jobが作られない
- logsエンドポイントが404
- workflow nameが空
BuildFailedというsynthetic workflowができる
GitHub Actionsはprivate repoではbillable feature(課金対象の機能)として扱われます。billing accountがlocked状態だと、runnerの種類に関係なくworkflow startupの段階でブロックされることがあるんです。
問題だったのはorganizationアカウントでした#
さらにSupportに確認した結果、問題だったbilling accountは個人アカウントではなく、organizationアカウントでした。
これで範囲が確定しました。
最初は個人アカウントの問題かもしれないし、終了したEnterpriseの問題かもしれないし、organizationの問題かもしれませんでした。でも最終的にはorganizationのbilling lockでした。
Supportからは、billing teamへ新しいチケットを開くよう案内されました。
今回学んだこと#
今回のトラブルシューティングで得た教訓はかなり明確です。
1. BuildFailed + startup_failure + jobs=[]はrunnerの問題ではないかもしれない#
runnerの問題なら、たいていjobは作られます。たとえばこんな形になります。
queued
waiting for runner
no matching runnerところが今回のようにこう出るなら:
workflowName: ""
path: BuildFailed
jobs: []
logs: 404workflowがrunnerに到達する前に死んだということです。この場合、YAMLやrunnerのlabel、runnerがonlineかどうかだけを追いかけていると、多くの時間を無駄にしかねません。
2. private repoのActionsはbilling状態の影響を受ける#
self-hosted runnerを使っても、ActionsそのものはGitHubのbillable featureの領域に引っかかります。だから「自分のrunnerで回っているのに、なぜbillingが問題なんだ?」と考えてはいけません。
Actionsのorchestration(作業をキューに入れてrunnerに割り当てる過程)そのものがGitHubのfeatureだからです。
3. Enterprise終了後はbilling / accountのscopeを必ず確認する#
Enterpriseを終了したからといって、残りの状態がすべてきれいに消えるわけではなさそうです。少なくとも今回は、これら全部が絡み合っていました。
- Enterpriseの終了
- Organization billing
- Actions runner group
- private repoのActions
- Support ticketのrouting
Enterpriseが終わったなら、次を確認してみてください。
Personal billing
Organization billing
Enterprise billing
Actions access
Runner groups
Outstanding balance
Seats
Billing cycle特に、支払い情報を追加する前に「いくらが即座に請求されるのか」を確認するのが大事です。
最終まとめ#
今回の問題のroot causeはこう整理できます。
organization billing lock
→ GitHub Actions billable feature blocked
→ all private repo workflows fail at startup
→ synthetic BuildFailed workflow
→ jobs=[]
→ logs=404次のアクションはrunnerを再インストールすることではなく、billing teamに確認することです。確認すべき要点はこれくらいです。
- 未払い残高(outstanding balance)があるか、あるなら正確な金額はいくらか
- 支払い情報を追加すると即座にいくら請求されるか(月次請求への切り替えが可能かを含む)
- 終了したEnterpriseのbilling scopeとまだ紐づいているか
今日の結論はこれです。CIが落ちたからといって、いつもコードやrunnerの問題とは限りません。 ときには請求状態が、いちばん低いレイヤーのインフラ障害のように現れるんです。症状がどう見てもインフラっぽいのに何も引っかからないなら、billingの状態も一度開いてみてください。
When you have eliminated the impossible, whatever remains, however improbable, must be the truth.
— Arthur Conan Doyle


