外部記憶装置

外付け記憶装置

Mewz on libkrun - その1 libkrun を試す

Mewz (WebAssembly x Unikernel) を libkrun で動かしてみた - 外部記憶装置 の詳細を記すシリーズ

目次

libkrun とは

libkrunRedHat のエンジニアである Sergio López 氏によって開発されている、コンテナ向けのVMMである。

github.com

VMM としては QEMU が代表例として知られているが、 QEMU はコンテナ向けに利用するにはフットプリントが大きく、コンテナ向けとしては扱いにくい問題がある。 そういった点を踏まえ、libkrun は、コンテナ向けにカスタマイズされた専用の Linux カーネルを動かすために必要最低限な仮想デバイスのみ提供するシンプルなVMMとして設計されている。 Kubernetes 等のコンテナオーケストレーションシステムと合わせて利用されることも想定され、ホストの Network Namespace 経由で通信するための passt との統合や、TSI と呼ばれる virtio-vsock を用いて通信する仕組みを持つ。

libkrun 自体はその名のとおり共有ライブラリとして提供され、CAPI経由で呼び出すことができるため、crun などの既存のコンテナソフトウェアと組み合わせやすいという特徴を持つ。

専用の Linux カーネルについても libkrunfw という共有ライブラリとして提供されている。 実体としては、Linux カーネル全体が配列として定義され、CAPI経由でエントリアドレスやバイナリ自体が提供される仕組みとなっている。

github.com

詳細については以下の記事にて詳しく解説されている。

rheb.hatenablog.com

logmi.jp

libkrun をビルドする

libkrun のビルドには Rust ツールチェインが必要であるため、あらかじめインストールしておく。

$ rustc --version
rustc 1.82.0 (f6e511eec 2024-10-15)

libkrunfw のビルド

まず、libkrunfw をビルド、インストールする。Linux kernel も同時にビルドされるため、必要なパッケージ群をインストールしておく。

$ sudo apt install libncurses-dev gawk flex bison openssl libssl-dev libelf-dev autoconf python3-pyelftools
$ git clone https://github.com/containers/libkrunfw
$ cd libkrunfw
$ mkdir build
$ make -j $(nproc)
$ DESTDIR=./build make install

kernel のビルドが走るため、暫く待つ。ビルドに成功すると、libkrunfw.so.4.6.0 という共有ライブラリが生成される。

$ ls -l build/usr/local/lib64/
total 19204
lrwxrwxrwx 1 naoki naoki       14 Dec 28 17:22 libkrunfw.so -> libkrunfw.so.4
lrwxrwxrwx 1 naoki naoki       18 Dec 28 17:22 libkrunfw.so.4 -> libkrunfw.so.4.6.0
-rwxr-xr-x 1 naoki naoki 19662520 Dec 28 17:22 libkrunfw.so.4.6.0

libkrun のビルド

次に、libkrun をビルドする。patchelf が必要なため、これもインストールしておく。

$ sudo apt install patchelf
$ git clone https://github.com/containers/libkrun
$ cd libkrun

libkrunfw.so を通常とは異なるパスにインストールしたため、rustc の探索パスに上記のパスを追加しておく。

diff --git a/src/libkrun/build.rs b/src/libkrun/build.rs
index a3ccc22..7e78f2d 100644
--- a/src/libkrun/build.rs
+++ b/src/libkrun/build.rs
@@ -1,4 +1,6 @@
 fn main() {
+    println!("cargo:rustc-link-search=../libkrunfw/build/usr/local/lib64");
+
     #[cfg(target_os = "macos")]
     println!("cargo:rustc-link-lib=framework=Hypervisor");
     #[cfg(target_os = "macos")]

今回はネットワーク機能を利用するために NET=1 をオプションに追記してビルドする。 なお、オプションとしてはブロックデバイス(virtio-blk) を有効化するBLK=1 なども存在する。

$ make NET=1
$ ls -l target/release/libkrun.so
-rwxr-xr-x 2 naoki naoki 3712296 Dec 28 17:28 target/release/libkrun.so

ビルドに成功すると、libkrun.so が得られる。 libkrun では、この共有ライブラリを呼び出す形で利用する。 そのため、libkrun を利用するためには自分で呼び出すコードを書く必要があるが、今回はexamplesに含まれるchroot_vmを利用する。

一旦共有ライブラリをまとめ、examples/Makefile に共有ライブラリの探索パスを追加する。

$ cp -r ../libkrunfw/build/usr/local/lib64 lib
$ cp target/release/libkrun.so* lib/.
diff --git a/examples/Makefile b/examples/Makefile
index 8c16305..4059676 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -1,6 +1,6 @@
 ARCH = $(shell uname -m)
 OS = $(shell uname -s)
-LDFLAGS_x86_64_Linux = -lkrun
+LDFLAGS_x86_64_Linux = -lkrun -L../lib -Wl,-rpath-link,../lib
 LDFLAGS_aarch64_Linux = -lkrun
 LDFLAGS_arm64_Darwin = -L/opt/homebrew/lib -lkrun
 LDFLAGS_sev = -lkrun-sev

ビルドし、LD_LIBRARY_PATH で共有ライブラリを配置したディレクトリを指定して実行する。

$ make
$ LD_LIBRARY_PATH=../lib ./chroot_vm
Missing COMMAND argument
Missing NEWROOT argument

Usage: ./chroot_vm [OPTIONS] NEWROOT COMMAND [COMMAND_ARGS...]
OPTIONS:
        -h    --help                Show help
              --net=NET_MODE        Set network mode
              --passt-socket=PATH   Instead of starting passt, connect to passt socket at PATHNET_MODE can be either TSI (default) or PASST

NEWROOT:      the root directory of the vm
COMMAND:      the command you want to execute in the vm
COMMAND_ARGS: arguments of COMMAND

rootfs の作成

最後に、libkrun で利用する rootfs を作成する。podman を利用した rootfs 作成用のコマンドが用意されているため、それを利用する。

$ sudo apt install podman
$ make rootfs
$ ls -l
...
drwxr-xr-x 18 naoki naoki      4096 Dec 28 17:49 rootfs_fedora
...

libkrun を動かす

rootfs として rootfs_fedora が作成されるため、それを利用して chroot_vm を実行する。 なお、/dev/kvm を利用するため、通常は sudo で起動する必要がある。

$ sudo LD_LIBRARY_PATH=../lib ./chroot_vm ./rootfs_fedora /bin/sh
sh-5.2# uname -a
Linux localhost 6.6.63 #1 SMP PREEMPT_DYNAMIC Mon Dec  2 11:39:28 CET 2024 x86_64 GNU/Linux
sh-5.2# echo "nameserver 8.8.8.8" > /etc/resolv.conf
sh-5.2# curl example.com
<!doctype html>
<html>
<head>
    <title>Example Domain</title>

    <meta charset="utf-8" />
    <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style type="text/css">
...

ネットワーク機能付きでビルドしたため、外部のウェブサイトにもアクセス可能であることがわかる。

まとめ

今回の記事では、 libkrun のビルドから実際に動作させるまでをまとめた。 次の記事では libkrun の内部をまとめる。