30分で論文流し読みシリーズ 9「Cntr: Lightweight OS Containers」

www.usenix.org

  • 実際の所要時間

    • 1時間
  • 課題

    • コンテナの実行において、コンテナイメージサイズを最小化しつつ、稀にしか使わないデバッガなどのその他ツールも使いたい
    • アプリもその他ツールもすべて入ったイメージは無駄に大きすぎる
    • アプリが通常使わないその他ツールをイメージから削除してしまうと、いざというときにその他機能が使えない、使うとしてもコンテナに外からツールを流し込まなくてはいけないので面倒
    • コンテナイメージのベースイメージを小さくする*1のはlibcの入れ替えなどによる互換性の問題が避けられない
  • 解決方法概要 -コンテナイメージをslimイメージとfatイメージの二種類に分ける

     - slimイメージ: アプリ実行に必要なものだけが入っている
     - fatイメージ: その他ツールが入っている。slimイメージにその他ツールを足した拡張版、というわけではない。コンテンツはなんでもいい。CNTRはfatイメージを使わずホスト環境を直接使う方法もあるが、説明は割愛
    
    • これ以降slimイメージから作られたコンテナをslimコンテナ、fatイメージから作られたコンテナをfatコンテナと記載
    • アプリの実行にはslimイメージを使う。その他ツールが使いたくなったらアプリのコンテナにfatイメージから作ったコンテナをアタッチ(詳細は後述)
    • 上記環境からはユーザはslimコンテナ、およびfatコンテナの両方にアクセス可能。つまりfatコンテナ内のデバッガを使ってslimコンテナ内のアプリをデバッグ、といったことができる
  • 解決方法詳細

    1. ユーザがCNTRを呼び出す。このときCNTRにslimコンテナの名前*2とfatイメージをパラメタとして指定する
    2. コンテナの名前をもとに、カーネルから動作中のコンテナのnamespaceや環境変数、cgroupsの一覧といったコンテナのコンテキストを得る
      • コンテナ名をもとにコンテキストを得る方法はコンテナランタイム依存なので、CNTRがランタイムごとにこの処理を実装する必要がある
    3. fatイメージを使ってコンテナを立ち上げて、CNTRFSサーバ(後述)を動かす
    4. 前述のコンテナのコンテキストをもとに、アプリのコンテナ上にネストしたnamespaceを作る
      • CNTRFSというCNTR専用ファイルシステムをマウントする。このCNTRFSはユーザからのファイルアクセスをslimコンテナおよびfatコンテナにforwardするproxyとなる
      • このときにユーザが指定したfatコンテナをパラメタとして渡す。これによってCNTRFSからのファイルアクセスフォワード先が、ユーザの指定したfatコンテナになる。フォワードにおいてはCNTRFSクライアントとサーバが連携
    5. 上記namespaceの中にCNTRのユーザがアクセスできる環境(ここではCNTR環境と呼ぶ)を用意して、その上で動作するシェルをユーザに提供する
    6. ユーザがファイルシステムにアクセスすると、CNTRFSは次のように実際のアクセス先を分ける
      • "/var/lib/cntr"以下にアクセスするとslimコンテナのデータにアクセス
      • "/proc"や"/sys"以下はslimコンテナのものを直接見せる
      • それ以外の場所へのアクセスするはfatコンテナのデータにアクセス
  • 効果

    • xfstestsをほとんどパスするほどの高い互換性がある
    • コンテナ実装に依存する部分が少ないこともあって、DockerやLXC,systemd-spawnなどの有名どころのコンテナランタイムで使える
    • Dockerhub上の有名どころのコンテナイメージのサイズを平均で2/3程度に小さくできる
    • 性能オーバーヘッドは少ない
  • 感想

    • かっこいい。言われてみるとなるほどだけど、うまくやるなあと思った
    • たくさんfatコンテナを付けると面白そう
    • Kubernetesephemeral containerをほうふつとさせる。なにか関係があるんだろうか。

*1:たとえばUbuntuからAlpineなど

*2:コンテナランタイムが個々のコンテナを識別するもの