Youkiの基礎知識とcontribution環境構築

Youkiとは

runc同様、OCI runtime specである。Rustで書かれている。日本語の容器が名前の由来。

なお、OCI runtime specは、1. 隔離環境の作成, 2. コンテナ実行, 3. プロセスのKill, 4. コンテナの削除、に関する明文化された仕様を指す。

メリット

Rustで実装するメリットは、Goよりsystem callを扱いやすい(Cを呼び出すオーバーヘッドが少ない、ゼロコスト抽象化などの仕様のおかげ?)、Cと比べてメモリ安全、が挙げられていた。そのおかげか、Youkiは、runcより高速に動作するらしい。

仕様

現在はLinux環境しかサポートしていない。Linux以外の環境で動かしたい場合、VagrantVMを利用する必要がある。

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は動作するらしい。

Youki flow

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

参考

github.com

containers.github.io