Youkiとは
runc同様、OCI runtime specである。Rustで書かれている。日本語の容器が名前の由来。
なお、OCI runtime specは、1. 隔離環境の作成, 2. コンテナ実行, 3. プロセスのKill, 4. コンテナの削除、に関する明文化された仕様を指す。
メリット
Rustで実装するメリットは、Goよりsystem callを扱いやすい(Cを呼び出すオーバーヘッドが少ない、ゼロコスト抽象化などの仕様のおかげ?)、Cと比べてメモリ安全、が挙げられていた。そのおかげか、Youkiは、runcより高速に動作するらしい。
仕様
現在はLinux環境しかサポートしていない。Linux以外の環境で動かしたい場合、VagrantでVMを利用する必要がある。
Youkiは低レベル container runtimeなので、Docker, Podmanなどの高レベル container runtimeと組み合わせて使うことになる。
Youkiには、ルート権限が必要なrootful modeと、不要なrootless modeがある。ルート権限とは、コンテナ内のプロセス権限がルートユーザーと同等かどうか。ルート権限がある場合、セキュリティ面での問題が懸念される。このあたりはコンテナセキュリティ本を読むと、雰囲気がわかるはず。
Dockerで動かす方法
etc/docker/daemon.json
を書き換えることで、Dockerでもyoukiもruntimeとして使える。
{ "default-runtime": "runc", "runtimes": { "youki": { "path": "/path/to/youki/youki", "runtimeArgs": [ "--debug", "--systemd-log" ] } } }
レポジトリの説明
libcgroups
Linux cgroupとやり取りしたりするための機能を担っている。common, stats, systemd, test_manager, v1, v2といったmoduleを持つ。例えば、cgroup fileの読み書きを簡単にしてくれるuser interfaceなどが提供されている。
libcontainer
containerの作成・管理を担う。apparmor, container, hook, namespacesなどの様々なmoduleがある。
liboci-cli
OCI container runtimeのためのCLIを提供している。
libseccomp
libseccompへのRust FFI bindingを提供する。FFIとは、あるプログラミング言語から他プログラミング言語を利用するための機構。この文脈でいうと、RustからC言語で書かれたlibseccompを扱うということだと思う。
Webasssembly
runwasiのように、WebAssembly moduleをYoukiで実行することが可能。
control flow
以下のような流れでYoukiは動作するらしい。
Contribution環境を作るときに試行錯誤したメモ
Rustに関するメモ
コードリーディング・contributionをする際に、分からなかったところのメモ。
Builder
以下のstruct Linuxの場合、ビルダーパターンを利用して初期値を設定することができる。ビルダーパターンを使うと、オブジェクトの構築をstep by stepで行えるようになり、オブジェクトの初期化を扱いやすくしてくれる。コード内でLinuxBuilderが出てきたが、LinuxBuilderというオブジェクトを定義している箇所はなく、LinuxオブジェクトにBuilderがderiveされているだけ。
#[derive(Builder, Clone, Debug, Deserialize, Eq, Getters, Setters, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] #[builder( default, pattern = "owned", setter(into, strip_option), build_fn(error = "OciSpecError") )] #[getset(get = "pub", set = "pub")] /// Linux contains platform-specific configuration for Linux based /// containers. pub struct Linux { #[serde(default, skip_serializing_if = "Option::is_none")] /// UIDMappings specifies user mappings for supporting user namespaces. uid_mappings: Option<Vec<LinuxIdMapping>>,
Linux Builderの初期化例
// Linux構造体のビルダーを使用して、uid_mappingsに値を設定 let linux = Linux::builder() .uid_mappings(vec![uid_mapping]) // ここでuid_mappingsにベクターを設定 .build() // ビルダーパターンを完成させ、Linuxインスタンスを生成 .expect("Failed to build Linux"); // build()メソッドがエラーを返す可能性があるため、unwrap()やexpect()で処理
enum型
以下のようなenum型があるとする。
#[derive(Debug, thiserror::Error)] pub enum InitProcessError { #[error("failed to set sysctl")] Sysctl(#[source] std::io::Error), #[error("failed to mount path as readonly")] MountPathReadonly(#[source] SyscallError),
enum型は、以下のように、InitProcessError::Sysctl (各enumの値)、のように指定して使う。
fn set_sysctl() -> Result<(), InitProcessError> { Err(InitProcessError::Sysctl(io::Error::new(io::ErrorKind::Other, "oh no!"))) }
contribution環境の構築
私はLinux環境 PCでは無いので、CodeSpaceを使用した。EC2(amazon Linux)も試したが、CodeSpaceの方がラクだった。
just
justとは、makeに影響を受けたtask runner。Makefileと違って、.PHONYが不要なので簡潔に書ける。
install方法はdocumentに書いてある(makeで良いのでは?と思った)
curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to ~/bin export PATH="$PATH:$HOME/bin"
golang
runtime-toolsを動かすために、go 1.19が必要。apt-getだとversion指定できないのでwgetでversion指定してインストールした。
wget https://go.dev/dl/go1.19.13.linux-amd64.tar.gz sudo tar -C /usr/local -xzf go1.19.13.linux-amd64.tar.gz export PATH="$PATH:/usr/local/go/bin"
Rustc
CodeSpaceではすでにインストールされていて不要。EC2 amazon Linuxで動かすときはインストールが必要。
curl https://sh.rustup.rs -sSf | sh
GitHubとの接続
CodeSpaceでは不要。EC2 amazon Linuxで動かすとき必要だった。
sudo yum install -y git ssh-keygen -t rsa -b 4096 cat ~/.ssh/id_rsa.pub # 結果をgithub settingsに貼り付ける。 ssh -T git@github.com git clone git@github.com:hogehoge/youki.git
その他のライブラリ
CodeSpaceでは不要。EC2 amazon Linuxで動かすとき必要だった。このあたりはYoukiのREADMEに書いてある。
sudo dnf install \ pkg-config \ systemd-devel \ elfutils-libelf-devel \ libseccomp-devel \ clang-devel \ openssl-devel # 以下のコマンドを実行してリンカーを入れる。 sudo dnf install glibc-static libstdc++-static