Slide 1

Slide 1 text

詳解 bypass4netns Rootless Containers Network の仕組みと高速化 Container Runtime Meetup #6 (2024/12/16) 京都大学大学院情報学研究科 松本直樹(@PiBVT) 1

Slide 2

Slide 2 text

自己紹介 京都大学大学院情報学研究科 博士後期課程2年生 • 岡部研究室(通信情報システムコース情報通信基盤講座 高機能ネットワーク分野) 所属 • 主な出版物(コンテナ関連) • bypass4netns: Accelerating TCP/IP Communications in Rootless Containers, AINTEC 2024, August 2024 • Repository: https://github.com/rootless-containers/bypass4netns • Slide: https://bit.ly/3ZFCBJ7 Paper: https://dl.acm.org/doi/10.1145/3674213.3674221 • Efficient Container Image Updating in Low-bandwidth Networks with Delta Encoding, IC2E 2023, September 2023 • Slide: https://bit.ly/3DebM60 Repository: https://github.com/naoki9911/d4c 細々とした開発も • “Mewz (WebAssembly x Unikernel) を libkrun で動かしてみた” https://pibvt.hateblo.jp/entry/2024/02/24/215710 2 本日の発表内容 スライド: https://bit.ly/4ggWb4z

Slide 3

Slide 3 text

Rootless Containers について 通常のランタイム(Rootful Containers) は特権で動く = ランタイムが弱点になりうる CVE-2024-21626(runc における /sys/fs/cgroup の fd リーク) など Rootless Containers: ランタイム全体も一般ユーザーの権限(非特権)で動かす → ランタイムが破られても被害の範囲は一般権限に抑えられる 3 プロセス Container Runtime プロセス Container Runtime 一般 ユーザー Root Rootful Containers Rootless Containers スライド: https://bit.ly/4ggWb4z

Slide 4

Slide 4 text

Rootless Containers について 通常のランタイム(Rootful Containers) は特権で動く = ランタイムが弱点になりうる CVE-2024-21626(runc における /sys/fs/cgroup の fd リーク) など Rootless Containers: ランタイム全体も一般ユーザーの権限(非特権)で動かす → ランタイムが破られても被害の範囲は一般権限に抑えられる 3 プロセス Container Runtime 脆弱性! プロセス Container Runtime 一般 ユーザー Root Rootful Containers Rootless Containers スライド: https://bit.ly/4ggWb4z

Slide 5

Slide 5 text

Rootless Containers について 通常のランタイム(Rootful Containers) は特権で動く = ランタイムが弱点になりうる CVE-2024-21626(runc における /sys/fs/cgroup の fd リーク) など Rootless Containers: ランタイム全体も一般ユーザーの権限(非特権)で動かす → ランタイムが破られても被害の範囲は一般権限に抑えられる 3 プロセス Container Runtime 脆弱性! 攻撃 プロセス プロセス Container Runtime 一般 ユーザー Root Rootful Containers Rootless Containers スライド: https://bit.ly/4ggWb4z

Slide 6

Slide 6 text

Rootless Containers について 通常のランタイム(Rootful Containers) は特権で動く = ランタイムが弱点になりうる CVE-2024-21626(runc における /sys/fs/cgroup の fd リーク) など Rootless Containers: ランタイム全体も一般ユーザーの権限(非特権)で動かす → ランタイムが破られても被害の範囲は一般権限に抑えられる 3 プロセス Container Runtime Root 権限で 不正な操作が可能 脆弱性! 攻撃 プロセス プロセス Container Runtime 一般 ユーザー Root Rootful Containers Rootless Containers スライド: https://bit.ly/4ggWb4z

Slide 7

Slide 7 text

Rootless Containers について 通常のランタイム(Rootful Containers) は特権で動く = ランタイムが弱点になりうる CVE-2024-21626(runc における /sys/fs/cgroup の fd リーク) など Rootless Containers: ランタイム全体も一般ユーザーの権限(非特権)で動かす → ランタイムが破られても被害の範囲は一般権限に抑えられる 3 プロセス Container Runtime Root 権限で 不正な操作が可能 脆弱性! 攻撃 プロセス プロセス Container Runtime 脆弱性! 一般 ユーザー Root Rootful Containers Rootless Containers スライド: https://bit.ly/4ggWb4z

Slide 8

Slide 8 text

Rootless Containers について 通常のランタイム(Rootful Containers) は特権で動く = ランタイムが弱点になりうる CVE-2024-21626(runc における /sys/fs/cgroup の fd リーク) など Rootless Containers: ランタイム全体も一般ユーザーの権限(非特権)で動かす → ランタイムが破られても被害の範囲は一般権限に抑えられる 3 プロセス Container Runtime Root 権限で 不正な操作が可能 脆弱性! 攻撃 プロセス プロセス Container Runtime 脆弱性! 攻撃 プロセス 一般 ユーザー Root Rootful Containers Rootless Containers スライド: https://bit.ly/4ggWb4z

Slide 9

Slide 9 text

Rootless Containers について 通常のランタイム(Rootful Containers) は特権で動く = ランタイムが弱点になりうる CVE-2024-21626(runc における /sys/fs/cgroup の fd リーク) など Rootless Containers: ランタイム全体も一般ユーザーの権限(非特権)で動かす → ランタイムが破られても被害の範囲は一般権限に抑えられる 3 プロセス Container Runtime Root 権限で 不正な操作が可能 脆弱性! 攻撃 プロセス プロセス Container Runtime 不正な操作は 一般ユーザー権限に制限 脆弱性! 攻撃 プロセス 一般 ユーザー Root Rootful Containers Rootless Containers スライド: https://bit.ly/4ggWb4z

Slide 10

Slide 10 text

Rootless Containers を実現する技術 user_namespaces(7) (UserNS) 擬似的な root (UID=0) を持つユーザー空間を作る → Root が必要な操作の大部分が動く(ホスト視点では一般ユーザーで動く) UserNS の詳細については以下の資料を参考 • コンテナ仮想、その裏側 〜user namespaceとrootlessコンテナ〜 https://tech.retrieva.jp/entry/2019/06/04/130134 • 次のコンテナセキュリティの時代 – User Namespace With a Pod https://speakerdeck.com/pfn/cloudnative-days-2024-usernamespace-with-a-pod 4 スライド: https://bit.ly/4ggWb4z

Slide 11

Slide 11 text

例外: NetNS 間の通信 network_namespaces(7)(NetNS) 間の通信は通常 veth(4) を用いる veth(4): Virtual Ethernet Device. NetNS 間を繋ぐ L2 トンネルデバイスの一種 通常の Rootful Containers ならば大体↓のようになる ホスト NetNS コンテナ NetNS a Bridge veth App veth コンテナ NetNS b veth veth App nerdctl0, docker0 など 5 スライド: https://bit.ly/4ggWb4z

Slide 12

Slide 12 text

NetNS 間の通信 veth IF を作るためには NetNS が紐づく UserNS について CAP_NET_ADMIN が必要 https://elixir.bootlin.com/linux/v6.12.2/ source/net/core/rtnetlink.c#L3485 https://elixir.bootlin.com/linux/v6.12.2/ source/net/core/rtnetlink.c#L2389 6 スライド: https://bit.ly/4ggWb4z

Slide 13

Slide 13 text

NetNS 間の通信 veth IF を作るためには NetNS が紐づく UserNS について CAP_NET_ADMIN が必要 → ホスト側の veth IF を作るためにホストの CAP_NET_ADMIN が必要 https://elixir.bootlin.com/linux/v6.12.2/ source/net/core/rtnetlink.c#L3485 https://elixir.bootlin.com/linux/v6.12.2/ source/net/core/rtnetlink.c#L2389 6 スライド: https://bit.ly/4ggWb4z

Slide 14

Slide 14 text

NetNS 間の通信 veth IF を作るためには NetNS が紐づく UserNS について CAP_NET_ADMIN が必要 → ホスト側の veth IF を作るためにホストの CAP_NET_ADMIN が必要 = そのままでは完全な Rootless は不可能 https://elixir.bootlin.com/linux/v6.12.2/ source/net/core/rtnetlink.c#L3485 https://elixir.bootlin.com/linux/v6.12.2/ source/net/core/rtnetlink.c#L2389 6 スライド: https://bit.ly/4ggWb4z

Slide 15

Slide 15 text

UserNS と NetNS の関係 新しい UserNS に紐づく NetNS を作れば veth IF を作れる 7 https://elixir.bootlin.com/linux/v6.12.2/source/include/net/net_namespace.h#L88 スライド: https://bit.ly/4ggWb4z

Slide 16

Slide 16 text

類似事例: lxc-user-nic Unprivileged LXC Containers では “lxc-user-nic” を用いて veth IF を作成 lxc-user-nic のバイナリが SUID を持つため、一般ユーザも root(EUID=0) として実行可能 8 スライド: https://bit.ly/4ggWb4z

Slide 17

Slide 17 text

類似事例: lxc-user-nic Unprivileged LXC Containers では “lxc-user-nic” を用いて veth IF を作成 lxc-user-nic のバイナリが SUID を持つため、一般ユーザも root(EUID=0) として実行可能 → バイナリが高い権限で動くことになるため弱点になりうる 8 スライド: https://bit.ly/4ggWb4z

Slide 18

Slide 18 text

類似事例: lxc-user-nic Unprivileged LXC Containers では “lxc-user-nic” を用いて veth IF を作成 lxc-user-nic のバイナリが SUID を持つため、一般ユーザも root(EUID=0) として実行可能 → バイナリが高い権限で動くことになるため弱点になりうる • CVE-2017-5985 • 任意のユーザーに対してホスト上に任意の名前の IF 作成を許してしまう可能性 → 実在のインタフェースに取って代わられる可能性 8 スライド: https://bit.ly/4ggWb4z

Slide 19

Slide 19 text

類似事例: lxc-user-nic Unprivileged LXC Containers では “lxc-user-nic” を用いて veth IF を作成 lxc-user-nic のバイナリが SUID を持つため、一般ユーザも root(EUID=0) として実行可能 → バイナリが高い権限で動くことになるため弱点になりうる • CVE-2017-5985 • 任意のユーザーに対してホスト上に任意の名前の IF 作成を許してしまう可能性 → 実在のインタフェースに取って代わられる可能性 • CVE-2018-6556 • ユーザーが与えたパスを開いてしまう可能性 → sys や proc 配下ファイルの場合何かしらの影響を及ぼすことが可能になる 8 スライド: https://bit.ly/4ggWb4z

Slide 20

Slide 20 text

類似事例: lxc-user-nic Unprivileged LXC Containers では “lxc-user-nic” を用いて veth IF を作成 lxc-user-nic のバイナリが SUID を持つため、一般ユーザも root(EUID=0) として実行可能 → バイナリが高い権限で動くことになるため弱点になりうる • CVE-2017-5985 • 任意のユーザーに対してホスト上に任意の名前の IF 作成を許してしまう可能性 → 実在のインタフェースに取って代わられる可能性 • CVE-2018-6556 • ユーザーが与えたパスを開いてしまう可能性 → sys や proc 配下ファイルの場合何かしらの影響を及ぼすことが可能になる Rootless Containers では SUID なバイナリを可能な限り排除しリスクを低減 8 スライド: https://bit.ly/4ggWb4z

Slide 21

Slide 21 text

Rootless Containers Network 対外通信を veth なしで実現 → slirp4netns, RootlessKit port driver による通信の中継 ※ コンテナ間通信は Rootful Containers と同様に veth + bridge で行う https://github.com/containerd/nerdctl/blob/41b83493e1e41b8a76db25f2dbfb5046edf685ee/docs/images/rootlessKit-network-design.png 9 スライド: https://bit.ly/4ggWb4z

Slide 22

Slide 22 text

Rootless Containers Network 新たに作成した UserNS と NetNS(Detach NetNS) 内にコンテナネットワークを構築する 10 RootlessKit (Parent) ホスト UserNS 新 UserNS ホスト NetNS スライド: https://bit.ly/4ggWb4z

Slide 23

Slide 23 text

Rootless Containers Network 新たに作成した UserNS と NetNS(Detach NetNS) 内にコンテナネットワークを構築する 10 RootlessKit (Parent) ホスト UserNS 新 UserNS https://github.com/rootless-containers/rootlesskit/blob/9c9049ac786483cccc59b25b8454d652669927b1/pkg/parent/parent.go#L176 ホスト NetNS スライド: https://bit.ly/4ggWb4z

Slide 24

Slide 24 text

Rootless Containers Network 新たに作成した UserNS と NetNS(Detach NetNS) 内にコンテナネットワークを構築する 10 RootlessKit (Parent) ホスト UserNS 新 UserNS https://github.com/rootless-containers/rootlesskit/blob/9c9049ac786483cccc59b25b8454d652669927b1/pkg/parent/parent.go#L176 RootlessKit (Child) ホスト NetNS Detach NetNS スライド: https://bit.ly/4ggWb4z

Slide 25

Slide 25 text

Rootless Containers Network 新たに作成した UserNS と NetNS(Detach NetNS) 内にコンテナネットワークを構築する 10 RootlessKit (Parent) ホスト UserNS 新 UserNS https://github.com/rootless-containers/rootlesskit/blob/9c9049ac786483cccc59b25b8454d652669927b1/pkg/parent/parent.go#L176 RootlessKit (Child) ホスト NetNS Detach NetNS slirp4netns スライド: https://bit.ly/4ggWb4z

Slide 26

Slide 26 text

Rootless Containers Network 新たに作成した UserNS と NetNS(Detach NetNS) 内にコンテナネットワークを構築する 10 RootlessKit (Parent) ホスト UserNS 新 UserNS https://github.com/rootless-containers/rootlesskit/blob/9c9049ac786483cccc59b25b8454d652669927b1/pkg/parent/parent.go#L176 RootlessKit (Child) ホスト NetNS Detach NetNS slirp4netns containerd スライド: https://bit.ly/4ggWb4z

Slide 27

Slide 27 text

Rootless Containers Network 新たに作成した UserNS と NetNS(Detach NetNS) 内にコンテナネットワークを構築する 10 RootlessKit (Parent) ホスト UserNS 新 UserNS https://github.com/rootless-containers/rootlesskit/blob/9c9049ac786483cccc59b25b8454d652669927b1/pkg/parent/parent.go#L176 RootlessKit (Child) ホスト NetNS Detach NetNS slirp4netns containerd Bridge スライド: https://bit.ly/4ggWb4z

Slide 28

Slide 28 text

Rootless Containers Network 新たに作成した UserNS と NetNS(Detach NetNS) 内にコンテナネットワークを構築する 10 RootlessKit (Parent) ホスト UserNS 新 UserNS https://github.com/rootless-containers/rootlesskit/blob/9c9049ac786483cccc59b25b8454d652669927b1/pkg/parent/parent.go#L176 RootlessKit (Child) ホスト NetNS Detach NetNS slirp4netns containerd containerd- shim-runc-v2 Container NetNS Bridge veth veth runc /bin/sh スライド: https://bit.ly/4ggWb4z

Slide 29

Slide 29 text

slirp4netns について libslirp を用いた NetNS 間通信を完全 Rootless で実現するライブラリ ※ libslirp: TCP/IP の処理を行うユーザーライブラリ。QEMU 等でも利用されている https://gitlab.freedesktop.org/slirp/libslirp Detach NetNS 内に作成した TAP デバイスとホスト NetNS 上のソケット間のメッセージを交換 • Detach NetNS と Container NetNS は一般ユーザーの UserNS に属し、veth IF を作れる • ホスト上の slirp4netns は Detach NetNS 内に TAP デバイスを作成しパケットを送受信 Bridge Detach NetNS veth App veth Container NetNS TAP slirp4netns Socket A https://github.com/rootless-containers/slirp4netns 11 スライド: https://bit.ly/4ggWb4z

Slide 30

Slide 30 text

slirp4netns について libslirp を用いた NetNS 間通信を完全 Rootless で実現するライブラリ ※ libslirp: TCP/IP の処理を行うユーザーライブラリ。QEMU 等でも利用されている https://gitlab.freedesktop.org/slirp/libslirp Detach NetNS 内に作成した TAP デバイスとホスト NetNS 上のソケット間のメッセージを交換 • Detach NetNS と Container NetNS は一般ユーザーの UserNS に属し、veth IF を作れる • ホスト上の slirp4netns は Detach NetNS 内に TAP デバイスを作成しパケットを送受信 Bridge Detach NetNS veth App veth Container NetNS TAP slirp4netns Socket A https://github.com/rootless-containers/slirp4netns 11 スライド: https://bit.ly/4ggWb4z

Slide 31

Slide 31 text

slirp4netns について libslirp を用いた NetNS 間通信を完全 Rootless で実現するライブラリ ※ libslirp: TCP/IP の処理を行うユーザーライブラリ。QEMU 等でも利用されている https://gitlab.freedesktop.org/slirp/libslirp Detach NetNS 内に作成した TAP デバイスとホスト NetNS 上のソケット間のメッセージを交換 • Detach NetNS と Container NetNS は一般ユーザーの UserNS に属し、veth IF を作れる • ホスト上の slirp4netns は Detach NetNS 内に TAP デバイスを作成しパケットを送受信 Bridge Detach NetNS veth App veth Container NetNS TAP slirp4netns Socket A ヘッダ TCP ペイロード https://github.com/rootless-containers/slirp4netns 11 スライド: https://bit.ly/4ggWb4z

Slide 32

Slide 32 text

slirp4netns について libslirp を用いた NetNS 間通信を完全 Rootless で実現するライブラリ ※ libslirp: TCP/IP の処理を行うユーザーライブラリ。QEMU 等でも利用されている https://gitlab.freedesktop.org/slirp/libslirp Detach NetNS 内に作成した TAP デバイスとホスト NetNS 上のソケット間のメッセージを交換 • Detach NetNS と Container NetNS は一般ユーザーの UserNS に属し、veth IF を作れる • ホスト上の slirp4netns は Detach NetNS 内に TAP デバイスを作成しパケットを送受信 Bridge Detach NetNS veth App veth Container NetNS TAP slirp4netns Socket A ヘッダ TCP ペイロード メッセージ ペイロードを取り出しソケットから send https://github.com/rootless-containers/slirp4netns 11 スライド: https://bit.ly/4ggWb4z

Slide 33

Slide 33 text

slirp4netns について libslirp を用いた NetNS 間通信を完全 Rootless で実現するライブラリ ※ libslirp: TCP/IP の処理を行うユーザーライブラリ。QEMU 等でも利用されている https://gitlab.freedesktop.org/slirp/libslirp Detach NetNS 内に作成した TAP デバイスとホスト NetNS 上のソケット間のメッセージを交換 • Detach NetNS と Container NetNS は一般ユーザーの UserNS に属し、veth IF を作れる • ホスト上の slirp4netns は Detach NetNS 内に TAP デバイスを作成しパケットを送受信 Bridge Detach NetNS veth App veth Container NetNS TAP slirp4netns Socket A ヘッダ TCP ペイロード メッセージ ペイロードを取り出しソケットから send https://github.com/rootless-containers/slirp4netns 11 スライド: https://bit.ly/4ggWb4z

Slide 34

Slide 34 text

slirp4netns について libslirp を用いた NetNS 間通信を完全 Rootless で実現するライブラリ ※ libslirp: TCP/IP の処理を行うユーザーライブラリ。QEMU 等でも利用されている https://gitlab.freedesktop.org/slirp/libslirp Detach NetNS 内に作成した TAP デバイスとホスト NetNS 上のソケット間のメッセージを交換 • Detach NetNS と Container NetNS は一般ユーザーの UserNS に属し、veth IF を作れる • ホスト上の slirp4netns は Detach NetNS 内に TAP デバイスを作成しパケットを送受信 Bridge Detach NetNS veth App veth Container NetNS TAP slirp4netns Socket A ヘッダ TCP ペイロード メッセージ ペイロードを取り出しソケットから send メッセージ https://github.com/rootless-containers/slirp4netns 11 スライド: https://bit.ly/4ggWb4z

Slide 35

Slide 35 text

slirp4netns について libslirp を用いた NetNS 間通信を完全 Rootless で実現するライブラリ ※ libslirp: TCP/IP の処理を行うユーザーライブラリ。QEMU 等でも利用されている https://gitlab.freedesktop.org/slirp/libslirp Detach NetNS 内に作成した TAP デバイスとホスト NetNS 上のソケット間のメッセージを交換 • Detach NetNS と Container NetNS は一般ユーザーの UserNS に属し、veth IF を作れる • ホスト上の slirp4netns は Detach NetNS 内に TAP デバイスを作成しパケットを送受信 Bridge Detach NetNS veth App veth Container NetNS TAP slirp4netns Socket A ヘッダ TCP ペイロード メッセージ ペイロードを取り出しソケットから send ヘッダ TCP ペイロード メッセージ メッセージから TCP パケットを構築し TAP から send https://github.com/rootless-containers/slirp4netns 11 スライド: https://bit.ly/4ggWb4z

Slide 36

Slide 36 text

RootlessKit port driver について Rootless Containers の機能を提供するRootlessKit のポート公開機能 https://github.com/rootless-containers/rootlesskit/tree/master/pkg/port/builtin “--publish” で公開されたポートに対する接続をコンテナに対して中継する 例) --publish 8080:80/tcp の場合 https://github.com/rootless-containers/rootlesskit RootlessKit (Parent) RootlessKit (Child) Bridge veth App veth Detach NetNS Container NetNS 12 スライド: https://bit.ly/4ggWb4z

Slide 37

Slide 37 text

RootlessKit port driver について Rootless Containers の機能を提供するRootlessKit のポート公開機能 https://github.com/rootless-containers/rootlesskit/tree/master/pkg/port/builtin “--publish” で公開されたポートに対する接続をコンテナに対して中継する 例) --publish 8080:80/tcp の場合 https://github.com/rootless-containers/rootlesskit RootlessKit (Parent) RootlessKit (Child) Bridge veth App veth 1. 8080/tcp で待ち受け Detach NetNS Container NetNS 12 スライド: https://bit.ly/4ggWb4z

Slide 38

Slide 38 text

RootlessKit port driver について Rootless Containers の機能を提供するRootlessKit のポート公開機能 https://github.com/rootless-containers/rootlesskit/tree/master/pkg/port/builtin “--publish” で公開されたポートに対する接続をコンテナに対して中継する 例) --publish 8080:80/tcp の場合 https://github.com/rootless-containers/rootlesskit RootlessKit (Parent) RootlessKit (Child) Bridge veth App veth 1. 8080/tcp で待ち受け Detach NetNS Container NetNS 12 スライド: https://bit.ly/4ggWb4z

Slide 39

Slide 39 text

RootlessKit port driver について Rootless Containers の機能を提供するRootlessKit のポート公開機能 https://github.com/rootless-containers/rootlesskit/tree/master/pkg/port/builtin “--publish” で公開されたポートに対する接続をコンテナに対して中継する 例) --publish 8080:80/tcp の場合 https://github.com/rootless-containers/rootlesskit RootlessKit (Parent) RootlessKit (Child) Bridge veth App veth 1. 8080/tcp で待ち受け Detach NetNS Container NetNS 2. accept sock 12 スライド: https://bit.ly/4ggWb4z

Slide 40

Slide 40 text

RootlessKit port driver について Rootless Containers の機能を提供するRootlessKit のポート公開機能 https://github.com/rootless-containers/rootlesskit/tree/master/pkg/port/builtin “--publish” で公開されたポートに対する接続をコンテナに対して中継する 例) --publish 8080:80/tcp の場合 https://github.com/rootless-containers/rootlesskit RootlessKit (Parent) RootlessKit (Child) Bridge veth App veth 1. 8080/tcp で待ち受け sock Detach NetNS Container NetNS 2. accept sock 3. コンテナへ接続 12 スライド: https://bit.ly/4ggWb4z

Slide 41

Slide 41 text

RootlessKit port driver について Rootless Containers の機能を提供するRootlessKit のポート公開機能 https://github.com/rootless-containers/rootlesskit/tree/master/pkg/port/builtin “--publish” で公開されたポートに対する接続をコンテナに対して中継する 例) --publish 8080:80/tcp の場合 https://github.com/rootless-containers/rootlesskit RootlessKit (Parent) RootlessKit (Child) Bridge veth App veth 1. 8080/tcp で待ち受け sock Detach NetNS Container NetNS 2. accept sock 3. コンテナへ接続 4. fd 間でコピー 12 スライド: https://bit.ly/4ggWb4z

Slide 42

Slide 42 text

実際の構造(全体) nerdctl run -it --rm -p 8080:80 alpine で nc を実行 RootlessKit (Parent) RootlessKit (Child) slirp4netns containerd ホスト UserNS 新 UserNS ホスト NetNS Detach NetNS containerd- shim-runc-v2 nc -l - p 80 Container NetNS 8080/tcp で Listen nc 外部endpoint 13 スライド: https://bit.ly/4ggWb4z

Slide 43

Slide 43 text

実際の構造(slirp4netns 周り) slirp4netns ホスト NetNS Detach NetNS Container NetNS nc 外部endpoint iptables (CNI) 10.0.2.100/24 10.4.0.1/24 default via 10.0.2.2 dev tap0 Masquerade (NAT) Bridge veth TAP veth 14 スライド: https://bit.ly/4ggWb4z

Slide 44

Slide 44 text

実際の構造(slirp4netns 周り) slirp4netns ホスト NetNS Detach NetNS Container NetNS nc 外部endpoint iptables (CNI) 10.0.2.100/24 10.4.0.1/24 default via 10.0.2.2 dev tap0 Masquerade (NAT) Bridge veth TAP veth 14 veth IF 経由で 外部エンドポイントに接続 スライド: https://bit.ly/4ggWb4z

Slide 45

Slide 45 text

実際の構造(slirp4netns 周り) slirp4netns ホスト NetNS Detach NetNS Container NetNS nc 外部endpoint iptables (CNI) 10.0.2.100/24 10.4.0.1/24 default via 10.0.2.2 dev tap0 Masquerade (NAT) Bridge veth TAP veth 接続を終端 14 veth IF 経由で 外部エンドポイントに接続 スライド: https://bit.ly/4ggWb4z

Slide 46

Slide 46 text

実際の構造(slirp4netns 周り) slirp4netns ホスト NetNS Detach NetNS Container NetNS nc 外部endpoint iptables (CNI) 10.0.2.100/24 10.4.0.1/24 default via 10.0.2.2 dev tap0 Masquerade (NAT) Bridge veth TAP veth 接続を終端 so ck ソケット を作成し接続 14 veth IF 経由で 外部エンドポイントに接続 スライド: https://bit.ly/4ggWb4z

Slide 47

Slide 47 text

実際の構造(slirp4netns 周り) slirp4netns ホスト NetNS Detach NetNS Container NetNS nc 外部endpoint iptables (CNI) 10.0.2.100/24 10.4.0.1/24 default via 10.0.2.2 dev tap0 Masquerade (NAT) Bridge veth TAP veth 接続を終端 so ck ソケット を作成し接続 14 veth IF 経由で 外部エンドポイントに接続 スライド: https://bit.ly/4ggWb4z

Slide 48

Slide 48 text

実際の構造(port driver 周り) RootlessKit(Parent) が接続を終端し Child が接続、fd 間コピーで中継 RootlessKit (Parent) ホスト NetNS Detach NetNS Container NetNS nc -l -p 80 iptables (CNI) DNAT so ck RootlessKit (Child) Bridge veth veth 10.4.0.1/24 15 スライド: https://bit.ly/4ggWb4z

Slide 49

Slide 49 text

実際の構造(port driver 周り) RootlessKit(Parent) が接続を終端し Child が接続、fd 間コピーで中継 RootlessKit (Parent) ホスト NetNS Detach NetNS Container NetNS nc -l -p 80 iptables (CNI) DNAT 接続を終端 so ck RootlessKit (Child) Bridge veth veth 10.4.0.1/24 15 スライド: https://bit.ly/4ggWb4z

Slide 50

Slide 50 text

実際の構造(port driver 周り) RootlessKit(Parent) が接続を終端し Child が接続、fd 間コピーで中継 RootlessKit (Parent) ホスト NetNS Detach NetNS Container NetNS nc -l -p 80 iptables (CNI) DNAT 接続を終端 so ck ソケット を作成し接続 RootlessKit (Child) sock Bridge veth veth 10.4.0.1/24 15 スライド: https://bit.ly/4ggWb4z

Slide 51

Slide 51 text

実際の構造(port driver 周り) RootlessKit(Parent) が接続を終端し Child が接続、fd 間コピーで中継 RootlessKit (Parent) ホスト NetNS Detach NetNS Container NetNS nc -l -p 80 iptables (CNI) DNAT 接続を終端 so ck ソケット を作成し接続 RootlessKit (Child) sock Bridge veth veth 10.4.0.1/24 15 スライド: https://bit.ly/4ggWb4z

Slide 52

Slide 52 text

実際の構造(port driver 周り) RootlessKit(Parent) が接続を終端し Child が接続、fd 間コピーで中継 RootlessKit (Parent) ホスト NetNS Detach NetNS Container NetNS nc -l -p 80 iptables (CNI) DNAT 接続を終端 so ck ソケット を作成し接続 RootlessKit (Child) sock Bridge veth veth 10.4.0.1/24 15 スライド: https://bit.ly/4ggWb4z

Slide 53

Slide 53 text

Usernetes(Gen2) 須田瑛大 氏が開発している Rootless Kubernetes • Rootless コンテナ内部で Pod 等を立ち上げて動かす • Rootless な kubelet (“KubeletInUserNamespace”) を利用 参考: Usernetes Gen2 - Kubernetes in Rootless Docker, with Multiple Nodes https://github.com/AkihiroSuda/AkihiroSuda/blob/master/slides/2024/20240415%20%5BContainer%20Plumbing%20Days %5D%20Usernetes%20Gen2%20-%20Kubernetes%20in%20Rootless%20Docker%2C%20with%20Multiple%20Nodes.pdf Rootless コンテナ docker.io/kindest/node ベースの node Pod Pod kubelet 16 スライド: https://bit.ly/4ggWb4z

Slide 54

Slide 54 text

課題 17 スライド: https://bit.ly/4ggWb4z

Slide 55

Slide 55 text

課題 課題1: 性能劣化 • 特に外部エンドポイントに対する接続(slirp4netns 担当) が遅い • 論文上のベンチでは iperf3 で別ホストに対する接続時に 570 Mbps 程度 (ネイティブ比で1/30) • Usernetes(Gen2) においても異 Node 間通信が影響を受ける 17 スライド: https://bit.ly/4ggWb4z

Slide 56

Slide 56 text

課題 課題1: 性能劣化 • 特に外部エンドポイントに対する接続(slirp4netns 担当) が遅い • 論文上のベンチでは iperf3 で別ホストに対する接続時に 570 Mbps 程度 (ネイティブ比で1/30) • Usernetes(Gen2) においても異 Node 間通信が影響を受ける 課題2: 公開ポートへの接続元アドレスが分からない • 接続元アドレスは実際に接続する RootlessKit (child) になる • ログ上で意味のないアドレスしか得られない(例では 10.0.4.1) 17 スライド: https://bit.ly/4ggWb4z

Slide 57

Slide 57 text

bypass4netns bypass4netns は slirp4netns, RootlessKit を “bypass” する • コンテナ内のアプリケーションが持つソケットをホスト上のソケットにスイッチ • スイッチされたソケットは slirp4netns 等の影響を受けない → ホストとほぼ同等な性能で通信出来るようになる 18 ボトルネック をbypass! Detach NetNS スライド: https://bit.ly/4ggWb4z

Slide 58

Slide 58 text

Rootless Containers における要件 Rootless Containers は構成する要素について以下の要件を持つ 19 スライド: https://bit.ly/4ggWb4z

Slide 59

Slide 59 text

Rootless Containers における要件 Rootless Containers は構成する要素について以下の要件を持つ • 完全な Rootless SUID 付きのバイナリは脆弱性のリスクがある(例: lxc-user-nic) 19 スライド: https://bit.ly/4ggWb4z

Slide 60

Slide 60 text

Rootless Containers における要件 Rootless Containers は構成する要素について以下の要件を持つ • 完全な Rootless SUID 付きのバイナリは脆弱性のリスクがある(例: lxc-user-nic) • 専用のカーネルモジュール等は利用しない: カーネルにモジュールや追加機能を安全に実装することは難しい 使える環境が限定されメンテナンスコストもかかる 19 スライド: https://bit.ly/4ggWb4z

Slide 61

Slide 61 text

Rootless Containers における要件 Rootless Containers は構成する要素について以下の要件を持つ • 完全な Rootless SUID 付きのバイナリは脆弱性のリスクがある(例: lxc-user-nic) • 専用のカーネルモジュール等は利用しない: カーネルにモジュールや追加機能を安全に実装することは難しい 使える環境が限定されメンテナンスコストもかかる • アプリケーションは無改変で利用できる: Rootless Containers はこれまでの Rootful Containers と同じように使えるように開発 アプリケーションに対する改変やリビルド等の必要がないようにする必要がある 19 スライド: https://bit.ly/4ggWb4z

Slide 62

Slide 62 text

Seccomp Notify bypass4netns では “Seccomp Notify” を活用してその機能を実現 seccomp_unotify(2) (Seccomp Notify) : 動的に syscall をフィルタするための機構 “Supervisor process” が “Target process” が実行する syscall の実行可否を決定 20 参考: 非特権コンテナの可能性を広げるseccomp notify機能, https://gihyo.jp/admin/serial/01/linux_containers/0047 スライド: https://bit.ly/4ggWb4z

Slide 63

Slide 63 text

Seccomp Notify を用いたソケットのスイッチ Seccomp Notify は特殊なフラグ SECCOMP_IOCTL_NOTIF_ADDFD を提供 • fd が指す “file description(=socket)” を別の file description に切り替える • 動作としては dup(2) とほぼ同じ 21 Rootless Container Process syscall ソケットの fd bypass4netns ソケットスイッチ 機構 コンテナ内の ソケット Seccomp Notify 5.実行 スライド: https://bit.ly/4ggWb4z

Slide 64

Slide 64 text

Seccomp Notify を用いたソケットのスイッチ Seccomp Notify は特殊なフラグ SECCOMP_IOCTL_NOTIF_ADDFD を提供 • fd が指す “file description(=socket)” を別の file description に切り替える • 動作としては dup(2) とほぼ同じ 21 Rootless Container Process syscall ソケットの fd bypass4netns ソケットスイッチ 機構 コンテナ内の ソケット Seccomp Notify 5.実行 スライド: https://bit.ly/4ggWb4z

Slide 65

Slide 65 text

Seccomp Notify を用いたソケットのスイッチ Seccomp Notify は特殊なフラグ SECCOMP_IOCTL_NOTIF_ADDFD を提供 • fd が指す “file description(=socket)” を別の file description に切り替える • 動作としては dup(2) とほぼ同じ 21 Rootless Container Process syscall ソケットの fd bypass4netns ソケットスイッチ 機構 コンテナ内の ソケット Seccomp Notify 5.実行 1. 通知 スライド: https://bit.ly/4ggWb4z

Slide 66

Slide 66 text

Seccomp Notify を用いたソケットのスイッチ Seccomp Notify は特殊なフラグ SECCOMP_IOCTL_NOTIF_ADDFD を提供 • fd が指す “file description(=socket)” を別の file description に切り替える • 動作としては dup(2) とほぼ同じ 21 Rootless Container Process syscall ソケットの fd bypass4netns ソケットスイッチ 機構 コンテナ内の ソケット ホスト上のソケット Seccomp Notify 5.実行 1. 通知 2. ソケットを確保 スライド: https://bit.ly/4ggWb4z

Slide 67

Slide 67 text

Seccomp Notify を用いたソケットのスイッチ Seccomp Notify は特殊なフラグ SECCOMP_IOCTL_NOTIF_ADDFD を提供 • fd が指す “file description(=socket)” を別の file description に切り替える • 動作としては dup(2) とほぼ同じ 21 Rootless Container Process syscall ソケットの fd bypass4netns ソケットスイッチ 機構 コンテナ内の ソケット ホスト上のソケット Seccomp Notify 5.実行 1. 通知 2. ソケットを確保 3. 通知に対して返答 (SECCOMP_IOCTL_NOTIF_ADDFD) スライド: https://bit.ly/4ggWb4z

Slide 68

Slide 68 text

Seccomp Notify を用いたソケットのスイッチ Seccomp Notify は特殊なフラグ SECCOMP_IOCTL_NOTIF_ADDFD を提供 • fd が指す “file description(=socket)” を別の file description に切り替える • 動作としては dup(2) とほぼ同じ 21 Rootless Container Process syscall ソケットの fd bypass4netns ソケットスイッチ 機構 コンテナ内の ソケット ホスト上のソケット Seccomp Notify 5.実行 4. ソケットスイッチ 1. 通知 2. ソケットを確保 3. 通知に対して返答 (SECCOMP_IOCTL_NOTIF_ADDFD) スライド: https://bit.ly/4ggWb4z

Slide 69

Slide 69 text

動作例: 外部エンドポイントへの接続 bypass4netns は外部エンドポイントへ接続する場合ソケットのみスイッチを行う 外部エンドポイント: loopback や他のコンテナ以外のアドレス = slirp4netns 経由で通信するエンドポイント 22 memset((char *)&end_addr, 0, sizeof(end_addr)); end_addr.sin_family = AF_INET; end_addr.sin_port = htons(80); end_addr.sin_addr.s_addr = inet_addr(“192.168.2.1"); 接続先は外部のエンドポイント スライド: https://bit.ly/4ggWb4z

Slide 70

Slide 70 text

動作例: 外部エンドポイントへの接続 bypass4netns は外部エンドポイントへ接続する場合ソケットのみスイッチを行う 外部エンドポイント: loopback や他のコンテナ以外のアドレス = slirp4netns 経由で通信するエンドポイント 22 memset((char *)&end_addr, 0, sizeof(end_addr)); end_addr.sin_family = AF_INET; end_addr.sin_port = htons(80); end_addr.sin_addr.s_addr = inet_addr(“192.168.2.1"); sockfd = socket(AF_INET, SOCK_STREAM, 0); 接続先は外部のエンドポイント (1) Creation スライド: https://bit.ly/4ggWb4z

Slide 71

Slide 71 text

動作例: 外部エンドポイントへの接続 bypass4netns は外部エンドポイントへ接続する場合ソケットのみスイッチを行う 外部エンドポイント: loopback や他のコンテナ以外のアドレス = slirp4netns 経由で通信するエンドポイント 22 memset((char *)&end_addr, 0, sizeof(end_addr)); end_addr.sin_family = AF_INET; end_addr.sin_port = htons(80); end_addr.sin_addr.s_addr = inet_addr(“192.168.2.1"); sockfd = socket(AF_INET, SOCK_STREAM, 0); int buf_size = 4096; setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (void *)&buf_size, sizeof(int)); 接続先は外部のエンドポイント (1) Creation (2) Configuration スライド: https://bit.ly/4ggWb4z

Slide 72

Slide 72 text

動作例: 外部エンドポイントへの接続 bypass4netns は外部エンドポイントへ接続する場合ソケットのみスイッチを行う 外部エンドポイント: loopback や他のコンテナ以外のアドレス = slirp4netns 経由で通信するエンドポイント 22 memset((char *)&end_addr, 0, sizeof(end_addr)); end_addr.sin_family = AF_INET; end_addr.sin_port = htons(80); end_addr.sin_addr.s_addr = inet_addr(“192.168.2.1"); sockfd = socket(AF_INET, SOCK_STREAM, 0); int buf_size = 4096; setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (void *)&buf_size, sizeof(int)); connect(sockfd, (struct sockaddr *)&end_addr, sizeof(end_addr)); 接続先は外部のエンドポイント (1) Creation (2) Configuration (3) Connection スライド: https://bit.ly/4ggWb4z

Slide 73

Slide 73 text

動作例: 外部エンドポイントへの接続 bypass4netns は外部エンドポイントへ接続する場合ソケットのみスイッチを行う 外部エンドポイント: loopback や他のコンテナ以外のアドレス = slirp4netns 経由で通信するエンドポイント 22 memset((char *)&end_addr, 0, sizeof(end_addr)); end_addr.sin_family = AF_INET; end_addr.sin_port = htons(80); end_addr.sin_addr.s_addr = inet_addr(“192.168.2.1"); sockfd = socket(AF_INET, SOCK_STREAM, 0); int buf_size = 4096; setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (void *)&buf_size, sizeof(int)); connect(sockfd, (struct sockaddr *)&end_addr, sizeof(end_addr)); // “sockfd” はここで既にホスト上のソケットに切り替わっている 接続先は外部のエンドポイント (1) Creation (2) Configuration (3) Connection スライド: https://bit.ly/4ggWb4z

Slide 74

Slide 74 text

動作例: 外部エンドポイントへの接続 bypass4netns は外部エンドポイントへ接続する場合ソケットのみスイッチを行う 外部エンドポイント: loopback や他のコンテナ以外のアドレス = slirp4netns 経由で通信するエンドポイント 22 memset((char *)&end_addr, 0, sizeof(end_addr)); end_addr.sin_family = AF_INET; end_addr.sin_port = htons(80); end_addr.sin_addr.s_addr = inet_addr(“192.168.2.1"); sockfd = socket(AF_INET, SOCK_STREAM, 0); int buf_size = 4096; setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (void *)&buf_size, sizeof(int)); connect(sockfd, (struct sockaddr *)&end_addr, sizeof(end_addr)); // “sockfd” はここで既にホスト上のソケットに切り替わっている getpeername(sockfd, (struct sockaddr*)&peer_addr, &len); printf("peer: %s¥n", inet_ntoa(peer_addr.sin_addr)); 接続先は外部のエンドポイント (1) Creation (2) Configuration (3) Connection (4) Status スライド: https://bit.ly/4ggWb4z

Slide 75

Slide 75 text

動作例: 外部エンドポイントへの接続 bypass4netns は外部エンドポイントへ接続する場合ソケットのみスイッチを行う 外部エンドポイント: loopback や他のコンテナ以外のアドレス = slirp4netns 経由で通信するエンドポイント 22 memset((char *)&end_addr, 0, sizeof(end_addr)); end_addr.sin_family = AF_INET; end_addr.sin_port = htons(80); end_addr.sin_addr.s_addr = inet_addr(“192.168.2.1"); sockfd = socket(AF_INET, SOCK_STREAM, 0); int buf_size = 4096; setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (void *)&buf_size, sizeof(int)); connect(sockfd, (struct sockaddr *)&end_addr, sizeof(end_addr)); // “sockfd” はここで既にホスト上のソケットに切り替わっている getpeername(sockfd, (struct sockaddr*)&peer_addr, &len); printf("peer: %s¥n", inet_ntoa(peer_addr.sin_addr)); sprintf(buffer, "GET / HTTP/1.1¥r¥n¥r¥n"); send(sockfd, buffer, strlen(buffer), 0); 接続先は外部のエンドポイント (1) Creation (2) Configuration (3) Connection (4) Status Other syscalls スライド: https://bit.ly/4ggWb4z

Slide 76

Slide 76 text

動作例: 外部エンドポイントへの接続 bypass4netns は外部エンドポイントへ接続する場合ソケットのみスイッチを行う 外部エンドポイント: loopback や他のコンテナ以外のアドレス = slirp4netns 経由で通信するエンドポイント 22 memset((char *)&end_addr, 0, sizeof(end_addr)); end_addr.sin_family = AF_INET; end_addr.sin_port = htons(80); end_addr.sin_addr.s_addr = inet_addr(“192.168.2.1"); sockfd = socket(AF_INET, SOCK_STREAM, 0); int buf_size = 4096; setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (void *)&buf_size, sizeof(int)); connect(sockfd, (struct sockaddr *)&end_addr, sizeof(end_addr)); // “sockfd” はここで既にホスト上のソケットに切り替わっている getpeername(sockfd, (struct sockaddr*)&peer_addr, &len); printf("peer: %s¥n", inet_ntoa(peer_addr.sin_addr)); sprintf(buffer, "GET / HTTP/1.1¥r¥n¥r¥n"); send(sockfd, buffer, strlen(buffer), 0); close(sockfd); 接続先は外部のエンドポイント (1) Creation (2) Configuration (3) Connection (4) Status Other syscalls (7) Close スライド: https://bit.ly/4ggWb4z

Slide 77

Slide 77 text

アプリの互換性 右表に記載のアプリケーションに対して動作するか確認 検証結果としては • 一部(下記)のアプリを除き正常に動作 → bypass4netns のスイッチ機構がおよそ正しく動くことを確認 • 静的リンクされたアプリについても動作 → LD_PRELOAD で対応できないアプリについても対応可能なことを確認 動作しない例 • Seccomp Notify が syscall をドロップする (Go 1.21.3 HTTP Client 試験時) → goroutine で HTTP Client を2個以上動作させると発現する場合がある 23

Slide 78

Slide 78 text

性能評価 3種類のネットワークで性能を測定 • rootful-pfd: Rootful container, iptables 経由のポート公開 • rootless-pfd: Rootless container, RootlessKit 経由のポート公開 • b4ns-pfd: Rootless container, bypass4netns 経由のポート公開 評価環境: VM をクライアント・サーバー用に2台使用, それぞれでコンテナを稼働 • CPU: AMD EPYC 7452 (2.35GHz base clock, 8 vCPU 割当) • Memory: 16GB • OS: Ubuntu 22.04 24 Rootful, Rootless コンテナ (server) VM VM Rootful, Rootless コンテナ (client) Bridge スライド: https://bit.ly/4ggWb4z

Slide 79

Slide 79 text

性能評価: iperf3 いずれの場合についても bypass4netns を利用した場合が最も高い性能を達成 • b4ns-pfd ではrootless-pfd (570Mbps)と比べて30倍の高速化 (19.7 Gbps) • rootful-pfd (17.9 Gbps) よりも高速 → b4ns-pfd では bridge や iptables などがバイパスされたことで高速化 25 スライド: https://bit.ly/4ggWb4z

Slide 80

Slide 80 text

性能評価: Redis redis-benchmark を用いて Redis の性能を評価 • b4ns-pfd で rootless-pfd と比較して約2倍高い性能を達成 • Rootful に比べて Rootless w/ bypass4netns の方が高い性能を達成 → おそらく iperf3 と同様の理由 • 実際のアプリケーションにおいても bypass4netns は高い性能を達成することを確認 26 スライド: https://bit.ly/4ggWb4z

Slide 81

Slide 81 text

実際に Rootless コンテナを動かす https://github.com/containerd/nerdctl/blob/main/docs/rootless.md に記載の手順でセットアップ $ mkdir ~/.local $ wget -O - https://github.com/containerd/nerdctl/releases/download/v2.0.1/nerdctl-full-2.0.1-linux-amd64.tar.gz | tar zx -C ~/.local $ echo 'export PATH=$PATH:$HOME/.local/bin' >> .bashrc $ source ~/.bashrc $ containerd-rootless-setuptool.sh install $ nerdctl run --rm hello-world 27 スライド: https://bit.ly/4ggWb4z

Slide 82

Slide 82 text

通常の Rootless コンテナでの iperf3 ホスト上で iperf3 -s をし、コンテナ→ホストで接続 手元の端末で約200〜300Mbps 28 スライド: https://bit.ly/4ggWb4z

Slide 83

Slide 83 text

bypass4netns 29 追加で専用デーモンである bypass4netnsd をインストール $ containerd-rootless-setuptool.sh install-bypass4netnsd コンテナ実行時のフラグとして “--annotation nerdctl/bypass4netns=true” を追記 $ nerdctl run -it --rm --annotation nerdctl/bypass4netns=true alpine スライド: https://bit.ly/4ggWb4z

Slide 84

Slide 84 text

まとめ • Rootless Containers は主に UserNS を用いることで実現される → ホストに veth IF を作ることは出来ない = そのままでは完全な Rootless は実現できない • slirp4netns, RootlessKit により完全な Rootless を実現 → トレードオフとして性能劣化がある • bypass4netns により slirp4netns 等をバイパスし高速化 • コンテナ内のソケットを必要に応じてホスト上のソケットにスイッチ • Seccomp Notify を用いることでアプリへの改変なしに性能の改善を達成 • 詳細は実装, 論文にて! • Repository: https://github.com/rootless-containers/bypass4netns • Slide: https://bit.ly/3ZFCBJ7 Paper: https://dl.acm.org/doi/10.1145/3674213.3674221 30 スライド: https://bit.ly/4ggWb4z

Slide 85

Slide 85 text

Appendix 31

Slide 86

Slide 86 text

User-mode Networking について パケットをユーザー空間のプロセスで処理してホスト上のソケットに置換する仕組み 用途 • Rootless Containers: root 権限なしで UserNS からの通信を中継 • QEMU 等の VMM: bridge, iptables の設定なしにホスト上のネットワークを利用 KubeVirt における ServiceMesh = 同じ NetNS を使う場合にも活用 実装例 • libslirp, slirp4netns: QEMU, Rootless Containers で既に利用されている • passt, pasta: Stefano Brivio 氏ら(RedHat) により開発, Rootless Podman や libkrun で利用, 高速(らしい) 公式HP: https://passt.top/, KVM Forum 2022 での発表: Slirp is dead, long live Slirp! https://kvm-forum.qemu.org/2022/Slirp%20is%20dead%2C%20long%20live%20Slirp%21%20KVM%20Forum%202022.pdf 32

Slide 87

Slide 87 text

関連研究 類似事例は “完全Rootless” を実現できない. 例) SUID なバイナリ, 専用のカーネルモジュール, eBPF の活用等 LD_PRELOAD は静的リンクされたバイナリを扱えない= 互換性の欠如 LD_PRELOAD は libc の関数呼び出しをフックするが, 静的リンクされたバイナリは libc を 呼び出さない 33

Slide 88

Slide 88 text

Seccomp Notify を用いたソケットのスイッチ Seccomp Notify を用いた syscall のフック自体が 大きなオーバーヘッドを持つ(約100倍) → 闇雲に syscall をフックしていると性能劣化が大きくなる 34 336 29494 0 5000 10000 15000 20000 25000 30000 35000 w/o Seccomp Notify w/ SeccompNotify Execution time (ns) getpid(2) execution time

Slide 89

Slide 89 text

bypass4netns がフックする syscall bypss4netns ではフック対象の syscall を分類してオーバーヘッドを最小化 • (2) Configuration: ソケットの設定を記録する ※ ホスト上のソケットを正しく設定するために記録 • (3) Connection: 接続先に従いスイッチする ※ 接続先や bind するポートを確認してスイッチを行う • (4) Status: peer のアドレス情報を書き換える • (7) Close: ソケットの管理情報を破棄する bypass4netns では recv(2),send(2) のようなデータに触れるsyscallはフックしない → Seccomp Notify のオーバーヘッドは通信性能に影響を与えない トレードオフとして SOCK_STREAM のみの対応にとどまる 35

Slide 90

Slide 90 text

アクセス制御(Experimental) bypass4netns はホスト上に作成したソケットで通信する → Detach NetNS 内の iptables に設定された ACL は機能しない bypass4netns では iptables の設定状況を動的にトレースする機能を提供 • Tracing agent が公開されたポートに対するコンテナ間の通信可否をチェック • bypass4netns ではチェック結果に応じてソケットスイッチの可否を決定 36

Slide 91

Slide 91 text

ポート公開への対応(Experimental) ソケットは一度スイッチされるとホストの NetNS 上に存在することになる → 他のコンテナは元のコンテナのアドレスでは接続できなくなる bypass4netns では公開されたポートに対する connect(2) のアドレスを書き換えて対処 • /proc/PID/mem 経由で直接プロセス内のアドレスを書き換える • getpeername(2) が呼ばれたときは元のコンテナのアドレスを返す 37

Slide 92

Slide 92 text

Usernetes Gen2 におけるマルチノード通信 bypass4netns は Usernetes においても限定的に適用可能 ※ Pod → 外部エンドポイント, NodePort の通信は高速化できる 38 引用: Usernetes Gen2 - Kubernetes in Rootless Docker, with Multiple Nodes https://github.com/AkihiroSuda/AkihiroSuda/blob/master/slides/2024/20240415%20%5BContainer%20Plumbing%20Days%5D%20Usernetes%20Gen2%20- %20Kubernetes%20in%20Rootless%20Docker%2C%20with%20Multiple%20Nodes.pdf

Slide 93

Slide 93 text

マルチノード通信の高速化(実験的試行) Usernetes w/ bypass4netns では Pod-to-Pod 通信は高速化できていない • Pod-to-Pod は VXLAN IF 経由で通信する • 通信には Rootless コンテナ内に作られた VXLAN IF を用いる → slirp4netns, RootlessKit により処理されるため性能劣化の影響を受ける 39 大幅な性能劣化

Slide 94

Slide 94 text

マルチノード通信の高速化(実験的試行) アドレス書き換えによる underlay 直接通信で高速化 1. 公開ポート(C2:80/tcp)が bind されたソケットをスイッチ 2. ホストのアドレスとポート(HostB:12345/tcp) をKVSに記録 3. 公開ポートに対する接続(C2:80/tcp)の connect(2) をフック 4. 接続先アドレスをKVSに記録されたアドレス(HostB:12345/tcp)に書き換え 40 C1 bypass4netns C2 bypass4netns HostA HostB

Slide 95

Slide 95 text

マルチノード通信の高速化(実験的試行) アドレス書き換えによる underlay 直接通信で高速化 1. 公開ポート(C2:80/tcp)が bind されたソケットをスイッチ 2. ホストのアドレスとポート(HostB:12345/tcp) をKVSに記録 3. 公開ポートに対する接続(C2:80/tcp)の connect(2) をフック 4. 接続先アドレスをKVSに記録されたアドレス(HostB:12345/tcp)に書き換え 40 C1 bypass4netns C2 Socket binding on 80/tcp bypass4netns HostA HostB

Slide 96

Slide 96 text

マルチノード通信の高速化(実験的試行) アドレス書き換えによる underlay 直接通信で高速化 1. 公開ポート(C2:80/tcp)が bind されたソケットをスイッチ 2. ホストのアドレスとポート(HostB:12345/tcp) をKVSに記録 3. 公開ポートに対する接続(C2:80/tcp)の connect(2) をフック 4. 接続先アドレスをKVSに記録されたアドレス(HostB:12345/tcp)に書き換え 40 C1 bypass4netns C2 Socket binding on 80/tcp Socket binded on 12345/tcp bypass4netns HostA HostB

Slide 97

Slide 97 text

マルチノード通信の高速化(実験的試行) アドレス書き換えによる underlay 直接通信で高速化 1. 公開ポート(C2:80/tcp)が bind されたソケットをスイッチ 2. ホストのアドレスとポート(HostB:12345/tcp) をKVSに記録 3. 公開ポートに対する接続(C2:80/tcp)の connect(2) をフック 4. 接続先アドレスをKVSに記録されたアドレス(HostB:12345/tcp)に書き換え 40 C1 bypass4netns C2 Socket binding on 80/tcp Socket binded on 12345/tcp bypass4netns Container Host C2:80/tcp HostB:12345/tcp KVS HostA HostB

Slide 98

Slide 98 text

マルチノード通信の高速化(実験的試行) アドレス書き換えによる underlay 直接通信で高速化 1. 公開ポート(C2:80/tcp)が bind されたソケットをスイッチ 2. ホストのアドレスとポート(HostB:12345/tcp) をKVSに記録 3. 公開ポートに対する接続(C2:80/tcp)の connect(2) をフック 4. 接続先アドレスをKVSに記録されたアドレス(HostB:12345/tcp)に書き換え 40 C1 Socket connecting to C2:80/tcp bypass4netns C2 Socket binding on 80/tcp Socket binded on 12345/tcp bypass4netns Container Host C2:80/tcp HostB:12345/tcp KVS HostA HostB

Slide 99

Slide 99 text

マルチノード通信の高速化(実験的試行) アドレス書き換えによる underlay 直接通信で高速化 1. 公開ポート(C2:80/tcp)が bind されたソケットをスイッチ 2. ホストのアドレスとポート(HostB:12345/tcp) をKVSに記録 3. 公開ポートに対する接続(C2:80/tcp)の connect(2) をフック 4. 接続先アドレスをKVSに記録されたアドレス(HostB:12345/tcp)に書き換え 40 C1 Socket connecting to C2:80/tcp bypass4netns C2 Socket binding on 80/tcp Socket binded on 12345/tcp bypass4netns Container Host C2:80/tcp HostB:12345/tcp KVS HostA HostB HostB:12345/tcp

Slide 100

Slide 100 text

マルチノード通信の高速化(実験的試行) アドレス書き換えによる underlay 直接通信で高速化 1. 公開ポート(C2:80/tcp)が bind されたソケットをスイッチ 2. ホストのアドレスとポート(HostB:12345/tcp) をKVSに記録 3. 公開ポートに対する接続(C2:80/tcp)の connect(2) をフック 4. 接続先アドレスをKVSに記録されたアドレス(HostB:12345/tcp)に書き換え 40 C1 Socket connecting to C2:80/tcp Socket connecting to HostB:12345/tcp bypass4netns C2 Socket binding on 80/tcp Socket binded on 12345/tcp bypass4netns Container Host C2:80/tcp HostB:12345/tcp KVS HostA HostB HostB:12345/tcp

Slide 101

Slide 101 text

マルチノード通信の高速化(実験的試行) アドレス書き換えによる underlay 直接通信で高速化 1. 公開ポート(C2:80/tcp)が bind されたソケットをスイッチ 2. ホストのアドレスとポート(HostB:12345/tcp) をKVSに記録 3. 公開ポートに対する接続(C2:80/tcp)の connect(2) をフック 4. 接続先アドレスをKVSに記録されたアドレス(HostB:12345/tcp)に書き換え 40 C1 Socket connecting to C2:80/tcp Socket connecting to HostB:12345/tcp bypass4netns C2 Socket binding on 80/tcp Socket binded on 12345/tcp bypass4netns Container Host C2:80/tcp HostB:12345/tcp KVS HostA HostB HostB:12345/tcp

Slide 102

Slide 102 text

性能評価 6種類のネットワークで性能を測定 • rootful-pfd: Rootful container, iptables 経由のポート公開 • rootless-pfd: Rootless container, RootlessKit 経由のポート公開 • b4ns-pfd: Rootless container, bypass4netns 経由のポート公開 • rootful-vxlan: Rootful container, ホスト上の VXLAN IF 経由で通信 • rootless-vxlan: Rootless container, コンテナ内の VXLAN IF 経由で通信 • b4ns-multinode: Rootless container, bypass4netns マルチノード機能経由で通信 41 rootless-vxlan b4ns-multinode rootful-vxlan

Slide 103

Slide 103 text

性能評価: iperf3 いずれの場合についても bypass4netns を利用した場合が最も高い性能を達成 • b4ns-pfd ではrootless-pfd (570Mbps)と比べて30倍の高速化 (19.7 Gbps) • rootful-pfd (17.9 Gbps) よりも高速 → b4ns-pfd では bridge や iptables などがバイパスされたことで高速化 • マルチノードについても同様に b4ns-multimode が最も高い性能を達成 42

Slide 104

Slide 104 text

性能評価: MySQL sysbench の OLTP benchmark で MySQL の性能を測定 • 大きな性能改善は見られなかった • レイテンシはわずかに減った • Rootful とほとんど同じ性能となった • MySQL, sysbench でも動作するが、性能上の改善はほとんどない 43

Slide 105

Slide 105 text

性能評価: Redis redis-benchmark を用いて Redis の性能を評価 • b4ns-pfd では約2倍、b4ns-multimode では約3倍高い性能を達成 • Rootful に比べて Rootless w/ bypass4netns の方が高い性能を達成 → おそらく iperf3 と同様の理由 • 実際のアプリケーションにおいても bypass4netns は高い性能を達成することを確認 44

Slide 106

Slide 106 text

Future Task: Kubernetes/Usernetes Support bypass4netns は Pod-to-Pod 通信 を高速化 • 現在の手法はソケットをホスト上にスイッチする → ポートの枯渇や予期せぬ通信が行われる可能性がある • Sidecar proxy による解決 → 通信性能における若干の劣化は予期されるが、より信頼性がある 45 現在の手法 Proxy 手法 接続について Proxy で検証 Proxy のソケットの みスイッチ 大量のソケット 予期せぬ通信