satysfi-docker の opam-slim タグ

(これは主に自分の備忘のための記事です)

最近出た opam-bin を使って、opam で satysfi パッケージをインストールできる小さい docker image を作りました。satysfi-docker の opam-slim タグです (experimental 扱い)。

satysfi-docker については

satysfi-docker を使って SATySFi をお手軽に試す - amutake's blog

を参照してください。

2020-12-20 追記

opam-bin はやめました。

依存を消して無理やりインストールする方法は opam-bin を使わなくてもできることに気がついたので、そうすることにしました。ビルド時間も普通になり、デバッグも簡単になりました。

github.com

opam ファイルのフィールド順に依存しているのがやばいですがビルドできなくなったらすぐ直せるでしょう…。

背景

satyrographos-repo というリポジトリがあります。これは satysfi のパッケージを集めた opam リポジトリです。 satyrographos-repo にある SATySFi のパッケージは、そのほとんどが satysfi と satyrographos を依存に持っているので、satysfi と satyrographos を opam 経由でインストールしていないとインストールできません。 amutake/satysfi:latest はそういうわけで opam で satysfi と satyrographos をインストールしたものをそのまま残していて、ocaml コンパイラと satysfi/satyrographos の依存ライブラリが全部入っているのでかなり大きいイメージになってしまっていました。

そこで amutake/satysfi:slim という小さいイメージを作ったのですが、これは satysfi と satyrographos のバイナリだけを入れたものになっていて opam 環境がありません。 satysfi 単体で使うならいいのですが、opam がないと satyrographos が入っている意味がほぼありません (なくはないのですが、よさの9割が失われてしまう linter などあるので9割は言い過ぎでしたすみません)。

現状では satysfi の外部パッケージを使いたい (opam を使いたい) なら latest、いらないなら slim、という使い分けをする感じになっています。

最近は satyrographos-repo に便利なパッケージが増えてきていて、opam を使いたい場面も多くなってきました。 ただ latest は大きすぎて CI で使うといちいちダウンロードだけで30秒くらい1分以上かかってしまうので、「うーんじゃあ git submodule にしちゃうか」みたいな気持ちになっていました。

satysfi の slack を見ていると、opam-bin というのが最近出て satysfi-docker のイメージも小さくできるのではという話があったので、やってみました。

opam-bin

opam-bin はビルド済みバイナリの opam リポジトリを簡単に作れる opam plugin です。一度ビルドしてしまえば再インストールは速く行えます。

詳しくは https://ocamlpro.github.io/opam-bin/ を見てください。でもところどころ動かないことがあります。ハマりポイントメモとしては、どうも依存ライブラリは全部 opam-bin がある状態でインストールされていないとローカルのバイナリ用 opam リポジトリ (local-bin という名前) に登録されないようで、つまりは opam-bin をインストールしたあとに opam switch して別の switch を新しく作り直さないといけないところでハマりました。追記: いまドキュメントを改めて見たら普通にこのこと書いてありました…

あとなんとなく static なバイナリを生成してくれるのかなと思っていましたがそういうやつではありませんでした。

やったこと

Experimental opam-slim tag by amutake · Pull Request #38 · amutake/satysfi-docker · GitHub

opam-bin はビルド済みバイナリの opam リポジトリを作ってくれますが、各パッケージの依存関係は (いいのか悪いのか) 保存されます。 なので、opam-bin を普通に使っているだけでは今回の目的にはあまり効果がありません。satysfi のビルド済みバイナリを再インストールしても結局依存ライブラリが全部インストールされてしまうからです。

ですが、他の switch に移ってもビルド済みバイナリのインストールができる、そして依存ライブラリの定義を消してもインストールが可能という特徴があります (普通は当たり前ですが依存ライブラリの定義を空にするとビルドできなくなる)。

そこで、opam-bin を使ってバイナリだけインストールしつつ、opam pin で local-bin からコピーをしてきて opam ファイルをいじくって依存ライブラリを無理やり空にしました。 これで依存ライブラリをインストールすることなしに satysfi と satyrographos をインストールすることができました。

ただ、opam-bin を使うとバージョンが 元のバージョン+bin+ハッシュ値っぽい文字列 になってしまい、これだと satysfi の特定のバージョンでしか動かないパッケージがインストールできない問題が出てきそうです。 これに対してもまた opam ファイルをいじくってバージョンを元のバージョンに戻してインストールするようにしました。

…というあまりよろしくなさそうなことをしました。あまりよろしくないのでいつトラブルが発生するかわからないということで experimental 扱いにしています。 でも適当に自分で使う分には便利だと思います。壊れたら教えて下さい。

これによってイメージのサイズを277MB (圧縮後で約100MB) にすることができました。latest は2.51GB (圧縮後で約800MB) なので CI でもだいぶ使いやすくなったと思います。 たぶん自分はこのタグだけ使う感じになりそうです。

たぶん、あるパッケージを opam install せずにインストール済み扱いにする方法があればもっと簡単にできそう & opam-bin を使わなくてもいいのですが、探しても見つかりませんでした。 どちらにしろいい方法ではないと思うのですが、opam-bin を使う方法はいちいちデバッグに時間がかかって辛すぎる (switch を分けないといけない関係で ocaml コンパイラのビルドが2回走る。イメージを小さくするためにキャッシュも効かせられないので、opam でビルド済みの ocaml コンパイラを使い回す方法があればいいのですが…。まあ system 使えということなのかもしれません) ので、それをなくせるだけでだいぶ嬉しいです。

他にもなにかいい方法を知っている方がいれば教えて下さい。

他メモ

  • conf-satysfi と conf-satyrographos を作って satyrographos-repo のパッケージ群をそれに依存するようにすると satysfi と satyrographos のバイナリだけ持っておけばよくなったりするのかな、と思いました。conf-* のことをあまりよく知らないのでそれが本当にいいかどうかはわかりません。opam にある各種 ocaml ライブラリも依存に ocaml が入っているのでだめかもしれません。
  • そろそろタグの名前の整理をしたい気がしています。opam-slim が問題なさそう (各種ハックを消せた) なら、今の opam-slim を latest に、今の latest を full かなにかに、今の slim と nightly は消して、satysfi と satysfi-dist だけインストールしてあるものを slim かなにかに、nightly は opam-slim の nightly 版に、という感じにしたい気がしています。
    • あといままでは satysfi の更新に合わせてイメージを更新していて satyrographos のバージョンの更新もそれに合わせてやっていたのですが、satysfi よりも satyrographos のほうが更新が早い (そして satyrographos のバージョンが古くなってしまう) ので、 amutake/satysfi:0.0.5-satyrographos-0.0.2.8 みたいなタグにするのもありかもと思っています。
    • あるいは イメージの名前を分けてしまって、satysfi と satyrographos にするのもいいかもしれません。
  • あと全然関係ないですがリポジトリの名前を satysfi-docker から docker-satysfi に変えたいです。docker は prefix についているもののほうが多そうなのと、 satysfi-docker だと docker 関連のコマンドが詰まった SATySFi パッケージみたいな名前に見えます。docker 関連のコマンドって何というのはありますが…。