ハクソク

世界を動かす技術を、日本語で。

私は情熱を持ってGitHub Actionsが嫌いです

概要

  • GitHub Actionsへの強い不満と、その理由の説明
  • tmplrプロジェクトのCI構築中に発生した問題の経緯
  • Linux ARM環境でのビルド失敗とその原因
  • フィードバックループの非効率さへの苛立ち
  • Makefileへの移行による問題解決と今後の教訓

GitHub Actionsへの憎悪

  • GitHub Actionsに対する強烈な嫌悪感
  • これまで使った技術でここまで嫌ったものは他に無し
  • PHPも冗談のネタにするが、嫌悪までは感じなかった
  • GitHub Actionsだけは情熱的に嫌いという感情

tmplrプロジェクトのCI構築

  • tmplrは、手軽にテンプレートを作成できるファイル/プロジェクトスキャフォールドツール
  • build.rsでCUEを使い、README.mdやCHANGELOG.mdなどを自動生成
  • 作業自体は楽しく、1.5時間程度で完了
  • 完成後、CIの結果を確認せずにいたため、後でビルド失敗に気付く

Linux ARMビルド失敗の原因

  • CUEバイナリをbuild.rs内で利用
  • GitHub Actionsのマトリクスで4プラットフォーム向けにビルド
    • Linux ARM
    • macOS ARM
    • Linux x86_64
    • macOS x86_64
  • Linux ARMのみ「コマンドが見つからない」とエラー発生
  • 他の3環境ではCUEが正常動作
  • GitHub Actionsのマトリクス実行環境が強く分離されているため、x86_64バイナリがarm64ランナーから隠蔽される仕様

非効率なフィードバックループ

  • 修正案を探してci.ymlを変更し、コミット・プッシュ
  • ActionsタブでLinux ARMのビルド結果を都度確認
  • 1回の変更につき2~3分かかり、非常に非効率
  • まるで2分遅延するエディタカセットテープ時代のプログラム実行のような体験
  • 2026年にもなってこの状況は許容できないと痛感

完全な解決策と教訓

  • ネットの格言:「GitHub Actionsにロジックを持たせるな。自分で管理し、Actionsから呼び出せ
  • build.rsを削除し、Makefileで生成処理を管理
  • 生成ファイルをリポジトリにコミットし、CI設定も元に戻す
  • これで問題が解決し、精神的な負担も軽減

GitHub Actionsの功罪

  • GitHub ActionsはmacOSビルドなど一部メリットも存在
  • 設定が簡単な点も評価
  • しかし、ランナーのデバッグやビルド最適化に多くの時間を浪費
  • 他にもっと良いシステムがあれば知りたいが、現状は逃げ場がない現実
  • 早い段階で問題に気付けて良かったという結論

まとめと余談

  • GitHub Actionsは便利さと引き換えに多くのストレスをもたらす存在
  • 個人プロジェクトや小規模開発では、Makefile等でロジックを管理するのが賢明
  • PHPのミームは今もお気に入りで、少しだけ救い

Hackerたちの意見

1. bashは使わない方がいいよ。CIに優しいスクリプト言語を使おう。個人的にはpwshが好き。 2. ワークフローにロジックを入れないで。ワークフローはシンプルであるべき(KISS)で、スクリプトを呼び出すだけにしよう。 3. スタンドアロンのスクリプトを持っていれば、ローカルで開発・修正・テストができるから、地獄のループにハマることがないよ。 4. デバッグしやすいようにCIパイプライン全体を設計して、状態を出力するプリントを入れたり、バージョンをエコーしたりしよう。今は必要なくても、将来の自分が感謝することになるよ。 5. デバッグ機能が優れたサードパーティのランナーを使うことも考えてみて。
1については反対だな。シェル以上のものが必要になると、ちょっと臭いがする。ビルドやテストのプロセスは、もっとシンプルであるべきだと思う。
ステップ0. 意図的に時間を無駄にするCIサービスは使わないで、「SSHで再ビルド」みたいな機能があるCIサービスを使おう。前の議論から見ると(https://news.ycombinator.com/item?id=46592643)、Semaphore CIはまだそれを提供しているみたいだね。
アクションでの永続状態はどう扱ってる?私のアクションでは、依存関係をゼロからインストールするのに一番時間がかかるんだ。それを早くしたいけど、どうやっても分からなかった。依存関係をキャッシュするためのオプションは、どれも複雑そうだった。
pythonとかでCLIを作って、CIと同じことをやるようにすればいいよ。すべてのCIステージはそのサブコマンドを呼び出すだけで済む。
いや、それはダメ。Windowsの環境じゃない限り。
(1)には同意しないけど、(2)には賛成だな。リポジトリにMakefileを置いて、CIターゲットを設定するのをおすすめするよ。それで、`make ci-test`みたいなシンプルなコマンドでCIから簡単に呼び出せるし。Makefileは複雑にしすぎないようにね。もちろん、他のタスクランナーを使うのも全然アリだよ。
> Bashは使うな 何それ?BashはCIフローに最適なスクリプト言語だよ。
以前、ビルドファームを管理するために雇われたことがあるんだ。すべてのビルドジョブは、さまざまなことをさまざまな順序で行うJenkinsプラグインの巨大なパイプラインだった。まじで悪夢だったよ。二度とやりたくない。それ以来、私が触ったすべてのCIセットアップは「make build」やそれに似たもののラッパーになっていて、すべての知恵はビルドしているコードの隣にあるGitに住んでる。これだけは譲れない。
#1のちょっとしたバリエーションだけど、bashやPowerShellで簡単にできる以上の複雑なことにはDenoのTypeScriptを使うようになったよ。pwshができることはすごく多いのは認めるけど、使い勝手が嫌いだし、慣れてない人には結構 awkward だと思う。逆に、TypeScriptやJavaScriptに近い開発者が多いと思うしね。DenoはTSを直接実行できるし、リポジトリやHTTPモジュールも別のインストールステップなしで直接参照できるから、pwsh以上のシェルスクリプトには便利だよ。例えば、DBMSクライアントを引っ張ってきて、テストや設定のために直接やり取りすることができる。だから、上記の理由から、e2eテストには他の言語よりもDenoを使うつもり。
ひどいCIプラットフォームに対処する方法は、すべてのCIプロセスをコンテナ内で行い、CIツールがそれを引っ張って実行することだよ。必要なときにローカルで簡単に実行できるしね。もちろん、プラットフォームはそれをやられるのを好まないけど、そうするとベンダーロックインが無効化されるから。
それが私がいつもGitLab CIパイプラインでやってたことだよ。異なる目的のために専用のイメージをデプロイするだけ。一般的なTerraformコード用のTerraformイメージを用意して、バージョンの標準化が簡単になった。依存関係が多いプロジェクト用に特定のイメージも作ったから、デプロイパイプラインを数秒で実行できるようになった。でも、今はDockerイメージも維持しなきゃいけない。結局、トレードオフだよね。
それに関しての問題は、macOSのビルドをコンテナ化する良い方法がないことだね。
SourceHut CIがすごく好きなんだ。理由は、1. ビルドが失敗したときに、SSHでマシンに入ってデバッグできること。2. マニフェストを超簡単に編集&実行できて、全くブランチにプッシュする必要がないこと。これで、リモートマシンで最小限の再現可能な例を試すのも超簡単になるよ。それ以外にも、GitHubやできればForgejoで自己ホスティングすれば、マシン上でデバッグしやすくなるけど、その分自己ホスティングが必要になるね。
ニュースレター、必要なんだよね。
この投稿はGitHub Actionsの一番の問題、つまりフィードバックループが緩いことを的確に指摘してると思う。よくあるシンプルな失敗モードでプッシュして完了を待つのはイライラするよね。他の人たちも、ローカルで実行できるスクリプト内にCI操作を隔離することでこの痛みを最小限に抑えるためのアーキテクチャ的なステップがあるって指摘してるし、GitHub Actionsの機能は進化的な強化として扱うべきだと思う(例えば、`GITHUB_STEP_SUMMARY`が実際に存在する場合のみ使うとか)。フィードバックループの痛みを解消するためにうまく機能するもう一つの方法は、`workflow_dispatch` + `gh workflow run`だね。プッシュサイクルを経る必要はあるけど、`gh workflow run`を使えば、実際にログを見に行く必要が出るまで開発フローを維持できるよ。(ただ、ちょっとイライラする制限として、`gh workflow run`がトリガーしたワークフローのURLを出力しないことがある。GitHubは非同期ディスパッチだからだと言ってるけど、後でウェブUIで明らかに取得してるのに、どうしてここでコンテキストがないのか理解できないな。)
失敗したインスタンスにSSHアクセスが必要だよ。そうすれば、ワークフローのどのステップからでも調査したり、修正したり、再試行したりできるから。プロダクションの実行は不変であるべきだけど、診断や編集、再試行のためには入れるべきだよね。これで診断や解決が早くなるし、修正もスムーズになると思う。ログとかもちゃんと見れるはずだし。そういえば、GHAのログって時々バグが多いよね。必要なときに半分くらいは読み込まれないことがある。
GitHub ActionsでDockerイメージを作成・プルして、その中でビルドやテストを実行するように標準化したよ。だから、何か問題が起きたときには、GitHub Actionsが実行しているのと非常に似たライブデバッグ環境があるんだ。まあ、参考までに。
> つまり、フィードバックループがしっかりしてないってこと。Lefthookはすごく助けになるよ。 https://anttiharju.dev/a/1#pre-commit-hooks-are-useful でも、みんな過去のいろんなgitフックの悪い経験から投資したがらないんだよね。でも、素晴らしいものにする方法はあるよ。
Nixは使ったことないし、正直懐疑的だけど、効率的にステップをキャッシュすることでこの問題を解決できるのかな?
これがRWX CIプラットフォーム(RWX.com)で解決した大きな問題の一つだよ。「rwx run」を使えば、ローカルの変更を自動で同期してくれるから、プッシュする必要もないし、我々の自動キャッシングのおかげで環境設定のキャッシュがヒットして、ワークフローを書いている間に同じことを何度も実行する必要がなくなるんだ。さらに、APIやMCPサーバーを使えば、結果を直接ターミナルで取得できるから、UIを開く必要もないよ。深く掘り下げたいときだけ開けばいい。
これはGitHub Actionsのせいじゃなくて、人々がそれを使って作り出す恐ろしいもののせいだよ。自動化は単にGitHub Actionを何かにラップすることだっていう前提のもとでね。Pythonとかでスクリプトを作ることを学んで、ロジックをそこにまとめれば、ローカルで実行できるし、新しいCTOが来たときに次のCIシステムに移行するのも楽になるよ。
なんか「Debianのsystemdユニットが古いinit.dスクリプトを呼び出す」エネルギーを感じるけど、ちょっと好きだな。
この場合、失敗したVMに簡単にSSHで入ってデバッグできないことが嫌なんだと思う。「ワークフローを編集して、プッシュして、実行されて失敗するのを待って、また繰り返す」って感じだね。
いや、それはGitHubのせいだよ。彼らはこういう恐ろしい状況を助長してる。なぜなら、ベンダーロックインにつながるから。これがマイクロソフトの本当の利益率の大部分の源なんだろうね。多分、彼らがプログラミング言語を作ったのに、デバッグツールを全然作らなかったのもそのせいだと思う。
100% GAのせいだし、わざとやってるよね。
GitHub Actionsは好きだし、前に使ってたTravisよりもいいと思う。重要な問題を解決してると思うよ。OSSプロジェクトにとっては、すごく価値のある無料リソースだし。私にとっては、Nixを採用したのがすごく良かった。再現可能な開発環境を整えて、コマンドを`nix-shell --run`でラップするか、もっと良いのは`nix develop --command`、さらに良いのはCIタスクの大部分を`nix build`や`nix flake check`で実行すること。これでGitHub Actionsともすごく簡単に連携できるし、同僚や他の貢献者ともスムーズに作業できるよ。
Nixのアプローチに賛成!フレークからGitHub Actionsに対応したコンテナを作って、その中でアクションを実行することもできるよ。自分の個人プロジェクトでやったことあるし、ここにリンク貼っとくね。https://github.com/anttiharju/compare-changes
ここで誰かにコメントを書いたけど、メインコメントもここに書こうと思った。あんまりGitHub Actionsは使ってないけど、そのアーキテクチャについては聞いたことがある。私の理解では、GitHub Actionsは単にbashやpythonファイルを呼び出すだけでいいと思う。bashには問題があるから、私はpythonの方が好きだな。 https://paulw.tokyo/standalone-python-script-with-uv/ を見てみることをおすすめするよ。これがGitHub Actionsのpythonスクリプトにぴったりかどうか教えてほしいんだけど、このスクリプトは自動的にuvをインストールして、pythonの依存関係やランタイムも取得して、pythonコードを実行するんだ。しかも、通常はすごく管理しやすいし、ローカルでも動かせる。唯一の問題は、bashがあるのにこんな複雑なことをする必要があるのかってことと、uvをインストールする際のパフォーマンスの懸念かな。でも、GitHub Actionsを考えると、後者は問題ないと思う。bashもいいけど、bashには厳しい制限があるし、pythonはこういうのに向いてると思う。エコシステムも少し成熟してるし、ウェブサーバーを作ったり、カスタムサーバーにログを報告したり、基本的にすべてを自動化できる。私にとって、このスクリプトは両方の良いところを兼ね備えていて、真剣に構築する価値があると思う。
> GitHub Actionsは、単にbashやpythonファイルを呼び出すだけでいいと思う。Bashには問題があるから、私はpythonの方が好きだし…それが本来の使い方だよ。YAMLファイルは主に実行環境(例えば、実行するオペレーティングシステムやDockerイメージ)を定義するためと、ジョブの依存関係ツリーを説明するためにある。実際に実行するアクションはGHのYAMLの外にあるスクリプトに委譲すべきだね。
GH Actionsは他のCIシステムと比べるとあんまり良くないけど、細かいところに入るまでは特に悪くもないよ。最も大事なアドバイスは、できるだけ多くのコードをクロスプラットフォームのスクリプト言語(例えばPythonやNode.js)で書いたローカル実行可能なスクリプトに入れること。そうすれば「コミット→プッシュ→CI失敗」の往復を避けられるから。GH ActionsのYAMLは、実行環境やジョブの依存関係ツリーを定義するためだけに使うのがいいよ。
ここでの根本的な問題は、ビルドツールや構成管理、CIツールの使い方におけるスコープクリープだと思う。設計されていないことや苦手なことをさせない方がいいよ。問題は必ずしもGitHub CIではなくて、シンプルに保てば大丈夫。だけど、物事がシンプルじゃなくなってきてるんだ。何年も前から、antやmaven、gradle、puppet、ansibleなどのプロジェクトでこれを何度も見てきた。必ず誰かが複雑で賢いことをやろうとして、プラグインを追加したり、さらにプラグインを追加したり、複雑な設定をするんだ。スクリプトの複雑さが爆発して、結局うまくいかなくて、正しいことをさせるために何時間も何日もかけて戦う羽目になる。問題は、間違ったツールを使っていることだよ。これらのツールはすべて、万能ツールに進化する傾向があるけど、すべてに優れているわけじゃない。機能があるからといって、それを使うのが良いアイデアとは限らない。著者もこれを指摘してるね。単にbashスクリプトを書いて、それを実行すればいい。もしそれが複雑になりすぎたら、もっと適切なものを選べばいい。Pythonでも、好きなもので。要は、自分がローカルで簡単に実行、テスト、デバッグできるものを選ぶことが大事。もちろん、ここは人それぞれ好みがあるけど。もしYAMLやCIビルドに複雑なフォーク/ジョインの動作や条件ロジックを無理に詰め込んでるなら、ビルドをシンプルにした方がいいよ。YAMLは一般的なプログラミング言語としては適してないからね。複雑な部分を外部スクリプトにすることで、CIプロバイダーを変えたときにもその部分が動く利点もある。GitLabに移りたいかもしれないし、誰かがJenkinsはそんなに悪くなかったと思うかもしれない。そのスクリプトは多分、簡単に適応できるよ。私の現在のGitHub Actionsの一つは、基本的にVMを起動して、build.shスクリプトを実行して、VMを停止するだけ。特別なランナーは必要ないし、VMのタイプも選べる。build.shの中で必要なことは何でもできる。実際のマトリックスビルドを持っているプロジェクトもあるけど、それがGitHub Actionsでやる中で一番複雑なことかな。多くのビルドステップはただのインラインシェルコマンドだし。ここでAIの話をすると、もしこれを手動でやってるなら、ローカルで実行するスクリプトがあれば、claude code/codex/何でも使って自動で修正してもらえるよ。今日はcodexでいくつかのansibleスクリプトを作ってたけど、すごくうまくいった。私よりも良いansibleスクリプトを作ってくれるよ。これらのツールは、自分が取り組んでいるものをテストしたり実行したりできるときに、より良く機能するんだ。
AWS CodeBuildや、単に自分でホストしたシンプルなJenkinsサーバーの方がずっと扱いやすいと思ってる。GitHub Actionsには何の利点があって、みんなそれを使ってるの?フィードバックはほぼ全てネガティブだよね。
> GitHub Actionsには何の利点があって、みんなそれを使ってるの? GitHubのデフォルトCIシステムで、比較的無料でコンピュートが得られるからだよ。
多くのユースケースにおいて、ほぼ無料で使えるのがいいよね。特にマルチCPUビルドを考えると。
Jenkinsサーバーよりも、維持するのが圧倒的にリソースを消費しないし、設定もリポジトリに入ってるからね(Jenkinsサーバーの設定じゃなくて)。
Depotの創業者として、私たちが提供しているより速くて安いGitHub Actionsランナーについて、みんなが感じていることが少数派ではなく大多数だと保証できるよ。GitHub Actionsを使ってフィードバックループを早く閉じるために作られた製品を持っている人間としては変なことだけど、実際にはGitHub Actions全体のシステムがひどいからこそ可能なんだ。ランナーやコントロールプレーンで新しいボトルネックを毎週発見してるし、簡単だと思ったことが存在しなかったり、動かなかったり、パフォーマンスがひどかったりする。もっといい方法があると確信しているし、その分野でアイデアを積極的に構築しているよ。だから、GitHub Actionsについてもっと知りたい人や、何がもっと良くなるかを話したい人がいたら、プロフィールにメールアドレス載せてるから気軽に連絡してね。 [0] https://depot.dev/