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

Rust no_stdで作るコンテナ

Rust no_stdで作るコンテナ

Takashi IIGUNI

October 10, 2021
Tweet

Other Decks in Programming

Transcript

  1. Rust no_stdで作る
    コンテナエンジン
    第15回 コンテナ技術の情報交換会@オンライン
    Takashi Iiguni (@guni1192)
    Kagawa University
    10/9/2021 1

    View full-size slide

  2. Profile
    • 氏名: 飯國 隆志(Takashi Iiguni)
    • 香川大学大学院工学研究科
    信頼性情報システム工学専攻M2
    • Favorite: Container, Security, Rust, eBPF
    • Twitter: guni1192
    • GitHub: guni1192
    • 来年から東京でSoftware Engineer
    10/9/2021 2

    View full-size slide

  3. 今日の話
    Rustのミドルウェアも
    Goみたいにポータブルな
    バイナリを作って配りたい
    10/9/2021 3

    View full-size slide

  4. Agenda
    • 今日話すこと
    • Rustでポータブルなシングルバイナリ作る話
    • Rustからlibcなしでシステムコールを呼び出す話
    • Rustの標準ライブラリ縛りでコンテナもどきを作る話
    • 話さないこと
    • OCI Runtimeの話
    10/9/2021 4

    View full-size slide

  5. Rust and Go
    • Goは基本的にstatic link
    • 標準ライブラリはあまりCに依存しないようにできてい
    るからstatic linkしやすい
    • システムコールの呼び出しすらGoとアセンブラ
    • Rustは基本的にdynamic link(が多い気がする)
    • 標準ライブラリ(std)がlibcに依存しているからstatic
    linkしにくい
    • musl libcを使うことでstatic linkできる
    • 依存ライブラリの再コンパイルが必要になる場合も
    ある
    10/9/2021 5

    View full-size slide

  6. 例えばyoukiの場合
    10/9/2021 6

    View full-size slide

  7. Rust library for implementing containers
    • libc: libc(7)をRustから呼び出すFFI binding
    • nix: libc crateのRust likeなwrapper
    • ResultによるError Handleなど
    10/9/2021 7

    View full-size slide

  8. libc(7)
    • C言語の標準ライブラリ
    • printf(3)やfopen(3)などのライブラリ関数を提供
    • write(2), open(2)などのシステムコールを呼ぶための関数も提供
    • 実装例
    • glibc(GNU C Library): GNU Projectのlibc
    • musl libc: MITライセンスのlibc. Alpine Linuxなどで利用されている
    10/9/2021 8

    View full-size slide

  9. Rustからlibc経由でシステムコール
    を発行する
    • Pros
    • 既存の実装を利用して多くの関数が利用できる
    • 成熟していて多くのArchに対応している
    • Cons
    • Rustの型に合わせた実装が難しい
    • Resultなどが使いたかったらnixのような抽象化ライブラリが必要
    • libcの脆弱性や更新などが必要
    10/9/2021 9

    View full-size slide

  10. Issue syscall in Linux x86_64
    • システムコールの発行はレジスタに値を格納し,syscall命令を実行する
    • 結果はraxレジスタに格納
    Register write(2) execve(2) clone(2)
    syscall number rax 1 59 56
    arg1 rdi fd cmd flags
    arg2 rsi buf args child stack
    arg3 rdx buf size env TID field in parent
    arg4 r10 TID field in child
    arg5 r8 thread pointer
    arg6 r9
    10/9/2021 10

    View full-size slide

  11. Rustから直接システムコールを呼ぶ
    Rustのinline assemblyを使う(asm!マクロ)
    10/9/2021 11

    View full-size slide

  12. 余談: 僕らがシステムコールと思ってい
    たものはシステムコールじゃなかった
    • wait系のシステムコール
    • Linux x86_64はwait4しかない
    • libcのwaitpidはwait4システムコールを呼んでいる
    (歴史的経緯やアーキテクチャの違いがありそう)
    • $ man 2 waitpidが引けたからといってシステムコールとは限らない
    10/9/2021 12

    View full-size slide

  13. 苦労話: libc とシステムコール
    • cloneシステムコール
    • libcの引数とカーネル側のレジスタの値
    が違う
    • コールバック関数があるのはlibc側の仕様
    musl libcのコードは読みやすかった
    glibcはコメントに重要なことがたくさん書いてあった
    10/9/2021 13

    View full-size slide

  14. 余談: libcを経由しないシステムコー
    ルの発行について
    • OpenBSDはlibc以外からのシステムコールをブロックする仕組みがある
    • 信頼できない経路からのシステムコールの発行を止めたい
    • この機構の導入によってGoのようなlibcを経由しない言語がブロック
    • GoはOpenBSDの場合はCGOを利用するようになった
    10/9/2021 14

    View full-size slide

  15. 試しにシングルバイナリの
    コンテナエンジンを作ろう!
    Rustからシステムコールを呼べた
    10/9/2021 15

    View full-size slide

  16. シングルバイナリな
    コンテナエンジンの要件
    • std crateを使用しない
    • std crateはlibcに依存している
    • Dynamic linkを一切しない
    • std crate
    • Rustの標準ライブラリ
    • Vec, Option, Boxといったプリミ
    ティブなライブラリを提供
    • 標準マクロ,IO,マルチスレッドな
    どの機能
    10/9/2021 16

    View full-size slide

  17. Rust no_std
    • std crateを用いないモード
    • stdの代わりにcore crateを使用できる
    • core crate
    • プラットフォームに依存しないポータブルな標準ライブラリ
    • 浮動小数点,文字列,スライス,アトミック操作やSIMD命令などのAPIを提供
    • 一般的にカーネルやブートローダ,ベアメタルな環境で用いるモード
    • 動的メモリ確保などの昨日は
    備考: Rustのno_std環境をちゃんと触るなら
    「Writing an OS in Rust」https://os.phil-opp.com がおすすめ
    10/9/2021 17

    View full-size slide

  18. Nosc(No std container)
    • Portable and Tiny Container Engine
    • without std crate
    • without dynamic link binary
    • Environment
    • Linux >= 5.7
    • Arch: x86_64
    • Cgroup v2
    • https://github.com/guni1192/nosc
    10/9/2021 18

    View full-size slide

  19. Nosc Feature
    • プロセスのNamespaceの分離
    • プロセスを親と異なるCgroupへ所属
    • 必要なシステムコール
    • clone3
    • execve
    • write
    • open
    • wait4
    • mkdir
    10/9/2021 19

    View full-size slide

  20. clone3
    • 子プロセスを作るシステムコール
    • Linux 5.3で追加された
    • Linux 5.7以降で子プロセスを親とは別のcgroupに配属可能に
    • clone_args.cgroupに配属させるcgroupディレクトリのfdを与えて実行
    • clone_args.flagsにCLONE_INTO_CGROUPを指定
    10/9/2021 20

    View full-size slide

  21. Nosc Run container
    10/9/2021 21

    View full-size slide

  22. Binary size
    Container Engine Size(Bytes)
    Nosc (static link + stripped) 24,904
    go tiny container (static link + stripped) ※ 1,584,856
    youki (striped) 2,574,792
    runc (striped) 11,445,576
    ※go tiny containerは即興で作ったnoscと似たような挙動をするコンテナエンジン
    10/9/2021 22

    View full-size slide

  23. Future work
    • libcに依存しないAlternative nixみたいなものを作ってみても面白そう
    • Cに依存しないコンテナエンジンとかも面白そう
    Summary
    • Rustでもポータブルなバイナリを作りたかった
    • libc無しでシステムコールを発行するライブラリを作っている
    • no_std環境で動くコンテナエンジンもどきを作ってみた
    • 失って初めて分かるstdとlibcの便利さ
    10/9/2021 23

    View full-size slide