Youkiを動かしてみる

## 概要

Kubernetesではコンテナを作成するとき、コンテナランタイム(高レベルランタイム、低レベルランタイム)を利用しています。

低レベルランタイムであるyoukiを通じてコンテナに関する理解をちょっと深めます。

## Youkiとは?
YoukiはRust言語で記載された低レベルコンテナランタイムです。
最近CNCFのsandboxとして登録されました。
モチベーションとしてruncよりも高速、Cよりもメモリ安全などがあると思います。

https://github.com/youki-dev/youki

## コンテナランタイムとは?

コンテナランタイムはコンテナを実行、管理する仕組みのことです。

主にコンテナのライフサイクルを管理する高レベルランタイムと実際のコンテナを作成する低レベルランタイムに別れます。

## Kubernetesでは?

KubernetesでPodを作成する場合にはKubeletが実際にコンテナを作成しますが、その中ではコンテナランタイムが利用されています。

* Kubeletが自分のノードで実行するPodの情報を取得
* KubeletはCRIを通じて高レベルコンテナランタイムにコンテナ作成のリクエストを送信する
* 高レベルランタイムは低レベルランタイムを呼び出して、コンテナを作成する

![スクリーンショット 2024-12-25 18.36.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526312/9b89b7d2-0575-7b0f-f9ce-5c684cabb539.png)

## Youkiを動かしてみる

youkiを実際に動かして、低レベルランタイムが何をやっているか体験してみます。(runcでも大体同様に実行できます)

EC2インスタンス(Ubuntu Server 24.04 LTS (HVM))上で実施
(youkiはDev Containerが用意されているので,そちらを利用することもできます)

## 準備

youkiをビルドする

必要なpackageをインストール

```
sudo apt-get install    \
      pkg-config          \
      libsystemd-dev      \
      build-essential     \
      libelf-dev          \
      libseccomp-dev      \
      libclang-dev        \
      libssl-dev
```

**Build**

just youki-devでyoukiのバイナリが作成されます。

```
git clone git@github.com:containers/youki.git
cd youki
just youki-dev
./youki -h
```

**ファイルシステムを取得する**

コンテナを動かすためのファイルシステムを用意します。

```
docker export $(docker create busybox) | tar -C rootfs -xvf -
```

**config.jsonの雛形を作成**
低レベルランタイムではconfig.jsonで実際のコンテナの設定を行います。

```
./youki spec
```

config.jsonのargsを以下の値に変更

```
  "process": {
    "terminal": false,
    "user": {
      "uid": 0,
      "gid": 0
    },
    "args": [
      "sleep", "300"
    ],
```

**事前確認**

コンテナ作成前のnamespaceやcgroupを確認してみます。

lsnsコマンドでnamespace確認

```
$ lsns -o NS,TYPE,PATH,NPROCS,PID,PPID,COMMAND,UID,USER     
NS TYPE   PATH               NPROCS   PID PPID COMMAND                                UID USER
4026531834 time   /proc/1/ns/time       111     1    0 /sbin/init                               0 root
4026531835 cgroup /proc/1/ns/cgroup     111     1    0 /sbin/init                               0 root
4026531836 pid    /proc/1/ns/pid        111     1    0 /sbin/init                               0 root
4026531837 user   /proc/1/ns/user       111     1    0 /sbin/init                               0 root
4026531838 uts    /proc/1/ns/uts        105     1    0 /sbin/init                               0 root
4026531839 ipc    /proc/1/ns/ipc        111     1    0 /sbin/init                               0 root
4026531840 net    /proc/1/ns/net        111     1    0 /sbin/init                               0 root
4026531841 mnt    /proc/1/ns/mnt        101     1    0 /sbin/init                               0 root
4026532172 mnt    /proc/189/ns/mnt        1   189    1 ├─/usr/lib/systemd/systemd-udevd         0 root
4026532173 uts    /proc/189/ns/uts        1   189    1 ├─/usr/lib/systemd/systemd-udevd         0 root
4026532193 mnt    /proc/332/ns/mnt        1   332    1 ├─/usr/lib/systemd/systemd-resolved    991 systemd-resolve
4026532202 mnt    /proc/474/ns/mnt        1   474    1 ├─/usr/lib/systemd/systemd-networkd    998 systemd-network
4026532215 mnt    /proc/684/ns/mnt        2   684    1 ├─/usr/sbin/chronyd -F 1               110 _chrony
4026532216 mnt    /proc/22353/ns/mnt      1 22353    1 ├─/usr/lib/polkit-1/polkitd --no-debug 989 polkitd
4026532217 uts    /proc/586/ns/uts        1   586    1 ├─/usr/lib/systemd/systemd-logind        0 root
4026532218 uts    /proc/684/ns/uts        2   684    1 ├─/usr/sbin/chronyd -F 1               110 _chrony
4026532272 mnt    /proc/586/ns/mnt        1   586    1 ├─/usr/lib/systemd/systemd-logind        0 root
4026532273 mnt    /proc/3964/ns/mnt       1  3964    1 ├─/usr/sbin/irqbalance                   0 root
4026532274 uts    /proc/742/ns/uts        1   742    1 ├─/usr/sbin/rsyslogd -n -iNONE         102 syslog
4026532280 uts    /proc/22353/ns/uts      1 22353    1 ├─/usr/lib/polkit-1/polkitd --no-debug 989 polkitd
4026532288 mnt    /proc/22365/ns/mnt      1 22365    1 └─/usr/sbin/ModemManager                 0 root
4026531862 mnt    /proc/26/ns/mnt         1    26    2 kdevtmpfs                                0 root
```

systemd-cglsコマンドでcgroup確認

```
systemd-cgls
CGroup /:
-.slice
├─user.slice
│ └─user-0.slice
│   ├─session-c13.scope
│   │ ├─124828 su
│   │ ├─124845 bash
│   │ ├─124856 systemd-cgls
│   │ └─124857 pager
│   └─user@0.service …
│     └─init.scope
│       ├─124831 /usr/lib/systemd/systemd --user
│       └─124833 (sd-pam)
├─init.scope
│ └─1 /sbin/init
└─system.slice
  ├─irqbalance.service
  │ └─3964 /usr/sbin/irqbalance
  ├─containerd.service …
...
```

**コンテナを作成**

* youki createで作成
* -bオプションでバンドルするファイルシステムを指定する
* 名前がtutorial_containerのコンテナを作成する

```
./youki create -b tutorial tutorial_container 
```

コンテナ作成後namespaceを確認します
PIDが124891のnamespaceが作成されていることがわかります。

```
lsns -o NS,TYPE,PATH,NPROCS,PID,PPID,COMMAND,UID,USER
        NS TYPE   PATH                   NPROCS    PID PPID COMMAND                                         UID USER
4026531834 time   /proc/1/ns/time           113      1    0 /sbin/init                                        0 root
4026531835 cgroup /proc/1/ns/cgroup         112      1    0 /sbin/init                                        0 root
4026531836 pid    /proc/1/ns/pid            112      1    0 /sbin/init                                        0 root
4026531837 user   /proc/1/ns/user           113      1    0 /sbin/init                                        0 root
4026531838 uts    /proc/1/ns/uts            106      1    0 /sbin/init                                        0 root
4026531839 ipc    /proc/1/ns/ipc            112      1    0 /sbin/init                                        0 root
4026531840 net    /proc/1/ns/net            112      1    0 /sbin/init                                        0 root
4026531841 mnt    /proc/1/ns/mnt            102      1    0 /sbin/init                                        0 root
4026532172 mnt    /proc/189/ns/mnt            1    189    1 ├─/usr/lib/systemd/systemd-udevd                  0 root
4026532173 uts    /proc/189/ns/uts            1    189    1 ├─/usr/lib/systemd/systemd-udevd                  0 root
4026532193 mnt    /proc/332/ns/mnt            1    332    1 ├─/usr/lib/systemd/systemd-resolved             991 systemd-resolve
4026532202 mnt    /proc/474/ns/mnt            1    474    1 ├─/usr/lib/systemd/systemd-networkd             998 systemd-network
4026532215 mnt    /proc/684/ns/mnt            2    684    1 ├─/usr/sbin/chronyd -F 1                        110 _chrony
4026532216 mnt    /proc/22353/ns/mnt          1  22353    1 ├─/usr/lib/polkit-1/polkitd --no-debug          989 polkitd
4026532217 uts    /proc/586/ns/uts            1    586    1 ├─/usr/lib/systemd/systemd-logind                 0 root
4026532218 uts    /proc/684/ns/uts            2    684    1 ├─/usr/sbin/chronyd -F 1                        110 _chrony
4026532221 pid    /proc/124891/ns/pid         1 124891    1 ├─./youki create -b tutorial tutorial_container   0 root
4026532222 uts    /proc/124891/ns/uts         1 124891    1 ├─./youki create -b tutorial tutorial_container   0 root
4026532223 ipc    /proc/124891/ns/ipc         1 124891    1 ├─./youki create -b tutorial tutorial_container   0 root
4026532224 net    /proc/124891/ns/net         1 124891    1 ├─./youki create -b tutorial tutorial_container   0 root
4026532272 mnt    /proc/586/ns/mnt            1    586    1 ├─/usr/lib/systemd/systemd-logind                 0 root
4026532273 mnt    /proc/3964/ns/mnt           1   3964    1 ├─/usr/sbin/irqbalance                            0 root
4026532274 uts    /proc/742/ns/uts            1    742    1 ├─/usr/sbin/rsyslogd -n -iNONE                  102 syslog
4026532280 uts    /proc/22353/ns/uts          1  22353    1 ├─/usr/lib/polkit-1/polkitd --no-debug          989 polkitd
4026532287 cgroup /proc/124891/ns/cgroup      1 124891    1 ├─./youki create -b tutorial tutorial_container   0 root
4026532288 mnt    /proc/22365/ns/mnt          1  22365    1 ├─/usr/sbin/ModemManager                          0 root
4026532289 mnt    /proc/124891/ns/mnt         1 124891    1 └─./youki create -b tutorial tutorial_container   0 root
4026531862 mnt    /proc/26/ns/mnt             1     26    2 kdevtmpfs                                         0 root
```


cgroupも:youki:tutorial_containerが作成されていることが確認できます

```
CGroup /:
-.slice
├─:youki:tutorial_container
│ └─124891 ./youki create -b tutorial tutorial_container
├─user.slice
│ └─user-0.slice
│   ├─session-c13.scope
│   │ ├─124828 su
│   │ ├─124845 bash
│   │ ├─124894 systemd-cgls
│   │ └─124895 pager
│   └─user@0.service …
│     └─init.scope
│       ├─124831 /usr/lib/systemd/systemd --user
│       └─124833 (sd-pam)
├─init.scope
│ └─1 /sbin/init
└─system.slice
```

```
ls /sys/fs/cgroup/:youki:tutorial_container
cgroup.controllers      cgroup.threads  cpu.weight                       hugetlb.1GB.events        hugetlb.2MB.numa_stat     memory.events.local  memory.stat             pids.events
cgroup.events           cgroup.type     cpu.weight.nice                  hugetlb.1GB.events.local  hugetlb.2MB.rsvd.current  memory.high          memory.swap.current     pids.max
cgroup.freeze           cpu.idle        cpuset.cpus                      hugetlb.1GB.max           hugetlb.2MB.rsvd.max      memory.low           memory.swap.events      pids.peak
cgroup.kill             cpu.max         cpuset.cpus.effective            hugetlb.1GB.numa_stat     io.max                    memory.max           memory.swap.high
cgroup.max.depth        cpu.max.burst   cpuset.cpus.exclusive            hugetlb.1GB.rsvd.current  io.pressure               memory.min           memory.swap.max
cgroup.max.descendants  cpu.pressure    cpuset.cpus.exclusive.effective  hugetlb.1GB.rsvd.max      io.prio.class             memory.numa_stat     memory.swap.peak
cgroup.pressure         cpu.stat        cpuset.cpus.partition            hugetlb.2MB.current       io.stat                   memory.oom.group     memory.zswap.current
cgroup.procs            cpu.stat.local  cpuset.mems                      hugetlb.2MB.events        io.weight                 memory.peak          memory.zswap.max
cgroup.stat             cpu.uclamp.max  cpuset.mems.effective            hugetlb.2MB.events.local  memory.current            memory.pressure      memory.zswap.writeback
cgroup.subtree_control  cpu.uclamp.min  hugetlb.1GB.current              hugetlb.2MB.max           memory.events             memory.reclaim       pids.current
```

コンテナを起動します
```
 ./youki start tutorial_container 
```

作成されたnamespaceに入ってコマンドを実行する
プロセスが隔離されて実行されていることが確認できます
```
PID=124921
nsenter --target $PID --uts --mount --ipc --net --pid /bin/sh
```

```
/ # ps -ef
PID   USER     TIME  COMMAND
    1 root      0:00 sleep 300
    2 root      0:00 /bin/sh
    3 root      0:00 ps -ef
```

## まとめ

コンテナランタイムについて簡単に紹介し、youkiを実際に動かしてみました。
他にも色々config.jsonの値を変えてみて、試してみると面白いと思います。