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

現代のCIは複雑すぎて方向性を誤っている (2021)

概要

  • CIプラットフォーム の進化とその利点
  • 複雑化 による課題と本質的な問題提起
  • CIシステムとビルドシステム の境界の曖昧さ
  • 理想的なCIプラットフォームへの 要件考察
  • Taskcluster という先進的な事例の紹介

モダンCIプラットフォームの現状と課題

  • CIプラットフォーム の進化により、開発者や企業がより頻繁かつ信頼性の高いソフトウェアをリリース可能
  • GitHub ActionsGitLab PipelinesBitbucket などの集中型CIプラットフォームによるスケールメリット
    • インターネット上に豊富な情報やノウハウの蓄積
    • 検索すればすぐにコピペ可能なコード例の入手
  • CI設定 に時間を費やすのは誰も望まない現状
    • 目標は「とにかくリリースしたい」

CIシステムの複雑化

  • 進化とともに 設定や機能が複雑化
    • 本質的には「リモートコード実行サービス」として機能
    • ソフトウェアのビルド・テスト・デプロイを目的とした設計
  • GitHub Actions の例
    • 組み込みテンプレートシステムと独自の式言語
    • ジョブのトリガー、変数、条件付き実行、ジョブ間依存関係
    • Dockerベースの実行環境や暗号化シークレット
    • ステップ・アクションの豊富な標準機能
    • 3rdパーティのActionsも多数存在
  • 必要な機能が多く、 不要な機能の削減が難しい
    • YAMLのプログラミング言語的利用に対する妥協

CIとビルドシステムの境界

  • CIシステムの複雑化 =ビルドシステムとの区別が困難
    • MakefileBazel のようなビルドシステムとの類似性
    • CIはリモート・分散型、ビルドシステムはローカル・単一マシンという違いのみ
  • Bazel のようなモダンビルドシステムはリモート実行・キャッシュを標準装備
    • サーバーサイドのGitフックでBazelをトリガーすれば、それも一種のCIシステム
  • CIとビルドシステムの高次抽象化
    • どちらも「汎用計算リソース管理+専門的なビルド・デプロイ機能」
    • Kubernetes やバッチジョブシステムと本質的に近い構造

CIシステムの冗長性と理想像

  • 現状のCIシステムは「ビルドシステムの再発明」や「ロジックの分断」を招く
    • 複雑なYAML、キャッシュや依存関係の最適化でビルドシステムと同じ問題に直面
    • ビルドシステムとCIシステム、2つのDAG(有向非巡回グラフ)管理の煩雑さ
  • 本来CIはビルドシステムの拡張であるべき
    • ローカル開発ワークフローと統合されたCIの利便性
    • ローカルでCIジョブを即時実行可能な開発体験
  • UIやAPIによる集中管理・レポート機能 は必要だが、リモート実行やワーク定義はビルドシステムで十分

CIプラットフォームの抽象度と今後の方向性

  • 現代のCIサービス は適切な抽象レベルを狙えていない
    • GitHub ActionsGitLab CI は「製品」寄りで、柔軟なプラットフォーム性が不足
  • 理想的なCIプラットフォームの要件
    • API経由で任意のタスクグラフをスケジューリング可能
    • YAMLやリポジトリに縛られない「リモート実行サービス」としての柔軟性
  • GitLab Pipelines は親子パイプラインや動的パイプラインで一歩リード
    • ただし完全なAPIベースのスケジューリングは未対応
  • GitHub Actions はYAMLファイルベースに強く依存し、柔軟性に制約

プラットフォームと製品の違い

  • 製品型CI :意見の強いYAML設定+Web UI+APIのセット
  • プラットフォーム型CI :APIで任意の計算リソース・ワークフローを定義可能
  • プラットフォームとしての進化には「YAMLレスなAPIによるタスク定義」が不可欠

Taskcluster:エンジニア向けCIプラットフォームの事例

  • MozillaのTaskcluster は、汎用性の高いCIプラットフォーム
    • Firefox開発のため2014-2015年に設計・実装
    • 他のCIサービスとは一線を画す柔軟性とパワー
  • Taskcluster の特徴
    • API駆動型のタスク定義・スケジューリング
    • 開発者が独自のビルド・CI・バッチシステムを構築可能な自由度
    • 公式の用途にとどまらない多様な応用事例
  • エンジニア本位の設計思想 と、他サービスが見習うべきアイデアの宝庫

このように、現代のCIプラットフォームは進化しつつも、 ビルドシステムとの統合や抽象度の見直し が今後の課題。 Taskcluster のような先進事例を参考に、より柔軟で開発者本位なCIの実現が期待される。

Hackerたちの意見

最近のオンライン/有料のCIシステムは山ほどあって、将来どうなるかなんて誰にもわからないよね…。俺は昔ながらのJenkinsマシンを使ってるけど、これをセットアップするのにかなり時間がかかったけど、それ以来ずっと安定してるし、コストもかからないし、シャットダウンされることもない。GitHub Actionsとかの魅力はわかるけどね…。

GHアクションのデバッグをしなきゃいけなくなるまで、特にそれがメインでしか動かないか、メインにコミットしたときだけ実行されるタスクの一つだったら、神様助けてくれ。ローカルのエミュレーターやモックなんて使うだけ無駄だよ。

Jenkinsに+1。俺の職場では最近Gitランナーをセットアップしたんだ。今やってるプロジェクトは、OSが指定されてて、長い話だから聞かないで。OSはCentOS 7なんだけど、ランナーはこれをサポートしてない。Ubuntu 22.04に移行する努力もあるけど、ランナーもこれをサポートしてない。だから、Jenkinsのインスタンスをセットアップしてるところ。

でも、設定ファイルがDSLに堕ちるなら、もう本当のプログラミング言語を使っちゃいなよ。これ、マジで同意。デバッガー付きの本物のプログラミング言語を使おう。YAMLは最悪だし、Starlarkもあんまり良くないよね。

YAML化されたDSLにコードを埋め込み始めると、ボーナスポイントだね。

本物のプログラミング言語を使って、デバッガーも使おう。YAMLは最悪だし、Starlarkもあんまり良くない。君の意見には賛成だったけど、「Starlark」って言った瞬間から違和感を感じた。俺の経験では、StarlarkはYAMLの百万倍はマシだよ。なんでそう思わないの?

リッチ・ヒッキーのトークを思い出すな。彼はDatomicというデータベースについて話していて、「データベースの問題は、あっちにあることだ」と言ってた。データを不変の「事実」でモデル化することで、データベースのロジックの多くをアプリケーションに近づけられるんだ。彼の場合は、Clojureのデータ構造を使ってね。CIの問題も、あっちにあるのかもしれない。自分のノートパソコンで簡単にセットアップして何度も実行できるものじゃなくなると、もう手遅れだよ。ビルドシステムとの比較は的を射てるね。俺は、リモートキャッシュなしで自分のノートパソコンで作業しているデータベースをビルドできるし、たまにやってるよ。時間はかかるけど、そんなに長くはないし、「このシステムを維持している人たちはこれを試してない」ってエラーも出ない。CIシステムは、もう忘れた方がいい。問題の一部、いや、全体が、すべてを動かしてポータブルで最適化された環境を作れる可能性があっても、結局はあっちでしか動かないってことなんだよね。だから、どんどん悪化していく。これを解決するのは簡単じゃないだろうな。今日の統一された解決策が、明日のレガシーの沼になるかもしれない。でも、それがソフトウェアってもんだよ。

ビルドシステムは完全に宣言的であってほしいんだけど、DSLが必要なことをサポートしてないんだよね。テンプレートとかカスタムスクリプトを入れる場所がちょっとあればいいんだけど。おめでとう!これでチューリング完全なシステムが手に入ったよ。そう、記事によれば、これで仮想通貨のマイニングもできるってことだね。Ansible、Terraform、Maven、Gradle。残念なことに、これらのIT領域(ビルドやCI)は、2つの有名な滑りやすい坂の交差点にいるんだ。1) 設定 2) ワークフロー。この2つの滑りやすい坂は、どれだけクリーンでシンプルか、何でも簡単にできるかのデモで有名なんだよね。デモでは必要なことは何でもできるって。でも、しばらくはそのままでいるかもしれないけど、結局は…スクリプトスープになるよ。

問題の一部、いや、全体の問題かもしれないのは、すべてを動かせてポータブルで最適化できる環境を作れたとしても、結局はあっちでしか動かないってことなんだよね。だからカエルはずっと煮え続ける。コンテナ(またはVM)内でソフトウェアをビルドするのがいいよ。ビルドごとに新しい環境を用意して、キャッシュや以前のビルド成果物を明示的にマウントする感じ。そしたら、これみたいなものがあれば、ローカルでもビルドできるよ:https://docs.drone.io/quickstart/cli/ それで、必要なだけタートルをスタックできる。コンテナビルドの一部として実行されるビルドスクリプトを持ったり、Mavenや必要なものを中に入れたりね。意外とまともに機能するよ。CIサーバーが「docker build -t my_image ...」と同じことをして、その後何かをする感じ。ビルド中はbuild.shスクリプトが中にあるだけなんだけど。

トランザクションと一貫した真実のソース、可視性や時間的順序のことは、ほとんどの場所で中央集権的で「向こう側」にあるんだ。通信の速度に限界がある限り(光の速度とか)、イベントホライズンは存在する。データベースの目的は、変化と時間を中央で追跡することなんだ。やりたいからじゃなくて、他の方法が全部失敗したからなんだよね。競合するCRDTの変更マージやGitのマージも、すぐにややこしくなることがある。人々は10年ごとにデータベースを再発明する。ハードウェアは速くなる。楽しんで見てればいいよ。

だから、CIをローカルやGitHub Actionsで実行できるスクリプトにしちゃったんだ。そしたら、CIは単にそのスクリプトを実行するためのちょっとしたyamlになるだけ。

ビルドはこれでいい:build.bashだけ。それでコンテナビルドもトリガーできるし。CIビルドがローカルビルドと違う動きをするのをデバッグするのに、無駄に時間を使いすぎた。いつもCIサーバーに余計なものが加わってるせいなんだよね。業界でこの「パターン」に従わないビルドを見つけたことがない。環境設定はローカルマシンでもCI/CDサーバーでも同じように動くべきだし、DevOpsチームがAnsibleとか使って同じようにベアメタルにセットアップしてるはず。

CI/CDやDevOpsのルールは、ビルドプロセス全体を1行にまとめることだよ:./build.sh どこかにコンテナを出荷したいなら、「CI」で実行しているか確認するビルドスクリプトの中でやればいい。今使っているCIプラットフォームにベンダーロックされるような派手なワークフローヤムルは必要ない。チェックアウトして、パラメータでビルドして、カバレッジチェッカーを指さすだけ。これ、新入社員のオンボーディングにも同じことが言えるよ。彼らはチェックアウトしてビルドできるべきで、問題や注意点はない、ローカル環境のセットアップもね。これで、彼らはその日の終わりまでにPRの準備ができるようになるんだ。(フォーチュン500の元DevOpsディレクター)

そうだね、ビルドシステムはそれをホストするプラットフォームから独立しているべきだよ。GitHubやGitLabでビルドを実行するのは問題ないけど、自分のインフラで簡単に実行できるべきだ。ビルドや統合の定義はそれとは独立しているべきで、そうした定義を取り込んで実行するソフトウェアはプロプライエタリなSaaSであるべきじゃない。

これ、めっちゃ共感する。最近、プロジェクトのビルドシステムが無視されて、別のものを使うアンチパターンに遭遇することが増えてる。例えば、Mavenプロジェクトがあって、宣言的な規約に従う代わりに、すべてがJenkinsパイプラインだけが知ってるシェルスクリプトの寄せ集めになってるとか。最近のケースでは、重要なビルド機能がJenkinsパイプラインに埋め込まれていて、ローカルマシンからビルドステップを実行するために何をしているのか逆エンジニアリングしなきゃいけない。特にひどい状況で、プロジェクトはパイプラインの実行に依存して基本的なフィードバックを提供してる。CI環境に過剰な責任を持たせると、開発者(またはCIプロセスを維持する人)としての生活が難しくなる。ローカルマシンでもCI環境でも同じように実行できるビルドシステムの一貫した使用が圧倒的に優れてる。これが、他のチームにパイプラインを作ってもらうときの混乱なんだろうね。

最近、モダンな.NETとSQLiteのおかげで、CI/CDの話を完全にスキップできてるんだ。最近、GH Actionsのビルドを試みたけど、イライラして自分でコンソールアプリを書いちゃった。Gitをポーリングしてコミットハッシュを追跡してdotnet buildを実行するのは、ロケットサイエンスじゃないからね。実際のデプロイ先にエージェントを置けば、ボス戦を3回スキップできるよ。

.NETにはこれを簡単にする何かがあるの?

個人的には、開発が全体的に複雑すぎて方向性を誤ってると思う。FAANGを真似してるからね。AWS、Azure、GCPのデプロイが必要?自分でベアメタルに置くことを考えたことある?もしないなら、なんで?ベストプラクティスじゃないから?そんなのナンセンスだよ。こういうことの答えは「ケースバイケース」で、ユーザーがあまり多くないアプリなら、特にB2Bや内部アプリなら、やっても大丈夫だよ。アメリカ中心すぎるのも問題。スケーラビリティの考え方は、他の国にはあまり当てはまらないからね。

要件も複雑だよね。全然スケールしなくても、ゼロダウンタイムデプロイや簡単なロールバック、サーバーのフォールトトレランス、サービスのアイソレーションが必要になることが多い。アプリをコンテナに入れてKubernetesに投げれば、そういうのが「無料」で、しかもよく知られたテスト済みの方法で手に入る。これらの一つでも手作業でやるのは、ましてや全部一緒にやるのは、ものすごく手間がかかるよ。

現代のハードウェアの能力を過小評価してる人も多いよね。約10ドルで、数台のVPSでRedisクラスターを使って、100万の同時接続を処理できるんだから。

なんで誰もこれを言わないのか分からないけど、sourcehutのCIツール(https://man.sr.ht/builds.sr.ht/)はこれを簡素化してくれるよ。好きなLinuxディストリビューションを回して、基本的にたくさんのシェルコマンドを含む非常にシンプルなYAMLを実行するだけだから、ローカルでも簡単に再現できるんだ。全部で12個のYAMLキーワードがあって、すべてをカバーしてる。失敗したビルドにSSHで入れる機能(デバッグ用)や、コミットせずにカスタムYAMLで一回限りのビルドを実行できる機能(テスト用)もあって、便利だと思う。トリガーでビルドを起こすsourcehutのリポジトリだけじゃなくて、どんなリポジトリでもチェックアウトできるはずで、GraphQL APIもあるよ。

人々がActionsを使う大きな理由の一つは、MacOSやWindowsで動かす必要があるからだよね。

YAMLに基づいているものは、簡単なことを trivial にし、難しいことを不可能にするって感じだ。これが原因で、何度もJenkinsに戻っちゃったし、今はもう他のYAMLベースのツールに迷い込むことはないと思ってる。

ちなみに、スレッドの中で何人かが言っていたように、bashをCIとして使う哲学に従えば、ローカルでも実行できるよ。そうすれば、sourcehutとGitHub Actionsの両方で同じCIロジックを使える。どちらも、何でも実行できるVMを提供していて、bashはもちろんすべてのイメージにあるからね。私たちはこれをhttps://oils.pub/ sourcehut yaml: https://github.com/oils-for-unix/oils/tree/master/.builds github yaml: https://github.com/oils-for-unix/oils/tree/master/.github/wo... でやってる。どちらも同じシェルを呼び出している。違いは以下の通り: * GitHubのAPIを使って緑になったらマージする;今のところsourcehutには同じものがない(GitHubがメインリポジトリだから) * GitHub Actionsはもっと多くのリソースを提供している。無料でプロジェクトを「ロックイン」している感じだね。このNixOSに関する投稿がそのヒントを与えているよ。https://blog.erethon.com/blog/2025/07/31/how-nixos-is-built/ 2025年7月のすべてのアクションの月額コストは14500ドルを少し超えたけど、GitHubが全額カバーしている。だから、多くのプロジェクトが徐々にGitHubに吸い込まれていると思う。確かにかなり寛大だからね(私たちもそうで、ちょっとイライラするけど -- 理論的にはsourcehutで全てを実行できるのに、GitHubでのタスクの方が多い)。--- でも、将来的にGitHubから移行できるように、徐々にロジックをシェルに統合するのはいい考えだと思う。オープンソースプロジェクトはクラウドサービスよりも長持ちする傾向があるからね。これ、私たちにも起こったことだよ -- 2018年頃にTravis CIを使い始めて、2021年には買収されて無料プランがなくなったんだ。

sourcehutのbuild.sr.htは、私が使った中で最高のCIシステムだよ。これを仕事で既存のJenkinsソリューションの代わりに試してみたいんだけど、Jenkinsがそんなに悪いとは思ってないんだ。以前、CI/CDシステムにはbashを実行する能力とシークレット管理が必要だと主張していたけど、今日は追加で、bashスクリプトを実行するための隔離された環境を立ち上げる能力も必要だと思う。

Droneは、フリーソフトウェアだった頃は完璧だったよ。「このイベントでこのdockerコンテナ内でこれらのコマンドを実行する」ってだけで、他には何もいらなかった。最後の完全オープンソース版を、たぶんもっと早く切り替えるべきだったのに、ずっと使ってた。商業化された時、GitHub Actionsが明らかな選択肢になったけど、なんか変なことが多すぎて予測不可能なんだよね。Droneの一件で目が覚めたし、もう二度とCLAにはサインしない。

それはWoodpeckerとして生き続けてる、最後の本当に自由なバージョンのフォークだよ。シンプルそのもので、貢献するのにCLAは不要。

コンテナ内でコマンドを実行するだけじゃないんだよね。誤解しないでほしいけど、これは素晴らしい基本機能なんだ。でも、結局は条件付きでテストを実行する必要が出てくる(計算リソースを節約するためにね)。ベンチマークによってはハードウェアが限られていることもあるから、ジョブをまとめて、5回か10回のコミットごとにしか実行しないこともある。ハードウェアを常に温かく保ちたいけど、キューは小さく保ちたいよね。だから、理想的には動的にジョブをまとめたい。結果の報告や、以前の結果との比較も必要だしね。あ、ジョブをまとめたり、条件付きで実行したりするから、後でスキップしたジョブを手動でトリガーする方法も必要だし、バイセクトも必要かも。計算リソースを節約しなきゃいけないとき、CIは本当に複雑になるんだ。特に、壊れやすいベンチマークや不安定なテストがあるときはね。理論的には、不安定なテストを排除する文化を強制できるけど、そうするにはツールのサポートが必要なことが多いんだよね。統計とかさ。

あなたと私では、ワークフローが全然違うと思う。Droneは今まで使った中で、一番直感的じゃないシステムだった。アイデア自体は良さそうなんだけど、実際にはDroneは箱から出しただけじゃ何も役に立たないってことがわかった。ステップ間でアーティファクトを移動したい?残念だけど、それはできない(少なくとも私たちが試したときはできなかった)。結局、すべてをDockerコンテナにまとめて、ただのbashスクリプトを実行することに戻った。Droneを使わなきゃいけなかったのは、設計者たちが「Droneが誰も聞いてない質問の答えだ」と決めたからなんだよね。

現代のCIで一番気になるのは、ほとんどがGitHub Actionsで動いてることと、GitHub自体がAI機能の方にリソースを優先して、GitHub Actionsのメンテナンスや改善を後回しにしてること。マジで、彼らのピン留めされたリポジトリを見てみて: https://github.com/actions/starter-workflows > このGitHubリポジトリに興味を持ってくれてありがとう。ただ今は貢献を受け付けていないんだ。 > お客様が成功するために役立つ戦略的な分野にリソースを集中させ、開発者の生活を楽にすることに注力しています。GitHub Actionsはこのビジョンの重要な部分ですが、他のActionsの分野にリソースを割いていて、今はこのリポジトリへの貢献を受け付けていません。

代わりに、YAMLの代わりに自然言語を使ったAgentic Workflowsに焦点を当ててるみたい。https://github.com/githubnext/gh-aw

最後に働いていた会社がGitHubでコードをホスティングしていたとき、Actionsはまだ存在していなかったし、個人的なことでは3行のコピーで十分だったから、あれを「使っている」とは言えないな。「GitHub Actionsは終わりそうだから、関わる価値がない」は私のビンゴカードにはなかったよ。

OPのビジョンはあまり好きじゃないな。主な反対意見は、このビジョンが完全にオンラインに依存していること。インターネットがダウンしているときや、飛行機の中、あるいは洞窟の中の離島にいるときでも、ローカルでビルド全体を実行できるようにしたいんだ。ローカルビルドとCIは、ローカルビルドが手動でトリガーされて、結果がターミナル(またはIDE)に報告される点だけが違うべきだよ。CIビルドはプッシュでトリガーされて、PR(または他のウェブページ、APIエンドポイントなど)に報告される。エントリーとエグジット以外は同じであるべきだ。タスク、キュー、DAGなどは全部いいけど、結局は実装の詳細に過ぎない。makeだってDAGやタスク、並列実行を持ってるしね。ビルドがローカルで実行できないなら、ビルドがないのと同じ。ローカルビルドとCIの違い、環境やタスクの設定、キャッシュなどのせいでCIが痛いんだ。ローカルビルド用のビルドシステムと別のCIセットアップがあるから、世界には本来あるべきよりも10%多くの苦痛が存在するんだよ。だから、基本的にはCIパイプラインが私のビルドシステムを呼び出す1つのコマンドか、CIパイプラインがローカルで実行できるかのどちらかだね。他のアレンジは自己 inflicted suffering だよ。

CIシステムにはビルド番号を追跡してほしいんだ。ローカルでビルドするときは、99%の時間ビルド番号なんて気にしないし。他にもCIがやってることがいくつかあって、それはローカルでもできるはずなんだけど、実際には気にしないから、違うことがしたいんだよね。

OPのビジョンを完璧に表現してると思う。ビルドシステムとCIパイプラインの統合だね。