$30 off During Our Annual Pro Sale. View Details »

詳説 OCIコンテナランタイム youki@第15回 コンテナ技術の情報交換会

うたもく
October 09, 2021

詳説 OCIコンテナランタイム youki@第15回 コンテナ技術の情報交換会

うたもく

October 09, 2021
Tweet

More Decks by うたもく

Other Decks in Technology

Transcript

  1. 詳説 OCIコンテナランタイム
    youki

    第15回 コンテナ技術の情報交換会

    うたもく(@utam0k)

    1

    View Slide

  2. 自己紹介

    ● うたもく(@utam0k)

    ● 普段はWeb企業のバックエンドエンジニア(Scala)

    ● 2021年からコンテナ真面目に入門

    ● containersのメンバー

    2

    View Slide

  3. 知ってもらいたいこと

    3
    youkiの面白いポイント

    ● Rustとコンテナランタイムってどうなの?

    ● runCとの違いは?

    ● 処理の流れは?


    コンテナを作るまでの流れがコードレベルでわかる

    ● youkiの詳細な処理の流れ

    ● runCの処理の流れ


    View Slide

  4. 目次

    1. youkiの紹介

    2. youkiの大まかな処理の流れ

    3. コンテナランタイムのコードを追っていく!

    4

    View Slide

  5. 目次

    1. youkiの紹介

    2. youkiの大まかな処理の流れ

    3. コンテナランタイムのコードを追っていく!

    5

    View Slide

  6. ● Rust製の低レベルコンテナランタイム

    ● podmanなどを開発しているcontainersで開発中

    ○ https://github.com/containers/youki
    ● うたもくを中心にリリースに向けて開発を進めている

    ● githubで⭐数が2.2K

    ● youki = 容器 = コンテナ

    youkiとは?

    6

    View Slide

  7. Kubelet(K8s)
 Linuxなど

    High-Level
    Runtime

    CRI

    Low-Level
    Runtime

    OCI

    7
    CRI − Container Runtime Interface

    OCI − Open Container Initiative

    Container Runtime


    View Slide

  8. Kubelet(K8s)
 Linuxなど

    High-Level
    Runtime

    CRI

    Low-Level
    Runtime

    OCI

    ● runc

    ● youki

    ● crun


    8

    View Slide

  9. youkiの存在意義

    ● コンテナランタイムの多様性

    ● Rustコンテナ界隈でのライブラリへの貢献

    ○ https://github.com/containers/oci-spec-rs
    ● 既存の低レイヤのソフトウェアをRustで書き換える
    一例

    9

    View Slide

  10. 目次

    1. youkiの紹介

    2. youkiの大まかな処理の流れ

    3. コンテナランタイムのコードを追っていく!

    10

    View Slide

  11. コンテナ技術の軽い復習

    ● コンテナを支える技術

    ○ chrootpace - ルートディレクトリを変更

    ○ namespace - 操作可能なリソースの隔離

    ○ cgroup ace - 使用可能なリソースの設定


    ● コンテナ界隈を支える仕様

    ○ CRI - Container Runtime Interface

    ○ OCI - Open Container Initiative

    11

    View Slide

  12. View Slide

  13. View Slide

  14. ● コンテナのプロセスができるまでには double-fork が必要

    ○ 1st fork 

    ■ 中間プロセス

    ■ initプロセスを作るための間のプロセス

    ○ 2nd fork

    ■ initプロセス

    ■ 実際にコンテナのinitプロセスになる 

    ○ 理由は後ほど...


    View Slide

  15. View Slide

  16. ● $ docker create --name test busybox hostname

    ● 高レベルランタイムからコンテナを作る命令を受付

    ○ 命令を受け付ける...? 

    ■ 単なるコマンド

    ■ $ youki create -b $(bundle_path) $(container_name)

    ● fork(2) - Intermediate Processを生成する


    View Slide

  17. View Slide

  18. ● unshare(CLONE_NEWUSER) - ユーザー名前空間を分離

    ○ 新しい名前空間で特権ユーザーになれる

    ● host ↔ containerのユーザーとグループのマッピング

    ○ 例) host(uid 1000) ↔ container(uid 0)

    中間
    create

    View Slide

  19. View Slide

  20. ● 中間プロセスでPID名前空間だけを先に分離

    ○ PID名前空間は発動した次のプロセスから適用されるため

    ● fork(2) - 中間プロセスからinitプロセスを生成

    ● initプロセスで残りの名前空間を分離

    ○ unshare(2)を発動した瞬間から分離される

    init
    中間

    View Slide

  21. なぜdouble-forkが必要なのか?

    ● PID名前空間の分離は発動した次のプロセスから適用される
    ○ fork回数 += 1
    ● PID名前空間の分離にはCAP_SYS_ADMINが必要
    ○ ホストが特権ユーザーではない場合は...?
    ○ ユーザー名前空間の分離(一般ユーザーで実行可能)
    ■ 中間Process内で特権ユーザーになる

    ■ fork回数 += 1

    ● ユーザー名前空間 → PID名前空間 → 残りの名前空間
    21

    View Slide

  22. View Slide

  23. ● 諸々コンテナになるのに必要な処理をinitプロセスに施す

    ○ pivot_root(2) - `/` の切り替え

    ○ setup capability - HCRから受け取ったケーパビリティにする

    ● 諸々準備が終わったことを最初のプロセス(youki create)に通知

    ● initプロセスはstartのシグナルが来るまで「待て」

    create 中間 init

    View Slide

  24. View Slide

  25. ● cgroupを諸々適用する

    ● 受け取ったinitプロセスのPIDをpidファイルに書き込む

    ○ HCRはこのpidファイルのPIDを元に色々管理していたりするっぽい

    create 中間

    View Slide

  26. View Slide

  27. ● initプロセスはデーモンプロセスとなり、コンテナのエントリポイントを実行
    するのを待つ

    ● 高レベルコンテナランタイムからスタートの合図

    ○ $ docker start test

    init

    View Slide

  28. 処理の流れのまとめ

    ● プロセスに対して細かく色々している

    ○ 名前空間の分離

    ○ pivot_root

    ○ capability

    ○ cgroups


    ● double-forkが必要

    28

    View Slide

  29. 処理の流れのまとめ

    ● プロセスに対して細かく色々している

    ○ 名前空間の分離

    ○ pivot_root

    ○ capability

    ○ cgroups


    ● double-forkが必要

    29
    Rust 得意分野っぽい!


    View Slide

  30. 目次

    1. youkiの紹介

    2. youkiの大まかな処理の流れ

    3. コンテナランタイムのコードを追っていく!

    30

    View Slide

  31. Let’s dive into youki

    View Slide

  32. ● 流れ自体は大きく変わらない

    ● 使用言語

    ○ runC - GoとCのハイブリッド

    ○ youki - Rust(一部FFI)

    runCではどうなっているのか

    32

    View Slide

  33. GoとCのハイブリッドだと...?

    ● Goの言語ランタイムの制約

    ○ fork(2) / clone(2) が難しい

    ■ おそらくGoroutineの関係

    ○ 言語ランタイムがマルチスレッド


    ● setns(2) 😢
    A multithreaded process may not change user
    namespace with setns().


    View Slide

  34. ● Goで扱えない部分はCで扱う

    ○ サブコマンドのinitがCを扱う

    ○ 言語ランタイムが起動する前にCの処理を呼び出す

    GoとCのハイブリッドだと...?


    View Slide

  35. ● 大雑把にrunCがコンテナを作る流れ

    1. runC create(Golang)

    ● Goでも可能な処理を行いinitサブコマンドを実行


    2. runC init(Golang & C)

    ● Goの言語ランタイムが起動する前にCの処理(double-fork)を
    行う


    3. double-fork(C言語)

    ● fork(2)、setns(2)、uid/gidのマッピングなどなど...

    GoとCのハイブリッドだと...?


    View Slide

  36. Let’s dive into runC

    View Slide

  37. runCのコード読み

    ● startContainer() - create.go

    ○ createContainer()

    ■ loadFactory()

    ● libcontainer.New()

    ○ /proc/self/exec init(= runc init)をコマンドとして
    container にセットしている


    ○ runner.run()

    ■ container をスタートする


    View Slide

  38. コードリーディングのまとめ

    ● runCはGoとCのハイブリッド

    ○ マルチスレッドでは処理ができない部分があるのでCを
    使う

    ○ createサブコマンド(Go) → initサブコマンド(C)

    ● youki

    ○ Rustのみでよりシンプルにコードがかける


    View Slide

  39. Thanks to all the people who
    already contributed to youki :)

    39

    View Slide

  40. Thanks you! Any questions?

    40

    View Slide