youki + libkrun
youkiとlibkrunを利用したVM型のコンテナの起動について説明する
-
youki
- ContainerBuilderがbuild関数を実行するときにpre_exec関数を実行する
- 通常のコンテナと同じく, Main Process, Intermediate Process, Init Processを実行する
- 最後にInit Processでlibkrun用のexec関数を実行する
-
Executor(libkrun 用)
- run.oci.handler=krun の OCI annotations が付いているコンテナだけを担当(それ以外は CantHandle を返してフォールバック)。
- pre_exec(spec): 実行前の準備(libkrun.so ロード, krun_create_ctx で ctx 生成, spec の調整 と .krun_config.json の出力 など)
- config.jsonを読み込んだ後, 且つ コンテナ作成操作(namespace作成, pivot_root)する前にExecutorで設定する必要のある処理があるためこの関数を作成した
- exec(spec): libkrun API を呼んで VM を実際に起動(krun_set_vm_config, krun_set_root, krun_start_enter)
-
libkrun
- KVMを利用してVMを起動する
- libcontainer
- ContainerBuilderがbuild関数を実行するときにpre_exec関数を実行するように変更
- この変更は通常のコンテナ起動処理に影響は与えない想定
- Executor
- features flagを利用し、libkrun用のコンテナを起動する時のみに実行するexec関数を用意した.この変更による影響はない。
- Executorでlibkrunに関する値(lib, ctx_id)を保持したいので、DefaultExecutorに修正を加えた.
- 現状のget_executorを毎回実行する方式では値が初期化されてしまうため
youki と libkrun を利用して VM 型コンテナを起動する手順を示す。
-
youki を実行する
- OCI バンドルの
config.jsonにannotations."run.oci.handler" = "krun"を設定
- OCI バンドルの
-
libcontainer で InitContainerBuilder/TenantContainerBuilderの
buildを実行する- Executor の
pre_execを呼ぶinit_builder.rs/tenant_builder.rsのbuild内で実行する想定config.jsonを読み込んだ直後かつ pivot_root より前に実行する- wasm 系と同様に features flag で有効化
can_handleで実行可否を判定
- libkrun をロードし、コンテキストを作成する
- 名前空間切替前 & pivot_root 前に
libkrun.soのロード とkrun_create_ctx()を行う - そうしないとバンドルされたファームウェア(libkrunfw)等が見つからない場合がある(crun 実装に準拠)
- 名前空間切替前 & pivot_root 前に
/dev/kvmを使うためにconfig.jsonを更新する- 存在しない場合、
linux.devicesに/dev/kvmを追加 - デバイス制限がある場合
resources.devicesに/dev/kvmの allow ルールを追加
- 存在しない場合、
config.jsonを複製してrootfs/.krun_config.jsonを作成するprocess.argsが VM 起動時のコマンドになる(krun_set_execと同等の役割)- セキュリティ上、
openat+O_NOFOLLOW相当で rootfs 直下へ安全に書き込む - https://github.com/containers/crun/blob/02a963f9f451d217affc277efa5dcffb6afebf87/src/libcrun/handlers/krun.c#L516
- Executor の
-
通常どおり Main / Intermediate / Init の各プロセスを生成する
-
Init Process で
executor.execを呼ぶ- feature = libkrun の時は libkrun 用 Executor を実行する(
CantHandleの場合はフォールバック)
- feature = libkrun の時は libkrun 用 Executor を実行する(
-
libkrun の起動前設定を行う(Init 側)
krun_set_vm_config(ctx, vcpus, ram_mib):VM に割り当てる vCPU 数とメモリを設定krun_set_root(ctx, "/"):ゲスト OS のルートを設定(pivot_root済みのため"/"を渡す)krun_set_log_level(ctx, 1):ログレベルを設定(例:1=error)
-
VM を起動する
krun_start_enter(ctx)を呼ぶ。
sequenceDiagram
participant youki
participant Main Process
participant Intermediate Process
participant Init Process
participant Executor
participant libkrun
participant kvm
Note over youki: load config.json
rect rgb(235,250,235)
youki->>Executor: pre_exec()
opt feature "libkrun"
Executor->>libkrun: load libkrun.so
Executor->>libkrun: krun_create_ctx()
Note over Executor: modify config.json
Note over Executor: setup .krun_config.json
end
end
youki->>Main Process: container_main_process()
Main Process->>Intermediate Process: clone3
Intermediate Process->>Init Process: clone3
Note over Init Process: pivot_root
Init Process->>Executor: exec()
rect rgb(235,250,235)
opt feature "libkrun"
Executor->>libkrun: krun_set_vm_config()
Executor->>libkrun: krun_set_root()
Executor->>libkrun: krun_set_log_level(1)
Executor->>libkrun: krun_start_enter()
libkrun->>kvm: start
end
end
kvmが有効になっていることを確認する
lsmod | grep kvm
kvm_intel 483328 0
kvm 1425408 1 kvm_intel
irqbypass 12288 1 kvm
libkrunとlibkrunfwをインストールする
https://github.com/containers/libkrun
https://github.com/containers/libkrunfw
ls /usr/local/lib64 | grep libkrun
libkrun.so
libkrun.so.1
libkrun.so.1.15.0
libkrunfw.so
libkrunfw.so.4
libkrunfw.so.4.10.0
edit config.json
"annotations": {
"run.oci.handler": "krun"
}
cd crate/youki
LD_LIBRARY_PATH=/usr/local/lib64 cargo run --features libkrun --features systemd run -b ../../tutorial/ container
DEBUG libcontainer::user_ns: this container does NOT create a new user namespace
DEBUG youki::workload::libkrun: executing libkrun pre executer
...
DEBUG libcontainer::notify_socket: notify container start
DEBUG libcontainer::notify_socket: notify finished
DEBUG libcontainer::notify_socket: received: start container
DEBUG libcontainer::container::container: Save container status: Container { state: State { oci_version: "v1.0.2", id: "container", status: Running, pid: Some(31812), bundle: "/home/ubuntu/workspace/youki/tutorial", annotations: Some({"run.oci.handler": "krun"}), created: Some(2025-09-02T23:26:08.276279669Z), creator: Some(0), use_systemd: false, clean_up_intel_rdt_subdirectory: Some(false) }, root: "/run/youki/container" } in "/run/youki/container"
DEBUG youki::workload::libkrun: executing libkrun executer
~ #
another terminal
ps aux | grep youki
root 31735 0.3 0.0 38144 14000 pts/1 S+ 23:26 0:00 /home/ubuntu/workspace/youki/target/debug/youki run -b ../../tutorial/ container
root 31812 0.1 0.0 1512708 63472 ? Ssl 23:26 0:00 /home/ubuntu/workspace/youki/target/debug/youki run -b ../../tutorial/ container
root 31981 0.0 0.0 7076 1868 pts/3 S+ 23:27 0:00 grep --color=auto youki
$ pstree -p 31735
4(31735)───libkrun VM(31812)─┬─{libkrun VM}(31814)
├─{libkrun VM}(31815)
├─{libkrun VM}(31817)
├─{libkrun VM}(31818)
├─{libkrun VM}(31819)
├─{libkrun VM}(31820)
└─{libkrun VM}(31821)
- youki run以外
- テスト libkrunがない環境でもできるようにしたい
- ルートレスコンテナ(何か追加が必要か)
- サポート like crun
- SEV, Nitro Enclaves virtio-gpu