Skip to content

Instantly share code, notes, and snippets.

@n4mlz
Last active January 27, 2025 12:18
Show Gist options
  • Save n4mlz/19533b78a2d83603b42fb30b65936ee0 to your computer and use it in GitHub Desktop.
Save n4mlz/19533b78a2d83603b42fb30b65936ee0 to your computer and use it in GitHub Desktop.
tiny-runc の失敗と Go の悪口

tiny-runc は、非特権環境で動作する OCI Runtime Specification 準拠の低レベルコンテナランタイムを目指して開発している。tiny-runc という名前の通り、「runc」という OSS を参考に書いている。runc は、Docker や Podman の中で動いている低レベルコンテナランタイムである。実際は youkiappare45 作の socker など、多くのコンテナランタイムの実装を参考に書いている。

tiny-runc はコードをめちゃくちゃ丁寧に書いて、人々のコンテナ自作の実装のサンプルにして欲しい!みたいな気持ちがあって書いていたが、だいぶ失敗した。まず Go はシステムプログラムに向いていない。fork と exec を分離できないのは論外。例えば fork したあとの処理を親と子で 1 つずつ書けばいいところを、わざわざ子プロセス用の処理を自身のサブコマンドとして分けて、親から自分自身を呼び出す、みたいな遠回りなことをしないといけない。しかもそうすると明確にプロセスが別れてしまうので、親で利用していた構造体を子で使うみたいなことができない。せっかくオブジェクト指向的抽象化を行っているのに、プロセスを fork するたびに exec を行ってしまうと、もう一度同じ構造体を作らないといけない。

ちなみに runc ではこの問題を、「namespace の分離の部分は C 言語で記述する」という方法を取って解決している (参考)。ただこの方法は「シンプルで理解しやすいコードで簡潔に記述する」という、tiny-runc で満たしたかったことと反してしまうので、tiny-runc ではこれを行っていない。結果、fork するためにわざわざ子プロセス用の処理を自身のサブコマンドとして分けて、親から自分自身を呼び出すみたいなカスみたいなコードになってしまったのだ。

パスとパッケージが同じ扱いなので、循環インポートを避けるために同一パッケージにしたい、あるいはドメインモデリング的に同一パッケージの方が自然だが同じパスにファイルが増えすぎてしまい、ある程度のまとまりごとに整理したい、みたいな時に非常に困る。

それまでは「Go って雑に書けていいね」みたいに思っていたのに、この件のせいで一気に Go が好きではなくなった。まぁ、runc でも名前空間を分けたり fork したりする部分だけは C で書かれているくらいだし、「Go でシステムプログラムをするな」という話ではありそう。

正直、tiny-runc は失敗した。Go でシステムプログラムをするべきではない。だから現在は tiny-runc 同じ目標をかかげつつ、新たに「tiny-youki」を書いている。今のところ自分でもかなり綺麗に書けていると思っていて、「私が本当に書きたかったコードはこういうものだ!!」と思っている。もしここまで読んでくれている方がいるのであれば、是非とも tiny-youki の方も参照してみてほしい。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment