Upgrade to Pro — share decks privately, control downloads, hide ads and more …

詳解 bypass4netns: Rootless Containers Network の仕...

松本直樹
December 16, 2024
180

詳解 bypass4netns: Rootless Containers Network の仕組みと高速化

Container Runtime Meetup #6 (2024/12/16)
https://runtime.connpass.com/event/335464/

松本直樹

December 16, 2024
Tweet

Transcript

  1. 詳解 bypass4netns Rootless Containers Network の仕組みと高速化 Container Runtime Meetup #6

    (2024/12/16) 京都大学大学院情報学研究科 松本直樹(@PiBVT) 1
  2. 自己紹介 京都大学大学院情報学研究科 博士後期課程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
  3. 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
  4. 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
  5. 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
  6. 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
  7. 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
  8. 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
  9. 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
  10. 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
  11. 例外: 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
  12. 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
  13. 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
  14. 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
  15. 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
  16. 類似事例: lxc-user-nic Unprivileged LXC Containers では “lxc-user-nic” を用いて veth IF

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

    を作成 lxc-user-nic のバイナリが SUID を持つため、一般ユーザも root(EUID=0) として実行可能 → バイナリが高い権限で動くことになるため弱点になりうる 8 スライド: https://bit.ly/4ggWb4z
  18. 類似事例: 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
  19. 類似事例: 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
  20. 類似事例: 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
  21. 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
  22. Rootless Containers Network 新たに作成した UserNS と NetNS(Detach NetNS) 内にコンテナネットワークを構築する 10

    RootlessKit (Parent) ホスト UserNS 新 UserNS ホスト NetNS スライド: https://bit.ly/4ggWb4z
  23. 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
  24. 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
  25. 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
  26. 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
  27. 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
  28. 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
  29. 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
  30. 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
  31. 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
  32. 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
  33. 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
  34. 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
  35. 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
  36. 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
  37. 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
  38. 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
  39. 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
  40. 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
  41. 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
  42. 実際の構造(全体) 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
  43. 実際の構造(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
  44. 実際の構造(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
  45. 実際の構造(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
  46. 実際の構造(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
  47. 実際の構造(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
  48. 実際の構造(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
  49. 実際の構造(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
  50. 実際の構造(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
  51. 実際の構造(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
  52. 実際の構造(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
  53. 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
  54. 課題 課題1: 性能劣化 • 特に外部エンドポイントに対する接続(slirp4netns 担当) が遅い • 論文上のベンチでは iperf3

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

    で別ホストに対する接続時に 570 Mbps 程度 (ネイティブ比で1/30) • Usernetes(Gen2) においても異 Node 間通信が影響を受ける 課題2: 公開ポートへの接続元アドレスが分からない • 接続元アドレスは実際に接続する RootlessKit (child) になる • ログ上で意味のないアドレスしか得られない(例では 10.0.4.1) 17 スライド: https://bit.ly/4ggWb4z
  56. bypass4netns bypass4netns は slirp4netns, RootlessKit を “bypass” する • コンテナ内のアプリケーションが持つソケットをホスト上のソケットにスイッチ

    • スイッチされたソケットは slirp4netns 等の影響を受けない → ホストとほぼ同等な性能で通信出来るようになる 18 ボトルネック をbypass! Detach NetNS スライド: https://bit.ly/4ggWb4z
  57. Rootless Containers における要件 Rootless Containers は構成する要素について以下の要件を持つ • 完全な Rootless SUID

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

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

    付きのバイナリは脆弱性のリスクがある(例: lxc-user-nic) • 専用のカーネルモジュール等は利用しない: カーネルにモジュールや追加機能を安全に実装することは難しい 使える環境が限定されメンテナンスコストもかかる • アプリケーションは無改変で利用できる: Rootless Containers はこれまでの Rootful Containers と同じように使えるように開発 アプリケーションに対する改変やリビルド等の必要がないようにする必要がある 19 スライド: https://bit.ly/4ggWb4z
  60. 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
  61. 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
  62. 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
  63. 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
  64. 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
  65. 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
  66. 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
  67. 動作例: 外部エンドポイントへの接続 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
  68. 動作例: 外部エンドポイントへの接続 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
  69. 動作例: 外部エンドポイントへの接続 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
  70. 動作例: 外部エンドポイントへの接続 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
  71. 動作例: 外部エンドポイントへの接続 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
  72. 動作例: 外部エンドポイントへの接続 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
  73. 動作例: 外部エンドポイントへの接続 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
  74. 動作例: 外部エンドポイントへの接続 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
  75. アプリの互換性 右表に記載のアプリケーションに対して動作するか確認 検証結果としては • 一部(下記)のアプリを除き正常に動作 → bypass4netns のスイッチ機構がおよそ正しく動くことを確認 • 静的リンクされたアプリについても動作

    → LD_PRELOAD で対応できないアプリについても対応可能なことを確認 動作しない例 • Seccomp Notify が syscall をドロップする (Go 1.21.3 HTTP Client 試験時) → goroutine で HTTP Client を2個以上動作させると発現する場合がある 23
  76. 性能評価 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
  77. 性能評価: 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
  78. 性能評価: Redis redis-benchmark を用いて Redis の性能を評価 • b4ns-pfd で rootless-pfd

    と比較して約2倍高い性能を達成 • Rootful に比べて Rootless w/ bypass4netns の方が高い性能を達成 → おそらく iperf3 と同様の理由 • 実際のアプリケーションにおいても bypass4netns は高い性能を達成することを確認 26 スライド: https://bit.ly/4ggWb4z
  79. 実際に 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
  80. 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
  81. まとめ • 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
  82. 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
  83. 関連研究 類似事例は “完全Rootless” を実現できない. 例) SUID なバイナリ, 専用のカーネルモジュール, eBPF の活用等

    LD_PRELOAD は静的リンクされたバイナリを扱えない= 互換性の欠如 LD_PRELOAD は libc の関数呼び出しをフックするが, 静的リンクされたバイナリは libc を 呼び出さない 33
  84. 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
  85. 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
  86. アクセス制御(Experimental) bypass4netns はホスト上に作成したソケットで通信する → Detach NetNS 内の iptables に設定された ACL

    は機能しない bypass4netns では iptables の設定状況を動的にトレースする機能を提供 • Tracing agent が公開されたポートに対するコンテナ間の通信可否をチェック • bypass4netns ではチェック結果に応じてソケットスイッチの可否を決定 36
  87. 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
  88. マルチノード通信の高速化(実験的試行) Usernetes w/ bypass4netns では Pod-to-Pod 通信は高速化できていない • Pod-to-Pod は

    VXLAN IF 経由で通信する • 通信には Rootless コンテナ内に作られた VXLAN IF を用いる → slirp4netns, RootlessKit により処理されるため性能劣化の影響を受ける 39 大幅な性能劣化
  89. マルチノード通信の高速化(実験的試行) アドレス書き換えによる 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
  90. マルチノード通信の高速化(実験的試行) アドレス書き換えによる 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
  91. マルチノード通信の高速化(実験的試行) アドレス書き換えによる 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
  92. マルチノード通信の高速化(実験的試行) アドレス書き換えによる 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
  93. マルチノード通信の高速化(実験的試行) アドレス書き換えによる 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
  94. マルチノード通信の高速化(実験的試行) アドレス書き換えによる 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
  95. マルチノード通信の高速化(実験的試行) アドレス書き換えによる 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
  96. マルチノード通信の高速化(実験的試行) アドレス書き換えによる 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
  97. 性能評価 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
  98. 性能評価: iperf3 いずれの場合についても bypass4netns を利用した場合が最も高い性能を達成 • b4ns-pfd ではrootless-pfd (570Mbps)と比べて30倍の高速化 (19.7

    Gbps) • rootful-pfd (17.9 Gbps) よりも高速 → b4ns-pfd では bridge や iptables などがバイパスされたことで高速化 • マルチノードについても同様に b4ns-multimode が最も高い性能を達成 42
  99. 性能評価: MySQL sysbench の OLTP benchmark で MySQL の性能を測定 •

    大きな性能改善は見られなかった • レイテンシはわずかに減った • Rootful とほとんど同じ性能となった • MySQL, sysbench でも動作するが、性能上の改善はほとんどない 43
  100. 性能評価: Redis redis-benchmark を用いて Redis の性能を評価 • b4ns-pfd では約2倍、b4ns-multimode では約3倍高い性能を達成

    • Rootful に比べて Rootless w/ bypass4netns の方が高い性能を達成 → おそらく iperf3 と同様の理由 • 実際のアプリケーションにおいても bypass4netns は高い性能を達成することを確認 44
  101. Future Task: Kubernetes/Usernetes Support bypass4netns は Pod-to-Pod 通信 を高速化 •

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