GitHub Actionsが本当に大嫌いです
(xlii.space)- GitHub Actions の遅いフィードバックループと複雑なデバッグ過程に対する開発者の苛立ちを共有
- tmplr プロジェクトで
build.rsを通じて CUE でドキュメントを生成していたが、CI ビルドが失敗したことで問題が始まる - 4つのプラットフォームのうち Linux ARM だけがビルド失敗。その原因は、cross build 時に x86_64 バイナリが arm64 ランナー上で隠される GitHub Actions の動作方式にあった
- 単一の変更をテストするのに 2〜3分 かかる非効率なフィードバックループを繰り返す
- 解決策として
build.rsを削除し、GNU Makefile に移行。CI ロジックを直接制御する方式で問題を解決
問題発生の背景
- tmplr は、人が読み書きできるテンプレートファイルを使うファイル/プロジェクト用スキャフォールディングツール
build.rsで CUE を使ってREADME.md、CHANGELOG.md、バージョン/ヘルプファイルを生成し、一貫性を保証- 作業自体は約1.5時間で完了し、関連する記事も書き終えていた
- ローカルでは正常に動作したが、GitHub Actions の CI 環境では CUE バイナリが未インストールのためビルド失敗
ビルド失敗の原因
- 4つのプラットフォーム(Linux ARM、macOS ARM、Linux x86_64、macOS x86_64)のうち Linux ARM だけで「command not found」エラー が発生
- 原因: matrix cross build が強く分離されており、CUE は x86_64 Linux ホスト と macOS ARM ホスト にしかインストールされていなかった
- macOS は x86_64 バイナリの実行に問題なし
- Linux x86_64 も x86_64 バイナリの実行に問題なし
- しかし GitHub Actions は arm64 ランナーで x86_64 バイナリを隠し、実行不能な状態にしていた
非効率なフィードバックループ
- 問題解決のために繰り返した手順:
1. 可能な修正方法を調べる
2.ci.ymlを変更する
3. コミットしてプッシュする (jj squash --ignore-immutable && jj git push)
4. 「Actions」タブを開く
5. 最新の実行を開く
6. Linux ARM の実行を開く
7. 数秒待つ
8. うんざりする
9. 繰り返す - 変更1回ごとに 2〜3分 かかる
- 理想を言えば、GitHub が 完全な機能を備えたローカルランナー を提供するか、あるいはプッシュ後に進行状況を素早く確認できる機能を提供できればよい
- 「scratch commit」 のような機能: Git 履歴や Action の実行履歴を汚さずに、さまざまな実行を試せる方法
- しかし現時点では、そのような機能は存在しない
解決方法
- 30分間このループを繰り返した後で中断
- インターネットで知られている方法を適用: 「GitHub Actions にロジックを管理させず、自分でスクリプトを制御し、Actions にはそのスクリプトを呼び出させるだけにすること」
build.rsを削除(惜しさはあったが、犠牲は必要だった)- すべての生成作業を GNU Makefile に移行
- 生成されたファイルをリポジトリにコミットし、CI の変更を元に戻す
- 問題解決完了
結論
- GitHub Actions は、ある種の良いものを持てなくしてしまう原因になっている
- ランナーのデバッグやビルドプロセス最適化に多くの時間を失う
- しかし一方で、他の方法では得がたい macOS ビルド のような利点もある
- もちろん、GitHub Actions より設定が簡単な別システムも知られていない
We are all doomed to GitHub Actions. …but at least I dodged the bullet early.
3件のコメント
GitHub Actionsは環境セットアップ(OS、ビルドツールチェーン、…)とスクリプト(シェル、Python、bat、ps1…)の実行だけを担うべき。GitHubが落ちても、環境さえ整っていればどこでもビルドできるべきだ。最近のGitHub Actionsのワークフローを見ていると、ここまでしてわざわざ使う必要があるのかと思う。はるか昔(?)にAnsibleもそうなって廃れた。
Hacker Newsの意見
GitHub Actionsの核心的な問題は、フィードバックループが遅すぎること 単純な失敗を確認するだけでも、pushして待たなければならないのは本当にもどかしい CIジョブはローカルで実行できるスクリプトとして分離し、Actionsの機能は段階的な拡張としてだけ使うのがよいと思う
workflow_dispatchとgh workflow runの組み合わせも悪くないが、後者が実行したワークフローのURLをすぐ返さないのは不便gh workflow runでURLを得るには、GitHub APIでワークフロー実行一覧を再取得する必要があった 同時に複数の実行があると混線する可能性はあるが、今のところそれなりにうまく動いているCI設計のコツをまとめてみた
MakefileにCIターゲットを定義し、make ci-testのように簡単に呼び出せるのがよいmake buildのような単純なラッパーで管理しているBeginStep("Step Name")のようなマーカーで区切れたらよいのにと思う問題はGitHub Actionsそのものより、その上に雑に積み上げられた自動化にある ロジックはPythonのような言語でスクリプト化し、ローカルでも実行可能にすべきだ
自分はすべてのCIをコンテナ内で処理している CIプラットフォームはそのコンテナを実行するだけなので、ローカルでも同じように回せる プラットフォーム側はこうしたやり方を嫌う。ベンダーロックインが崩れるからだ
自分はGitHub Actionsが好きだ 以前使っていたTravisより良いし、OSSプロジェクトにとっては無料リソースとして非常に有用だ Nixを導入して以降、環境再現性が高まり、Actionsとの相性がずっと良くなった
GitHub Actionsは単にbashやpythonスクリプトを呼び出す構造であるべきだと思う bashには限界が多く、Pythonの方が柔軟でローカル実行もしやすい この記事のように、uvを自動インストールして依存関係を管理する方式が理想的だ bashより複雑ではあるが、Actions環境では性能上の問題は大きくない
Actionsの最大の問題は、「ワークフローを組み合わせろ」という宣伝のされ方にある デバッグはほとんど不可能で、キャッシュ設定も厄介なためビルドが遅くなる こうした理由から、常駐VMで直接実行する方式が魅力的に感じられる
自分はDepotの創業者だ GitHub Actionsランナーをより高速かつ安価に提供するサービスを運営している 多くの人が感じている不満は、実際に大多数の意見だ Actionsシステムは構造的に非効率で、毎週新しいボトルネックが見つかる より良い方法があると確信しており、それを実験している 詳しくはdepot.devで確認できる
先週末に
gg watch actionというツールを作った 現在のブランチの最新または実行中のアクションを見つけてくれるツールだ GitHubリンクghCLIに入っているべき機能だ」と好評だった ただし、gg tuiコマンドでリポジトリが見えないバグがあったactのようなツールが役に立つのか気になった nektos/act アーキテクチャの違いにより、ローカル実行とオンライン実行が異なる可能性はあるが、それでも有用そうだYAMLの中にロジックを入れなければならない構造なので、避けられない問題のように見えます。
上の記事がその答えをおおむね下のように出しているようですが、スクリプト部分をDaggerに置き換えれば、これが正解なのではないかとも思います。
"GitHub Actionsにロジックを管理させるのではなく、スクリプトを直接制御し、Actionsはそのスクリプトを呼び出すだけにすること"