binary cacheとpackage repositoryは似ているが一次性が違う
binary cacheとbinary package repositoryは、どちらもHTTP等からビルド済みartifactを取得するため、利用者からはよく似て見える。しかし設計上は「何を一次的なpackage universeとみなすか」が異なる。
ビルド済みパッケージ配布を一括りにしない のNix/Guix/Spack型では、build definitionやconcretized specが先にあり、cacheはそのbuild resultを再利用する層として置かれる。Nixのsubstituteは「バイナリパッケージ」よりbuild resultに近い のNixでは特に明確で、substituteが見つからなければderivationをbuildできる。
一方、APTのようなdistribution repositoryでは、repositoryのPackages indexに列挙された.deb群がinstallerから見えるbinary package universeになる。APTは複数repositoryのPackages metadataを取得してversion/dependencyを解決する。source package用のdeb-srcは存在するが、通常のbinary install operationがcache miss時にそのsource packageを自動buildして同じpackageを生成するモデルではない。
Conda channelもこちらに近い。channelに公開されたbinary packageのmetadataをsolverが読み、互換なpackage集合を選ぶ。linux/amd64だけではビルド済みバイナリの互換性を表せない のvirtual packageはhost条件をsolverへ入れる仕組みだが、目的のbinary buildがchannelに存在しなければ、それは通常のsolverから見ればinstall候補にならない。
この差を簡略化すると次のようになる。
- build cache: 「このbuild/specを実行した結果は既にあるか?」を問い合わせる
- package repository: 「install可能なpackageとして何が公開されているか?」を問い合わせる
ただし境界は連続的である。Homebrew Bottleはformulaというrecipeを持つためcache的だが、一般利用者にはBottle repositoryが事実上のbinary distribution channelでもある。Spack Build Cacheも十分大規模になればbinary repositoryのように利用できる。逆にrepository側もsource packageやbuild serviceを持つことがある。
したがって違いはprotocol名ではなく、cache missがsemantically何を意味するかを見ると分かりやすい。
- Nix: build resultがcacheに無いのでbuildする
- Spack: concretized specのbinaryが無ければsource buildへ戻せる
- APT: repositoryにそのbinary package/versionが無ければ、別repositoryやversionを探す必要がある
- Conda: solverがavailable buildsの中から別の解を探す
この違いはprebuiltがないときのsource build fallbackは同じ意味ではないにも繋がる。
またcacheではbuild action/specとartifact identityの対応が重要になるため、lockfileで依存を固定してもreproducible buildにはならない や binary cacheの公開鍵を追加することはbuilderを信頼することに近い が中心課題になる。一方repositoryではrepository metadataのfreshnessやindex signing、署名検証だけではrollback・freeze attackを防げない のようなupdate securityがより前面に出る。
実装技術としては両者ともCDN、object storage、content-addressed blob store、OCI Registry等をbackendにできるため、storage layerだけを見て分類することはできない。何がauthoritative metadataであり、artifactが無いときsystemがどう振る舞うかを見る必要がある。