Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
Slide 1
Slide 1 text
詳説 OCIコンテナランタイム youki 第15回 コンテナ技術の情報交換会 うたもく(@utam0k) 1
Slide 2
Slide 2 text
自己紹介 ● うたもく(@utam0k) ● 普段はWeb企業のバックエンドエンジニア(Scala) ● 2021年からコンテナ真面目に入門 ● containersのメンバー 2
Slide 3
Slide 3 text
知ってもらいたいこと 3 youkiの面白いポイント ● Rustとコンテナランタイムってどうなの? ● runCとの違いは? ● 処理の流れは? コンテナを作るまでの流れがコードレベルでわかる ● youkiの詳細な処理の流れ ● runCの処理の流れ
Slide 4
Slide 4 text
目次 1. youkiの紹介 2. youkiの大まかな処理の流れ 3. コンテナランタイムのコードを追っていく! 4
Slide 5
Slide 5 text
目次 1. youkiの紹介 2. youkiの大まかな処理の流れ 3. コンテナランタイムのコードを追っていく! 5
Slide 6
Slide 6 text
● Rust製の低レベルコンテナランタイム ● podmanなどを開発しているcontainersで開発中 ○ https://github.com/containers/youki ● うたもくを中心にリリースに向けて開発を進めている ● githubで⭐数が2.2K ● youki = 容器 = コンテナ youkiとは? 6
Slide 7
Slide 7 text
Kubelet(K8s) Linuxなど High-Level Runtime CRI Low-Level Runtime OCI 7 CRI − Container Runtime Interface OCI − Open Container Initiative Container Runtime
Slide 8
Slide 8 text
Kubelet(K8s) Linuxなど High-Level Runtime CRI Low-Level Runtime OCI ● runc ● youki ● crun 8
Slide 9
Slide 9 text
youkiの存在意義 ● コンテナランタイムの多様性 ● Rustコンテナ界隈でのライブラリへの貢献 ○ https://github.com/containers/oci-spec-rs ● 既存の低レイヤのソフトウェアをRustで書き換える 一例 9
Slide 10
Slide 10 text
目次 1. youkiの紹介 2. youkiの大まかな処理の流れ 3. コンテナランタイムのコードを追っていく! 10
Slide 11
Slide 11 text
コンテナ技術の軽い復習 ● コンテナを支える技術 ○ chrootpace - ルートディレクトリを変更 ○ namespace - 操作可能なリソースの隔離 ○ cgroup ace - 使用可能なリソースの設定 ● コンテナ界隈を支える仕様 ○ CRI - Container Runtime Interface ○ OCI - Open Container Initiative 11
Slide 12
Slide 12 text
No content
Slide 13
Slide 13 text
No content
Slide 14
Slide 14 text
● コンテナのプロセスができるまでには double-fork が必要 ○ 1st fork ■ 中間プロセス ■ initプロセスを作るための間のプロセス ○ 2nd fork ■ initプロセス ■ 実際にコンテナのinitプロセスになる ○ 理由は後ほど...
Slide 15
Slide 15 text
No content
Slide 16
Slide 16 text
● $ docker create --name test busybox hostname ● 高レベルランタイムからコンテナを作る命令を受付 ○ 命令を受け付ける...? ■ 単なるコマンド ■ $ youki create -b $(bundle_path) $(container_name) ● fork(2) - Intermediate Processを生成する
Slide 17
Slide 17 text
No content
Slide 18
Slide 18 text
● unshare(CLONE_NEWUSER) - ユーザー名前空間を分離 ○ 新しい名前空間で特権ユーザーになれる ● host ↔ containerのユーザーとグループのマッピング ○ 例) host(uid 1000) ↔ container(uid 0) 中間 create
Slide 19
Slide 19 text
No content
Slide 20
Slide 20 text
● 中間プロセスでPID名前空間だけを先に分離 ○ PID名前空間は発動した次のプロセスから適用されるため ● fork(2) - 中間プロセスからinitプロセスを生成 ● initプロセスで残りの名前空間を分離 ○ unshare(2)を発動した瞬間から分離される init 中間
Slide 21
Slide 21 text
なぜdouble-forkが必要なのか? ● PID名前空間の分離は発動した次のプロセスから適用される ○ fork回数 += 1 ● PID名前空間の分離にはCAP_SYS_ADMINが必要 ○ ホストが特権ユーザーではない場合は...? ○ ユーザー名前空間の分離(一般ユーザーで実行可能) ■ 中間Process内で特権ユーザーになる ■ fork回数 += 1 ● ユーザー名前空間 → PID名前空間 → 残りの名前空間 21
Slide 22
Slide 22 text
No content
Slide 23
Slide 23 text
● 諸々コンテナになるのに必要な処理をinitプロセスに施す ○ pivot_root(2) - `/` の切り替え ○ setup capability - HCRから受け取ったケーパビリティにする ● 諸々準備が終わったことを最初のプロセス(youki create)に通知 ● initプロセスはstartのシグナルが来るまで「待て」 create 中間 init
Slide 24
Slide 24 text
No content
Slide 25
Slide 25 text
● cgroupを諸々適用する ● 受け取ったinitプロセスのPIDをpidファイルに書き込む ○ HCRはこのpidファイルのPIDを元に色々管理していたりするっぽい create 中間
Slide 26
Slide 26 text
No content
Slide 27
Slide 27 text
● initプロセスはデーモンプロセスとなり、コンテナのエントリポイントを実行 するのを待つ ● 高レベルコンテナランタイムからスタートの合図 ○ $ docker start test init
Slide 28
Slide 28 text
処理の流れのまとめ ● プロセスに対して細かく色々している ○ 名前空間の分離 ○ pivot_root ○ capability ○ cgroups ● double-forkが必要 28
Slide 29
Slide 29 text
処理の流れのまとめ ● プロセスに対して細かく色々している ○ 名前空間の分離 ○ pivot_root ○ capability ○ cgroups ● double-forkが必要 29 Rust 得意分野っぽい!
Slide 30
Slide 30 text
目次 1. youkiの紹介 2. youkiの大まかな処理の流れ 3. コンテナランタイムのコードを追っていく! 30
Slide 31
Slide 31 text
Let’s dive into youki
Slide 32
Slide 32 text
● 流れ自体は大きく変わらない ● 使用言語 ○ runC - GoとCのハイブリッド ○ youki - Rust(一部FFI) runCではどうなっているのか 32
Slide 33
Slide 33 text
GoとCのハイブリッドだと...? ● Goの言語ランタイムの制約 ○ fork(2) / clone(2) が難しい ■ おそらくGoroutineの関係 ○ 言語ランタイムがマルチスレッド ● setns(2) 😢 A multithreaded process may not change user namespace with setns().
Slide 34
Slide 34 text
● Goで扱えない部分はCで扱う ○ サブコマンドのinitがCを扱う ○ 言語ランタイムが起動する前にCの処理を呼び出す GoとCのハイブリッドだと...?
Slide 35
Slide 35 text
● 大雑把に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のハイブリッドだと...?
Slide 36
Slide 36 text
Let’s dive into runC
Slide 37
Slide 37 text
runCのコード読み ● startContainer() - create.go ○ createContainer() ■ loadFactory() ● libcontainer.New() ○ /proc/self/exec init(= runc init)をコマンドとして container にセットしている ○ runner.run() ■ container をスタートする
Slide 38
Slide 38 text
コードリーディングのまとめ ● runCはGoとCのハイブリッド ○ マルチスレッドでは処理ができない部分があるのでCを 使う ○ createサブコマンド(Go) → initサブコマンド(C) ● youki ○ Rustのみでよりシンプルにコードがかける
Slide 39
Slide 39 text
Thanks to all the people who already contributed to youki :) 39
Slide 40
Slide 40 text
Thanks you! Any questions? 40