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

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

うたもく
October 09, 2021

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

うたもく

October 09, 2021
Tweet

More Decks by うたもく

Other Decks in Technology

Transcript

  1. 知ってもらいたいこと
 3 youkiの面白いポイント
 • Rustとコンテナランタイムってどうなの?
 • runCとの違いは?
 • 処理の流れは?
 


    コンテナを作るまでの流れがコードレベルでわかる
 • youkiの詳細な処理の流れ
 • runCの処理の流れ
 

  2. Kubelet(K8s)
 Linuxなど
 High-Level Runtime
 CRI
 Low-Level Runtime
 OCI
 7 CRI

    − Container Runtime Interface
 OCI − Open Container Initiative
 Container Runtime

  3. コンテナ技術の軽い復習
 • コンテナを支える技術
 ◦ chrootpace - ルートディレクトリを変更
 ◦ namespace -

    操作可能なリソースの隔離
 ◦ cgroup ace - 使用可能なリソースの設定
 
 • コンテナ界隈を支える仕様
 ◦ CRI - Container Runtime Interface
 ◦ OCI - Open Container Initiative
 11
  4. • コンテナのプロセスができるまでには double-fork が必要
 ◦ 1st fork 
 ▪ 中間プロセス


    ▪ initプロセスを作るための間のプロセス
 ◦ 2nd fork
 ▪ initプロセス
 ▪ 実際にコンテナのinitプロセスになる 
 ◦ 理由は後ほど...

  5. • $ docker create --name test busybox hostname
 • 高レベルランタイムからコンテナを作る命令を受付


    ◦ 命令を受け付ける...? 
 ▪ 単なるコマンド
 ▪ $ youki create -b $(bundle_path) $(container_name)
 • fork(2) - Intermediate Processを生成する

  6. なぜdouble-forkが必要なのか?
 • PID名前空間の分離は発動した次のプロセスから適用される ◦ fork回数 += 1 • PID名前空間の分離にはCAP_SYS_ADMINが必要 ◦

    ホストが特権ユーザーではない場合は...? ◦ ユーザー名前空間の分離(一般ユーザーで実行可能) ▪ 中間Process内で特権ユーザーになる
 ▪ fork回数 += 1
 • ユーザー名前空間 → PID名前空間 → 残りの名前空間 21
  7. • 諸々コンテナになるのに必要な処理をinitプロセスに施す
 ◦ pivot_root(2) - `/` の切り替え
 ◦ setup capability

    - HCRから受け取ったケーパビリティにする
 • 諸々準備が終わったことを最初のプロセス(youki create)に通知
 • initプロセスはstartのシグナルが来るまで「待て」
 create 中間 init
  8. GoとCのハイブリッドだと...?
 • Goの言語ランタイムの制約
 ◦ fork(2) / clone(2) が難しい
 ▪ おそらくGoroutineの関係


    ◦ 言語ランタイムがマルチスレッド
 
 • setns(2) 😢 A multithreaded process may not change user namespace with setns().

  9. • 大雑把に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のハイブリッドだと...?

  10. runCのコード読み
 • startContainer() - create.go
 ◦ createContainer()
 ▪ loadFactory()
 •

    libcontainer.New()
 ◦ /proc/self/exec init(= runc init)をコマンドとして container にセットしている
 
 ◦ runner.run()
 ▪ container をスタートする